我需要计算两个日期之间的天数差。使用 date 命令,我们可以将日期转换为秒数,然后计算天数差。例如:
$ echo $((($(date +%s --date "2023-10-21")-$(date +%s --date "1899-12-29"))/(3600*24)))
45220
如果第一次约会是正数,那么一切都很好。如果第一次约会是负数,那就行不通了。例如:
$ echo $((($( date +%s --date "-2022-05-10")-$(date +%s --date "1899-12-29"))/(3600*24)))
date: invalid date '-2022-05-10'
25570
另一方面,DATE 命令可以对负日期进行操作:
$ date --date="3000 years ago"
Mon Nov 24 13:12:27 LMT -977
否则。正如我所见,负日期和正日期有一些区别。
对于正日期,一年从 1 月 1 日开始。但对于负日期,一年从 12 月 31 日开始:
第一年:...-29.12.01 -30.12.01 -31.12.01[0000]+01.01.01 +02.01.01 +03.00.01... :第一年
关于解决方案。
这是计算数字日期值所必需的Libreoffice Calc从其零日期。Libreoffice 中的零日期是1899-12-30。但你必须从这个日期往前数一天才能得到正确的答案,到目前为止1899-12-29。发生这种情况是因为一天中的秒数由于各种原因并不恒定。例如从零日期开始1899-12-30:
$ echo "( $(date +%s --date 2023-10-21) - $(date +%s --date 1899-12-30) ) / (3600*24)" | bc -l
45219.97936342592592592592
我们离得到正确的整数 45220(对于我的时区)还差 30 分 17 秒。对于不同的日期和时区,差异可能会有所不同。“所有这些都意味着依赖于日期命令应该绝不被视为整天,但秒应该考虑还“,”联邦储蓄银行。Libreoffice 的零日期的更好的计算可能是这样的(对浮点结果进行四舍五入):
$ echo "x=( $(date +%s --date 2023-10-21) - $(date +%s --date 1899-12-30) ) / (3600*24) + 0.5 ; scale=0; x/1" | bc -l
45220
谢谢联邦储蓄银行答案。否则:date 命令无法识别某些时区中日期 19-10-01 的前 3 分 03 秒(尝试“for i in {-1869875830..-1869875800}; do TZ=Asia/Istanbul date --date @$i; done”,- Egmont)并计算出错误的零年;没有年份0(弗雷德卡德)。
因此“使用专用于日历日计算的工具”,-艾格蒙特。
“对于(之后的日期)公历)公元 1600 年你可以考虑使用dateutils.ddiff“,-钢铁司机。
检查日期计算在线(FedKad)。
PS 要查看您所在国家/地区的时差,您可以使用“zdump -v“命令。例如:zdump -v Europe/Berlin、zdump -v America/New_York、zdump -v Iran 等。
答案1
我认为该date
命令首先无法正确解释公元前年份:
的输出
date -d 'now - 2023 years'
是Fri 24 Nov 0000 02:58:34 PM LMT
错误的;没有公元 0 年。类似地,
date -d 'now - 2024 years'
输出是Wed 24 Nov -001 03:00:16 PM LMT
,这又是错误的。
即使你问题中第一次计算的结果(45220
)也不正确,因为可以检查在线的返回45221
天数。
我做了一些测试,发现该date
命令似乎无法将日期 1910-01-01 识别为有效日期(至少对于我的时区而言):
$ date --date "1910-10-01"
date: invalid date ‘1910-10-01’
正如命令所显示的那样,它应该是星期六cal
。
$ date --date "1910-09-30"
Fri 30 Sep 1910 12:00:00 AM IMT
$ date --date "1910-09-31"
date: invalid date ‘1910-09-31’
$ date --date "1910-10-01"
date: invalid date ‘1910-10-01’
$ date --date "1910-10-02"
Sun 02 Oct 1910 12:00:00 AM EET
@egmont 在评论中解释了这个“缺少一天”的原因(实际上由于时区变化而缺少 3 分 4 秒的时间段):
$ date --date "1910-09-30 23:59:59"
Fri 30 Sep 1910 11:59:59 PM IMT
$ date --date "1910-10-01 00:00:00"
date: invalid date ‘1910-10-01 00:00:00’
$ date --date "1910-10-01 00:01:00"
date: invalid date ‘1910-10-01 00:01:00’
$ date --date "1910-10-01 00:03:03"
date: invalid date ‘1910-10-01 00:03:03’
$ date --date "1910-10-01 00:03:04"
Sat 01 Oct 1910 12:03:04 AM EET
这就是您第一次计算时“缺失”一天的原因。
请注意!在我的时区,您的计算结果如下:
$ echo $((($(date +%s --date "2023-10-21")-$(date +%s --date "1899-12-29"))/(3600*24)))
45220
上述数字是除法浮点结果的“截断”整数结果,在我的时区中类似于 45220.9562037...。请检查您的系统上以下命令的输出:
$ echo "( $(date +%s --date 2023-10-21) - $(date +%s --date 1899-12-29) ) / (3600*24)" | bc -l
45220.95620370370370370370
更好的计算可能是这样的(对浮点结果进行四舍五入):
$ echo "x=( $(date +%s --date 2023-10-21) - $(date +%s --date 1899-12-29) ) / (3600*24) + 0.5 ; scale=0; x/1" | bc -l
45221
所有这些意味着依赖于date
命令的计算永远不应被视为整天,但也应将秒数考虑在内。
您可以使用其他工具:
- 例如,LibreOffice Calc似乎正确计算了日期(天)差异,如下面的屏幕截图所示:
- 作为替代命令行实用程序,您可以使用日期差异正如@steeldriver 所建议的那样。但是,它不支持 1601-01-01 之前的日期(“根据设计,不支持 1601-01-01 之前的日期。“),更不用说负面年份了:
$ dateutils.ddiff 1901-01-01 1601-01-01
-109572
$ dateutils.ddiff 1901-01-01 1600-12-31
ddiff: cannot make sense of `1600-12-31' using the given input formats
- 以下 Python 代码将显示日期差异(尽管它不支持负年份):
from datetime import date
print((date(2023,10,21)-date(1899,12,29)).days)
你应该仔细考虑日期计算背后的实际需求,尤其是对于公历没有意义的日子。