Intereting Posts
Ansible failed_when только распечатать настроенное сообщение об ошибке Как сохранить результаты предыдущих операций в awk? Найти путь DVD-ROM во FreeBSD Исключение отдельных папок при копировании материалов из одного каталога в другой Каким уведомлением отправляется Firefox при завершении загрузки? Входное поведение Stdin между «cat» и «less» Агент SSH не работает с частным ключом pkcs8 Почему postfix использует ручной раздел 1, а не 8? Функциональность Dead key с компоновкой US-Intl в Fedora 23 Fedora 15: em1 недавно исчезла, и hostapd больше не обслуживает интернет для беспроводных устройств Как получить `pdftotext` для вывода текста в читаемом кодировании? Брандмауэр расширенной политики: allow_hosts.rules не работает Есть ли способ использовать эту команду, не набирая «y» все время? Что такое параметр ядра для дешифрования раздела, отличного от root? Как перенумеровать разделы GPT на диск с диском?

Как я могу рассчитывать и форматировать длительность дат, используя инструменты GNU, а не дату результата?

Все тонны статей, которые я нашел до сих пор, все были сосредоточены на получении итоговой даты, которая по-прежнему полезна, но не того, что я хочу в этом случае.

Пример ссылки: Unix & Linux SE – Быстрое вычисление различий даты .

С datediff в этом другом Q & A, это больше того, что я хочу, ссылаясь на результат продолжительности даты / времени, и он по существу использует математику timestamp Unix с предшествующими преобразованиями, но я хочу, чтобы моя степень детализации снизилась до второй, и именно поэтому я дона Разделить на 86400.

Имея доступ к секундам, я теперь хочу отформатировать его таким образом, чтобы использовать команду date GNU следующим образом: date -d "@69600" "+ %Y years %m months %e days %H:%M:%S"

Я понимаю, что все по сути является продолжительностью даты / времени с эпохи Unix, но теперь у меня проблема с номерами день, месяц и год, не начиная с 0, что не правильно отражает значение продолжительности, которое я хочу.

Я мог бы сократить этот формат и применить больше команд expr чтобы существенно вычесть 1 или 1970 из каждого значения, но мне интересно, есть ли какой-либо другой более простой и простой способ справиться с расчетом даты / времени, чтобы достичь результата продолжительности, кроме цепочки математике и форматировании. Возможно, есть еще одна опция в GNU date которую я мог бы использовать, или другой инструмент, который бы принял 2 аргумента даты / времени и сразу дал мне результат, который я ищу.

Наличие его в Homebrew для Mac было бы плюсом :).

Простая математическая ссылка на дату: Новости Walker – Арифметика даты в сценариях командной оболочки Linux

Случайные даты форматирования ссылок:

  • lifewire – Как отобразить дату и время с помощью командной строки Linux
  • ma.ttias.be – Формат даты в формате Linux: изменить вывод даты для скриптов или команд

С датифом dateutils (а не GNU извините) (ранее ddiff , dateutils.ddiff на Debian):

 $ dateutils.ddiff -f '%Y years, %m months, %d days, %H:%0M:%0S' \ '2012-01-23 15:23:01' '2017-06-01 09:24:00' 5 years, 4 months, 8 days, 18:00:59 

(даты, выбранные как UTC, добавить что-то вроде --from-zone=Europe/London для дат, которые будут считаться местным временем в соответствующем часовом поясе. --from-zone=localtime может работать для часовой пояс по умолчанию в системе; --from-zone="${TZ#:}" будет работать до тех пор, пока $TZ указывает путь к файлу часового пояса IANA (например, TZ=:Europe/London , а не TZ=GMT0BST,M3.5.0/1:00:00,M10.5.0/2:00:00 Спецификация TZ в стиле POSIX)).

С открытой date , так что все еще не с инструментами GNU извините (если вы используете ksh93 как свою оболочку, эта date может быть доступна как встроенная), вы можете использовать date -E чтобы получить разницу между двумя датами в формате, который дает 2 номера с единицами:

 $ date -E 1970-01-01 2017-06-01 47Y04M $ date -E 2017-01-01 2017-06-01 4M29d $ date -E 12:12:01 23:01:43 10h49m 

Обратите внимание, что что-либо выше часа неоднозначно, поскольку дни имеют различное количество часов в местах с DST (23, 24 или 25), а месяцы и годы имеют различное количество дней, поэтому, возможно, нет смысла иметь больше точности, чем эти две единицы выше.

Например, существует ровно один год между 2015-01-01 00:00:00 и 2016-01-01 00:00:00 или между 2016-01-01 00:00:00 и 2017-01-01 00: 00:00, но это не то же самое время (365 * 24 часа в одном случае, 366 * 24 часа в другом)

Там ровно один день между 2017-03-24 12:00:00 и 2017-03-25 12:00:00 или между 2017-03-25 12:00:00 и 2017-03-26 12:00:00, но когда это местное время в европейских странах (которое переключилось на летнее время на 2017-03-26), один день составляет 24 часа в одном случае и 23 часа в другом.

