GNU Date:计算日期之间的天数不一致

GNU Date:计算日期之间的天数不一致

我正在尝试计算两个日期之间的天数,如下所示:

$ 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 天)。

相关内容