Цитирование через 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 день, и так далее.

  • В сценарии оболочки выполните команду, только если источник более новый, чем целевой
  • Как сменить пароль с помощью скрипта
  • Как распечатать индекс цикла в файл с помощью awk?
  • Как проверить, монтируется ли файловая система с помощью скрипта
  • прочитать файл и присвоить значения другому файлу
  • Вычитание с помощью значений в массиве
  • выйдите из сценария, если строка ls не нашла соответствия
  • распечатать все значения файла после удаления некоторых символов с помощью grep
  • 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$ 
    Linux и Unix - лучшая ОС в мире.