Другими словами, продолжительность, указывающая годы, месяцы, недели или дни, имеет смысл только в том случае, если она связана с одной из границ, которые она должна применяться к (и часовому поясу). Таким образом, вы не можете преобразовать несколько секунд в такую ​​продолжительность, не зная, в какое время (от или до) оно должно применяться (если вы не хотите использовать приблизительные определения дня (24 часа), месяца (30 * 24 часа) или год (365 * 24 часа)).

В какой-то степени даже продолжительность в секундах неоднозначна. Для упрощения секунды в эпоху эпохи Unix определяются как 86400-я часть данного дня Земли 1 . Эти секунды становятся длиннее и длиннее, когда Земля вращается.

Итак, что-то вроде (с date GNU):

 d1='2016-01-01 00:00:00' d2='2017-01-01 00:00:00' eval "$(date -d "@$(($(date -d "$d2" +%s) - $(date -d "$d1" +%s)))" +' delta="$((%-Y - 1970)) years, $((%-m - 1)) months, $((%-d - 1)) days, %T"')" echo "$delta" 

Или у fish :

 date -d@(expr (date -d $d2 +%s) - (date -d $d1 +%s)) +'%Y %-m %-d %T' | \ awk '{printf "%s years, %s months, %s days, %s\n", $1-1970, $2-1, $3-1, $4, $5}' 

Как правило, не дает вам то, что является правильным, поскольку временная дельта применяется к 1970 году вместо фактической даты начала 2016 года.

Например, выше, это дает мне (в европейском / лондонском часовом поясе):

 1 years, 0 months, 1 days, 01:00:00 

вместо

 1 years, 0 months, 0 days, 00:00:00 

(это может быть достаточно подходящим для вас).


1 Технически, в то время как день составляет 86400 Unix секунд, сетевые системы обычно синхронизируют свои часы с атомными часами с использованием секунд SI. Когда атомные часы говорят 12: 00: 00.00, эти системы Unix также говорят 12: 00: 00.00. Исключение составляет только после введения секунд прыжка, где либо есть одна секунда Unix, которая длится 2 секунды, либо несколько секунд, которые длятся немного дольше, чтобы смазать эту дополнительную секунду в течение более длительного периода.

Таким образом, можно узнать точную продолжительность (в терминах атомных секунд) между двумя отметками времени Unix (выпущенными системами, синхронизированными с атомными часами): получить разницу между временными интервалами Unix между двумя временными метками и добавить число прыжков секунды, которые были добавлены между ними.

datediff также есть -f %rS чтобы получить количество реальных секунд между двумя датами:

  $ dateutils.ddiff -f% S '1990-01-01 00:00:00' '2010-01-01 00:00:00' 
  631152000 
  $ dateutils.ddiff -f% rS '1990-01-01 00:00:00' '2010-01-01 00:00:00' 
  631152009 

Разница заключается в 9 прыжковых секундах, которые были добавлены между 1990 и 2010 годами.

Теперь это количество реальных секунд не поможет вам рассчитать количество дней, так как дни не имеют постоянного количества реальных секунд. Между этими двумя датами ровно 20 лет, и эти 9 прыжков секунд скорее мешают достичь этой ценности. Также обратите внимание, что ddiff %rS работает только тогда, когда не сочетается с другими спецификаторами формата. Кроме того, будущие прыжки секунд неизвестны заранее, но также информация о последних секундах скачка может быть недоступна. Например, моя система не знает о них после 2012-07-01.

Хорошо, давайте предположим, что у вас есть две сопоставимые по date строки, определяющие два момента времени, в которые вы хотите рассчитать продолжительность между ними:

 echo $(($(date +%s -d "3 days ago")-$(date +%s -d "4 weeks 2 hours 1 minutes 33 seconds ago"))) | sed 's/-//' 

Но скажем далее, что вы хотите, чтобы это было более читаемо:

 convertsecs() { hours=$(($1/3600)) minutes=$(($1%3600/60)) seconds=$(($1%60)) } totalduration="$(($(date +%s -d "3 days ago")-$(date +%s -d "4 weeks 2 hours 1 minutes 33 seconds ago"))) | sed 's/-//'" convertsecs "$totalduration" echo "Duration was ${hours} hours, ${minutes} minutes, and ${seconds} seconds." 

Время – сложная вещь, и важно оценивать свои ожидания при расчете. Я не считаю, что технически возможно делать то, что вы просите точно и точно в общем случае, поскольку определенное количество секунд может соответствовать другому количеству минут, как только вы рассмотрите такие вещи, как прыжки секунд, которые сами не происходят на полностью предсказуемой основе.

Иными словами, в то время как мы говорим, что день составляет 24 часа, не каждый день составляет ровно 24 часа, поэтому, если вы хотите знать, сколько дней плюс минута плюс секунды заданной продолжительности, вам нужно привязать эту продолжительность где-то в реальном времени, чтобы чтобы знать, был ли там второй прыжок или даже был или нет 29 апреля где-то в продолжительности.

Еще более экзотично, не каждый месяц имеет такое же количество дней.

Если это не проблема, просто запустите подсчет секунд через базовую арифметику; используйте date чтобы конвертировать в секунды-с-эпохи, делить на 86400, чтобы получить дни, остаток на 3600, чтобы получить часы, остаток, чтобы получить минуты, и так далее.