在DST安全的Linux上以bash获取昨天的日期


158

我有一个运行在Linux上的shell脚本,并使用此调用以以下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"实现的方式是减去2013-03-11 0:35 CDTwas 之前的24小时和24小时2013-03-09 23:35 CST,这导致的结果"2013-03-09"

那么,在Linux上bash中获取昨天日期的一种DST安全的好方法是什么?


您是否总是同时运行它,是否重复运行它?
2013年

@tink它每天在00:35运行
Ike Walker

Answers:


267

我认为这应该有效,无论您运行它的频率和时间...

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

1
您如何将其分配给变量以供以后使用?
空值

6
@null-用相同的方式分配任何其他shell命令的输出。变量= $(日期-D “昨天13:00” '+%Y-%间- %d')...
天衣

对于GNU日期:date -d yesterday 13:00 -I
gogstad

这取决于这样一个事实,如果我理解正确的话,总是在晚上在夏季和冬季之间进行切换?
Nicolas Raoul

2
@NicolasRaoul:不保证;但是将其安排到清晨是一项广泛遵循的惯例。另一方面,没有IIRC可以在接近当地时间的地方进行切换。因此,“ 1300J永远不会在DST边界上”是一个合理的假设
Piskvor在

56

Mac OSX下的日期稍有不同。

对于昨天

date -v-1d +%F

上周

date -v-1w +%F

8
如果对在OSX中使用GNU样式感兴趣,还可以使用gdatehomebrew coreutils软件包中提供的。
user456584

11
你的意思date是不同的。
augurar

12

这也应该起作用,但是可能太多了:

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

如果您需要处理date不支持yesterday语法的Mac OS X ,则需要这样的东西
Mikko Rantalainen

7

如果确定脚本在一天的头几个小时运行,则只需执行

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

顺便说一句,如果脚本每天在00:35运行(通过crontab?),您应该问自己,如果DST更改在该小时内发生,将会发生什么;该脚本无法运行,或在某些情况下运行两次。现代的实现cron相当聪明在这方面,虽然。


5

您可以使用

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

要获取30天之前的日期,类似地,您可以将30替换为x天数


您应该更改格式%Y%m%d以匹配问题。无论如何,我都投票赞成,因为它工作正常。
isapir

4

这里的解决方案也可以与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

bash需要echo命令中使用的-e参数,但不适用于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

0

只需使用date值得信赖的秒数即可:

正如您正确指出的那样,如果您依赖英语时间算术,则会隐藏有关底层计算的许多细节。例如-d yesterday-d 1 day ago将会有不同的行为。

取而代之的是,您可以可靠地依靠unix纪元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进行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变量(外部子shell是可选的,但保持环境变量干净)。

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

注意:尽管手册页指出%()T格式化程序的任何参数都不会采用默认值-1,但我似乎得到了0(谢谢,bash手册版本4.3.48)


0
date -d "yesterday" '+%Y-%m-%d'

以后使用:

date=$(date -d "yesterday" '+%Y-%m-%d')

2
尽管此代码可以解决OP的问题,但最好包含有关您的代码如何解决OP的问题的说明。这样,将来的访问者可以从您的帖子中学习,并将其应用于自己的代码。SO不是编码服务,而是知识资源。高质量,完整的答案强化了这一想法,并且更有可能遭到反对。这些功能,加上所有职位必须自成体系的要求,是SO作为与众不同的平台的优势。您可以编辑以添加其他信息和/或在源文档中补充说明。
SherylHohman

0

您可以使用:

date -d "yesterday 13:55" '+%Y-%m-%d'

或者,无论您要检索什么时间,bash都会检索它。

对于月份:

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

0

由于这个问题被标记 “ DST安全”

使用fork date命令隐含延迟,有一种使用内置纯bash的简单有效的方法:

printf -v tznow '%(%z %s)T' -1
TZ=${tznow% *} printf -v yesterday '%(%Y-%m-%d)T' $(( ${tznow#* } - 86400 ))
echo $yesterday

比起不得不分叉,这在更系统友好的方面要快得多date

V> = 5.0,有一个新变量$EPOCHSECONDS

printf -v tz '%(%z)T' -1
TZ=$tz printf -v yesterday '%(%Y-%m-%d)T' $(( EPOCHSECONDS - 86400 ))
echo $yesterday
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.