是否可以在 DATE 命令中指定负日期,即公元前的一个日期?

是否可以在 DATE 命令中指定负日期,即公元前的一个日期?

我需要计算两个日期之间的天数差。使用 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)

你应该仔细考虑日期计算背后的实际需求,尤其是对于公历没有意义的日子

相关内容