it-swarm.com.ru

Получить вчерашнюю дату в bash для Linux, DST-safe

У меня есть сценарий Shell, который работает в Linux и использует этот вызов для получения вчерашней даты в формате YYYY-MM-DD:

date -d "1 day ago" '+%Y-%m-%d'

Он работает большую часть времени, но когда скрипт запускался вчера утром в 2013-03-11 0:35 CDT, он возвращал "2013-03-09" вместо "2013-03-10".

Предположительно виновато летнее время (которое началось вчера). Я предполагаю, что способ реализации "1 day ago" вычитал 24 часа, а за 24 часа до того, как 2013-03-11 0:35 CDT был 2013-03-09 23:35 CST, что привело к результату "2013-03-09".

Так какой же хороший DST-безопасный способ получить вчерашнюю дату в bash для Linux?

124
Ike Walker

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

date -d "yesterday 13:00" '+%Y-%m-%d'
203
tink

Bash под Mac OSX немного отличается.

Для вчерашнего дня

echo `date -v-1d +%F`

За последнюю неделю

echo `date -v-1w +%F`
42
Aries

Это также должно работать, но, возможно, это слишком много:

date -d @$(( $(date +"%s") - 86400)) +"%Y-%m-%d"
11
perreal

Если вы уверены, что скрипт запускается в первые часы дня, вы можете просто сделать

  date -d "12 hours ago" '+%Y-%m-%d'

Кстати, если скрипт запускается ежедневно в 00:35 (через crontab?), Вы должны спросить себя, что произойдет, если изменение DST произойдет в этот час; Сценарий не может быть запущен или запущен дважды в некоторых случаях. Современные реализации cron в этом отношении довольно умны хотя.

4
leonbloy

Здесь решение, которое будет работать с Solaris и AIX.

Изменение часового пояса возможно для изменения часов на несколько часов. В связи с переходом на летнее время 24 часа назад могут быть сегодня или позавчера.

Вы уверены, что вчера 20 или 30 часов назад. Который из? Ну, самый последний, которого нет сегодня.

echo -e "$(TZ=GMT+30 date +%Y-%m-%d)\n$(TZ=GMT+20 date +%Y-%m-%d)" | grep -v $(date +%Y-%m-%d) | tail -1

Параметр -e, используемый в команде echo, необходим для bash, но не работает с ksh . В ksh вы можете использовать ту же команду без флага -e.

Когда ваш скрипт будет использоваться в разных средах, вы можете запустить скрипт с помощью #!/Bin/ksh или #!/Bin/bash. Вы также можете заменить\n символом новой строки:

echo "$(TZ=GMT+30 date +%Y-%m-%d)
$(TZ=GMT+20 date +%Y-%m-%d)" | grep -v $(date +%Y-%m-%d) | tail -1
3
Walter A

ты можешь использовать

date -d "30 days ago" +"%d/%m/%Y"

чтобы получить дату от 30 дней назад, аналогично вы можете заменить 30 на x количество дней

2
Dan Pickard

Просто используйте date и верные секунды:

Как вы правильно заметили, многие детали о базовых вычислениях скрыты, если вы полагаетесь на арифметику английского времени. Например. -d yesterday и -d 1 day ago будут иметь разное поведение.

Вместо этого вы можете надежно зависеть от (точно задокументированных) секунд с Unix Epoch UTC и арифметики bash, чтобы получить нужный момент:

date -d @$(( $(date +"%s") - 24*3600)) +"%Y-%m-%d"

На это было указано в другом ответе . Эта форма более переносима на платформах с разными флагами командной строки date, не зависит от языка (например, «вчера» против «hier» во французском языке), и, честно говоря (в долгосрочной перспективе) будет легче запомнить, потому что хорошо, ты уже знаешь это В противном случае вы могли бы продолжать спрашивать себя: «Это был -d 2 hours ago или -d 2 hour ago снова?» или «Это -d yesterday или -d 1 day ago, что я хочу?»). Единственный сложный момент здесь - это @.

Вооружен Башом и ничем иным:

Bash исключительно на bash, вы также можете получить вчерашнее время через встроенную функцию printf:

 %(datefmt)T
     causes printf to output the date-time string resulting from using
     datefmt as a format string for strftime(3).  The  corresponding  argu‐
     ment  is an integer representing the number of seconds since the
     Epoch.  Two special argument values may be used: -1 represents the
     current time, and -2 represents the time the Shell was invoked.
     If no argument is specified, conversion behaves as if -1 had
     been  given.
     This is an exception to the usual printf behavior.

Так,

# inner printf gets you the current unix time in seconds
# outer printf spits it out according to the format
printf "%(%Y-%m-%d)T\n" $(( $(printf "%(%s)T" -1) - 24*3600 ))

или, что эквивалентно с переменной temp (внешняя подоболочка необязательна, но сохраняет переменные среды чистыми). 

(
  now=$(printf "%(%s)T" -1);
  printf "%(%Y-%m-%d)T\n" $((now - 24*3600));
)

Примечание: несмотря на то, что на man-странице указано, что ни один аргумент для форматера %()T не будет принимать код по умолчанию -1, вместо этого я получаю 0 (спасибо, руководство bash версии 4.3.48)

0
init_js