在 Linux 上的 bash 中获取昨天的日期,DST 安全
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15374752/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Get yesterday's date in bash on Linux, DST-safe
提问by Ike Walker
I have a shell script that runs on Linux and uses this call to get yesterday's date in YYYY-MM-DD
format:
我有一个在 Linux 上运行的 shell 脚本,并使用此调用以YYYY-MM-DD
格式获取昨天的日期:
date -d "1 day ago" '+%Y-%m-%d'
It works most of the time, but when the script ran yesterday morning at 2013-03-11 0:35 CDT
it returned "2013-03-09"
instead of "2013-03-10"
.
它大部分时间都可以工作,但是当脚本昨天早上运行时,2013-03-11 0:35 CDT
它返回"2013-03-09"
而不是"2013-03-10"
.
Presumably daylight saving time (which started yesterday) is to blame. I'm guessing the way "1 day ago"
is implemented it subtracted 24 hours, and 24 hours before 2013-03-11 0:35 CDT
was 2013-03-09 23:35 CST
, which led to the result of "2013-03-09"
.
据推测,夏令时(昨天开始)是罪魁祸首。我猜"1 day ago"
它的实现方式是减去 24 小时,而 24 小时之前2013-03-11 0:35 CDT
是2013-03-09 23:35 CST
,这导致了"2013-03-09"
.
So what's a good DST-safe way to get yesterday's date in bash on Linux?
那么,在 Linux 上的 bash 中获取昨天日期的一种好的 DST 安全方法是什么?
采纳答案by tink
I think this should work, irrespective of how often and when you run it ...
我认为这应该有效,无论您运行它的频率和时间如何......
date -d "yesterday 13:00" '+%Y-%m-%d'
回答by perreal
This should also work, but perhaps it is too much:
这也应该有效,但也许太多了:
date -d @$(( $(date +"%s") - 86400)) +"%Y-%m-%d"
回答by leonbloy
If you are certain that the script runs in the first hours of the day, you can simply do
如果您确定脚本在一天的前几个小时运行,您可以简单地执行
date -d "12 hours ago" '+%Y-%m-%d'
BTW, if the script runs daily at 00:35 (via crontab?) you should ask yourself what will happen if a DST change falls in that hour; the script could not run, or run twice in some cases. Modern implementations of cron
are quite cleverin this regard, though.
顺便说一句,如果脚本每天在 00:35 运行(通过 crontab?),您应该问问自己,如果 DST 更改落在那个小时内会发生什么;脚本无法运行,或在某些情况下运行两次。现代的实现cron
是相当聪明在这方面,虽然。
回答by Walter A
Here a solution that will work with Solaris and AIX as well.
这是一个也适用于 Solaris 和 AIX 的解决方案。
Manipulating the Timezone is possible for changing the clock some hours. Due to the daylight saving time, 24 hours ago can be today or the day before yesterday.
操纵时区可以改变几个小时的时钟。由于夏令时,24 小时前可以是今天或前天。
You are sure that yesterday is 20 or 30 hours ago. Which one? Well, the most recent one that is not today.
你确定昨天是 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
The -e parameter used in the echo command is needed with bash, but will not work with ksh. In ksh you can use the same command without the -e flag.
bash 需要使用 echo 命令中使用的 -e 参数,但不适用于 ksh。在 ksh 中,您可以使用没有 -e 标志的相同命令。
When your script will be used in different environments, you can start the script with #!/bin/ksh or #!/bin/bash. You could also replace the \n by a newline:
当您的脚本将在不同环境中使用时,您可以使用 #!/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
回答by Aries
Bash under Mac OSX is slightly different.
Mac OSX 下的 Bash 略有不同。
For yesterday
对于昨天
echo `date -v-1d +%F`
For Last week
上周
echo `date -v-1w +%F`
回答by Dan Pickard
you can use
您可以使用
date -d "30 days ago" +"%d/%m/%Y"
to get the date from 30 days ago, similarly you can replace 30 with x amount of days
要获取 30 天前的日期,同样您可以用 x 天数替换 30
回答by init_js
Just use date
and trusty seconds:
只需使用date
可信赖的秒数:
As you rightly point out, a lot of the details about the underlying computation are hidden if you rely on English time arithmetic. E.g. -d yesterday
, and -d 1 day ago
will have different behaviour.
正如您正确指出的那样,如果您依赖英语时间算术,则有关底层计算的许多细节都是隐藏的。例如-d yesterday
,并且-d 1 day ago
会有不同的行为。
Instead, you can reliably depend on the (precisely documented) seconds since the unix epoch UTC, and bash arithmetic to obtain the moment you want:
相反,您可以可靠地依赖(精确记录的)自 unix epoch UTC 和 bash 算术以来的秒数来获得您想要的时刻:
date -d @$(( $(date +"%s") - 24*3600)) +"%Y-%m-%d"
This was pointed out in another answer. This form is more portable across platforms with different date
command line flags, is language-independent (e.g. "yesterday" vs "hier" in French locale), and frankly (in the long-term) will be easier to remember, because well, you know it already. You might otherwise keep asking yourself: "Was it -d 2 hours ago
or -d 2 hour ago
again?" or "Is it -d yesterday
or -d 1 day ago
that I want?"). The only tricky bit here is the @
.
这是在另一个答案中指出的。这种形式在具有不同date
命令行标志的平台上更具可移植性,与语言无关(例如法语语言环境中的“昨天”与“hier”),坦率地说(从长远来看)将更容易记住,因为好吧,你已经知道了。否则,您可能会不断问自己:“是它-d 2 hours ago
还是-d 2 hour ago
再次?” 或“是我想要的-d yesterday
还是-d 1 day ago
我想要的?”)。这里唯一棘手的地方是@
.
Armed with bash and nothing else:
用 bash 武装起来,别无他物:
Bash solely on bash, you can also get yesterday's time, via the printf builtin:
仅在 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.
So,
所以,
# 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 ))
or, equivalently with a temp variable (outer subshell optional, but keeps environment vars clean).
或者,等效地使用临时变量(外部子外壳可选,但保持环境变量干净)。
(
now=$(printf "%(%s)T" -1);
printf "%(%Y-%m-%d)T\n" $((now - 24*3600));
)
Note: despite the manpage stating that no argument to the %()T
formatter will assume a default -1
, i seem to get a 0 instead (thank you, bash manual version 4.3.48)
注意:尽管手册页指出%()T
格式化程序的任何参数都不会假定默认值-1
,但我似乎得到了一个 0(谢谢,bash 手册版本 4.3.48)
回答by suresh Palemoni
date -d "yesterday" '+%Y-%m-%d'
To use this later:
要稍后使用它:
date=$(date -d "yesterday" '+%Y-%m-%d')
回答by F. Hauri
As this question is tagged bash"DST safe"
由于这个问题被标记为bash “DST 安全”
And using fork to date
command implie delay, there is a simple and more efficient way using pure bashbuilt-in:
并且使用 forkdate
命令隐含延迟,有一种使用纯 bash内置的简单且更有效的方法:
printf -v tznow '%(%z %s)T' -1
TZ=${tznow% *} printf -v yesterday '%(%Y-%m-%d)T' $(( ${tznow#* } - 86400 ))
echo $yesterday
This is a lot quicker on more system friendly than having to forkto date
.
在更系统友好的情况下,这比必须分叉到date
.
From bashV>=5.0, there is a new variable $EPOCHSECONDS
从bashV>=5.0,有一个新变量$EPOCHSECONDS
printf -v tz '%(%z)T' -1
TZ=$tz printf -v yesterday '%(%Y-%m-%d)T' $(( EPOCHSECONDS - 86400 ))
echo $yesterday
回答by Daremitsu
You can use:
您可以使用:
date -d "yesterday 13:55" '+%Y-%m-%d'
Or whatever time you want to retrieve will retrieved by bash.
或者你想检索的任何时间都将由 bash 检索。
For month:
月份:
date -d "30 days ago" '+%Y-%m-%d'