Цитирование через unix-даты

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

#!/bin/bash initial_date=`date -d "2008-02-04 00:00:00 UTC" +%s` end_date=`date +%s` n=0 until [ $initial_date -gt $end_date ]; do echo $initial_date let n+=1 readable_date=`date +"%Y-%m-%d %T" -d "1970-01-01 $initial_date sec"` echo $readable_date readable_date=`date -d "$readable_date + $n year"` initial_date=`date -d "$readable_date" +%s` done 

но его выход довольно странный для меня:

1202083200
2008-02-04 00 : 00: 00
1233702000
2009-02-03 23 : 00: 00
1265230800
2010-02-03 21 : 00: 00
1296756000
2011-02-03 18 : 00: 00
1328277600
2012-02-03 15 : 00: 00
1359885600
2013-02-03 11 : 00: 00
1391403600
2014-02-03 06 : 00: 00
1422918000
2015-02-02 23 : 00: 00
1454425200
2016-02-02 15 : 00: 00

Почему год не увеличивается правильно? Сдвиг часов кажется мне побочным эффектом unix >> UTC >> unix conversion. Есть ли какой-либо прямой (без реверсии) метод для этого?

PS
И да, я проверил это , этот и этот вопрос и не нашел ясного способа сделать это. Все они основаны на увеличении числа и преобразовании даты с помощью этого, что не кажется мне точным.

И да, я думал о добавлении 60*60*24*30*365 к начальной дате, но будет ли это правильно? Этот подход не учитывает високосные годы, месяцы, составляющие 31 день, и так далее.

2 Solutions collect form web for “Цитирование через unix-даты”

Используемая дата:

 $ dateA="2008-02-04 00:00:00 UTC" 

Первой причиной получения дат со сменными временами является запрос «местных» дат:

 $ date -d "$dateA" Sun Feb 3 19:00:00 EST 2008 

Который будет исправлен, если вы укажете время UTC:

 $ TZ=UTC0 date -d "$dateA" Mon Feb 4 00:00:00 UTC 2008 

Или лучше (используйте привычку использовать его) используйте опцию -u даты:

 $ date -ud "$dateA" Mon Feb 4 00:00:00 UTC 2008 

Вторая причина – запросить «относительные элементы» со знаком:

 $ date -ud "$(date +"%Y-%m-%d %T" -ud "$dateA") +1 year" ### wrong Tue Feb 3 23:00:00 UTC 2009 $ date -ud "$(date +"%Y-%m-%d %T" -ud "$dateA") 1 year" ### better Mon Feb 4 00:00:00 UTC 2008 

Но все время проблемы (обычно) исчезают, когда используется «часовой пояс» (-z):

 $ date -ud "$(date +"%Y-%m-%d %T %z" -ud "$dateA") +1 year" ### Best Wed Feb 4 00:00:00 UTC 2009 $ date -ud "$(date +"%Y-%m-%d %T %z" -ud "$dateA") 1 year" ### Preferred Wed Feb 4 00:00:00 UTC 2009 

Проблема связана с тем, как синтаксическая строка даты обрабатывается, если значение TZ отсутствует, +1 может быть интерпретировано как значение временной зоны:

 $ date -ud "2008-02-04 00:00:00 +3 year" Tue Feb 3 21:00:00 UTC 2009 

Даже если значение среды для TZ установлено:

 $ TZ=UTC0 date -ud "2008-02-04 00:00:00 +3 year" Tue Feb 3 21:00:00 UTC 2009 

Да, год был взят один раз (2009 вместо 2008), но +3 был использован для изменения представленного времени (а не того, что было предназначено).

Повторяю: проблема в том, что +3 может анализироваться как значение временной зоны.


Кроме того, для преобразования (эпохи) секунд в даты, дата GNU может использовать «@»,

 $ dateAsec="$( date -ud "$dateA" +"%s" ) $ date -ud @"$dateAsec" Mon Feb 4 00:00:00 UTC 2008 

Сценарий (с использованием функции (newdate)) можно записать следующим образом:

 #!/bin/bash dateI="$(date -ud "2008-02-04 00:00:00 UTC" +%s)" dateF="$(date -u +%s)" newdate(){ date -ud "$(date +"%Y-%m-%d %T %z" -ud @"$dateI") $1 year" +"%s"; } n=0 while dateN="$( newdate "$n" )" (( dateN < dateF )); do dateNhuman="$(date +"%Y-%m-%d %T %z" -ud @"$dateN")" echo "dateN=$dateN --- $dateNhuman ---> $dateF $(( $dateF - $dateN )) $n" (( n++ )) done 

Результаты:

 dateN=1202083200 --- 2008-02-04 00:00:00 +0000 ---> 1470543626 268460426 0 dateN=1233705600 --- 2009-02-04 00:00:00 +0000 ---> 1470543626 236838026 1 dateN=1265241600 --- 2010-02-04 00:00:00 +0000 ---> 1470543626 205302026 2 dateN=1296777600 --- 2011-02-04 00:00:00 +0000 ---> 1470543626 173766026 3 dateN=1328313600 --- 2012-02-04 00:00:00 +0000 ---> 1470543626 142230026 4 dateN=1359936000 --- 2013-02-04 00:00:00 +0000 ---> 1470543626 110607626 5 dateN=1391472000 --- 2014-02-04 00:00:00 +0000 ---> 1470543626 79071626 6 dateN=1423008000 --- 2015-02-04 00:00:00 +0000 ---> 1470543626 47535626 7 dateN=1454544000 --- 2016-02-04 00:00:00 +0000 ---> 1470543626 15999626 8 

Все годы появляются, и все кажется правильным.

Итератор в относительной дате от начальной точки может иметь больше смысла:

 #!/usr/bin/env bash START='2008-02-04 00:00:00 UTC' END=$( date +%s ) for yearnum in $( seq 1 999 ); do NUDATE=$( date -d "$START + $yearnum year" +%s ) PUNY_HUMAN_DATE=$( date -d "@$NUDATE" "+%Y-%m-%d %T %Z" ) if [[ $NUDATE -gt $END ]]; then break fi echo $NUDATE $PUNY_HUMAN_DATE done 

Это приводит к чему-то вроде:

 -bash-4.1$ bash iter 1233705600 2009-02-04 00:00:00 UTC 1265241600 2010-02-04 00:00:00 UTC 1296777600 2011-02-04 00:00:00 UTC 1328313600 2012-02-04 00:00:00 UTC 1359936000 2013-02-04 00:00:00 UTC 1391472000 2014-02-04 00:00:00 UTC 1423008000 2015-02-04 00:00:00 UTC 1454544000 2016-02-04 00:00:00 UTC -bash-4.1$ 
  • Как выбрать строки из файла CSV на основе разных значений столбцов?
  • Как проверить, была ли переменная передана функции в Bash?
  • Редактирование файла .profile для доступа
  • Доступ к вторичным переменным
  • Почему программированию на C не нужны сценарии компилятора и оболочки?
  • Пакетное переименование в соответствии с количеством страниц в pdf-файле
  • Как разбирать аргументы командной строки с произвольной строкой
  • Как я могу исправить скрипт завершения табуляции имени хоста SSH?
  • Каков наилучший способ сделать функцию bash в скрипте в качестве параметра при запуске через командную строку?
  • Скопируйте открытый ключ ssh на несколько хостов Linux
  • Конкретный способ вывода в файл, если задан аргумент, в stdout в противном случае
  • Проблема bc о длинном выражении
  • Linux и Unix - лучшая ОС в мире.