在Linux上使用bash获取昨天的日期,DST-safe

时间:2013-03-13 00:17:51

标签: linux bash

我有一个在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 CDT 2013-03-09 23:35 CST之前24小时减去24小时,这导致了"2013-03-09"的结果。

那么在Linux上使用bash获取昨天日期的DST安全方法是什么?

10 个答案:

答案 0 :(得分:217)

我认为这应该有效,无论你多久经营一次......

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

答案 1 :(得分:45)

Mac OSX下的Bash略有不同。

昨天

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

上周

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

答案 2 :(得分:11)

这也应该有效,但可能太多了:

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

答案 3 :(得分:4)

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

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

顺便说一句,如果脚本每天都在00:35运行(通过crontab?),你应该问问自己如果DST的变化在那个小时内会发生什么变化;脚本无法运行,或在某些情况下运行两次。但是,cron的现代实施在这方面是quite clever

答案 4 :(得分:3)

此处的解决方案也适用于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

答案 5 :(得分:2)

你可以使用

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

从30天前获取日期,类似地,您可以用x天数替换30

答案 6 :(得分:2)

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

要稍后使用:

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

答案 7 :(得分:1)

该问题被标记为 “ DST安全”

并使用fork to date命令隐含延迟,使用内置的 pure 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

答案 8 :(得分:0)

只需使用date并信任秒:

正如您正确指出的那样,如果您依赖英语时间算术,则会隐藏很多有关基础计算的详细信息。例如。 -d yesterday-d 1 day ago会有不同的行为。

相反,您可以可靠地依赖于自unix时代UTC以来的(精确记录的)秒数,并且bash算法可以获得您想要的时刻:

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

另一个answer指出了这一点。这种形式在具有不同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 ))

或者等同于临时变量(外部子shell可选,但保持环境变量干净)。

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

注意:尽管manpage声明%()T格式化程序没有参数会假设默认-1,但我似乎得到了0(谢谢你,bash手册版本4.3.48) )

答案 9 :(得分:0)

您可以使用:

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

或者bash会检索您想要检索的任何时间。

一个月:

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