我正在尝试计算两个日期之间的天数,如下所示:
$ echo $((($(date +%s -d 2016/11/22)-$(date +%s -d 2016/11/20))/(3600*24))) days
2 days
这是预期的答案,与此完全一致:
$ date -d '2016/11/22 - 2 days'
Sun Nov 20 00:00:00 CET 2016
然而,这两者似乎不一致:
$ echo $((($(date +%s -d 2020/06/28)-$(date +%s -d 2016/11/20))/(3600*24))) days
1315 days
$ date -d '2020/06/28 - 1315 days'
Mon Nov 21 00:00:00 CET 2016
我错过了什么吗?为什么我使用的第三个命令中没有得到 1316 天(而不是 1315 天)?
我又做了一些测试,更改了日期 2020/06/28 中的月份。似乎到三月份我就得到了预期的答案(即,我得到11 月 20 日在第四个命令中),但从四月份开始就出现了不一致(即,我得到11 月 21 日在第四个命令中)。有什么提示吗?
答案1
考虑以下:
$ date +%s -d 2020/06/28
1593316800
$ date +%s -d 2016/11/20
1479618000
$ echo $(( 1593316800 - 1479618000 ))
113698800
$ echo $(( 113698800 / (3600*24) ))
1315 # integer, no rounding
$ echo $(( (3600*24) ))
86400
$ echo "113698800/86400" | bc
1315
$ echo "113698800/86400" | bc -l
1315.9583333333333333333
$ printf "%.0f\n" $(echo "113698800/86400" | bc -l)
1316 # rounded to nearest integer
类似的ksh2020
计算问题:
$ printf "%(%s)T\n" 2020/06/28
1593365691
$ printf "%(%s)T\n" 2016/11/20
1479667133
$ echo $(( 1593365691 - 1479667133 ))
113698558
$ echo $(( 113698558/86400 ))
1315
$ echo "113698558/86400" | bc -l
1315.95553240740740740740
将时区设置为 UTC 可以解决该问题。
$ cat test.sh
#!/bin/bash
edate="$1"
sdate="$2"
medate=$(date +%s -d $edate)
msdate=$(date +%s -d $sdate)
secs=$(( medate - msdate ))
echo $(( secs / 86400))
echo "$secs / 86400" | bc -l
$
$ ./test.sh 2020/06/28 2016/11/20
1315
1315.95833333333333333333
$ sudo timedatectl set-timezone UTC
$ ./test.sh 2020/06/28 2016/11/20
1316
1316.00000000000000000000
或者,更简单的是,您可以使用该date -u
选项来生成正确的结果。
-u, --utc, --universal 打印或设置协调世界时 (UTC)
这似乎是夏令时问题,可能特定于您的时区设置。
答案2
你的回答很到位墨菲。非常感谢。
从 CET 更改为 CEST 发生在 3 月的最后一个星期日,即 2020 年 3 月 29 日。因此从 4 月份开始就缺失了 3600 秒。
我只需添加选项即可得到正确答案-u到日期:
$ echo $((($(date +%s -u -d 2020/06/28)-$(date +%s -u -d 2016/11/20))/(3600*24))) days
1316 days
显然,只需手动添加缺失的小时(3600 秒)即可得到相同的结果:
$ echo $((($(date +%s -d 2020/06/28)-$(date +%s -d 2016/11/20)+3600)/(3600*24))) days
1316 days
(如果您尝试使用 3599 而不是 3600,则会返回到 1315 天)。