是否可以在 DATE 命令中指定负日期,即基督诞生之前的日期?

Jun*_*ngo 6 command-line date

我需要计算两个日期之间的天数差异。使用 date 命令,我们可以将日期转换为秒,然后计算天数差异。\n例如:

\n
$ echo $((($(date +%s --date "2023-10-21")-$(date +%s --date "1899-12-29"))/(3600*24)))\n  45220\n
Run Code Online (Sandbox Code Playgroud)\n

当第一次约会是积极的时候,一切都很好。当第一个日期为负数时,它不起作用。例如:

\n
$ echo $((($( date +%s --date "-2022-05-10")-$(date +%s --date "1899-12-29"))/(3600*24)))\ndate: invalid date \'-2022-05-10\'\n25570\n
Run Code Online (Sandbox Code Playgroud)\n

另一方面,DATE 命令可以使用负日期进行操作:

\n
$ date --date="3000 years ago"\nMon Nov 24 13:12:27 LMT -977\n
Run Code Online (Sandbox Code Playgroud)\n

别的。据我所知,消极日期和积极日期有一些差异。
\n对于正日期,一年从 1 月 1 日开始。但对于负日期,一年从 12 月 31 日开始:

\n

第一年:...-29.12.01 -30.12.01 -31.12.01 [0000] +01.01.01 +02.01.01 +03.00.01... :第一年 +

\n

关于解决方案。

\n

这是从零日期计算Libreoffice Calc的数字日期值所必需的。Libreoffice 中的零日期是1899-12-30。但是您必须从该日期倒数一天才能得到正确的解决方案,截至日期1899-12-29。发生这种情况是因为由于各种原因一天中的秒数并不恒定。例如从零日期1899-12-30 开始

\n
$ echo "( $(date +%s --date 2023-10-21) - $(date +%s --date 1899-12-30) ) / (3600*24)" | bc -l\n45219.97936342592592592592\n
Run Code Online (Sandbox Code Playgroud)\n

我们还需要 30 分 17 秒才能获得正确的整数 45220(对于我的时区)。\n对于不同的日期和时区,差异可能会有所不同。\n“所有这些意味着永远不应该处理依赖于date命令的计算作为整日,但应考虑", - FedKad。\nLibreoffice 的零日期的更好计算可能如下所示(对浮点结果进行四舍五入):

\n
$ echo "x=( $(date +%s --date 2023-10-21) - $(date +%s --date 1899-12-30) ) / (3600*24) + 0.5 ; scale=0; x/1" | bc -l\n45220\n
Run Code Online (Sandbox Code Playgroud)\n

感谢FedKad的回答。\n否则:对于某些时区,日期命令无法识别日期 19-10-01 的前 3 分 03 秒(尝试 " for i in {-1869875830..-1869875800}; do TZ=亚洲/伊斯坦布尔日期 --date @$i; 完成 ", - Egmont) 并计算零年,这是错误的;没有0年(FredKad)。

\n

因此,“使用专用于日历日计算的工具”,- Egmont

\n

“对于(公历)公元1600 年之后的日期,您可以考虑使用dateutils.ddiff ”, \xe2\x80\x93 Steeldriver

\n

检查在线计算日期(FedKad)。

\n

PS 要查看您所在国家/地区的时间差距,您可以使用“ zdump -v ”命令。例如:\nzdump -v 欧洲/柏林、zdump -v 美国/纽约、zdump -v 伊朗等。

\n

Fed*_*eli 4

我认为该date命令一开始就无法正确解释公元前年份:

\n
    \n
  • date -d \'now - 2023 years\'is的输出是Fri 24 Nov 0000 02:58:34 PM LMT错误的;没有0年。

    \n
  • \n
  • 同样的date -d \'now - 2024 years\'输出也是Wed 24 Nov -001 03:00:16 PM LMT错误的。

    \n
  • \n
\n
\n

即使您的问题()中的第一个计算结果45220也不正确,可以在线检查它返回45221天数。

\n

我做了一些测试,发现该date命令似乎无法识别日期 1910-01-01 有效(至少对于我的时区):

\n
$ date --date "1910-10-01"\ndate: invalid date \xe2\x80\x981910-10-01\xe2\x80\x99\n
Run Code Online (Sandbox Code Playgroud)\n

正如命令所示,这应该是星期六cal

\n
$ date --date "1910-09-30"\nFri 30 Sep 1910 12:00:00 AM IMT\n$ date --date "1910-09-31"\ndate: invalid date \xe2\x80\x981910-09-31\xe2\x80\x99\n$ date --date "1910-10-01"\ndate: invalid date \xe2\x80\x981910-10-01\xe2\x80\x99\n$ date --date "1910-10-02"\nSun 02 Oct 1910 12:00:00 AM EET\n
Run Code Online (Sandbox Code Playgroud)\n

@egmont 的评论中解释了这个“缺失一天”的原因(实际上是由于时区更改而缺失了 3 分 4 秒的时间段):

\n
$ date --date "1910-09-30 23:59:59"\nFri 30 Sep 1910 11:59:59 PM IMT\n$ date --date "1910-10-01 00:00:00"\ndate: invalid date \xe2\x80\x981910-10-01 00:00:00\xe2\x80\x99\n$ date --date "1910-10-01 00:01:00"\ndate: invalid date \xe2\x80\x981910-10-01 00:01:00\xe2\x80\x99\n$ date --date "1910-10-01 00:03:03"\ndate: invalid date \xe2\x80\x981910-10-01 00:03:03\xe2\x80\x99\n$ date --date "1910-10-01 00:03:04"\nSat 01 Oct 1910 12:03:04 AM EET\n
Run Code Online (Sandbox Code Playgroud)\n

这就是您第一次计算中“缺失”这一天的原因。

\n

请注意!在我的时区,您的计算给出:

\n
$ echo $((($(date +%s --date "2023-10-21")-$(date +%s --date "1899-12-29"))/(3600*24)))\n45220\n
Run Code Online (Sandbox Code Playgroud)\n

上面的数字是除法浮点结果的“截断”整数结果,在我的时区中类似于 45220.9562037...。请检查您系统上以下命令的输出:

\n
$ echo "( $(date +%s --date 2023-10-21) - $(date +%s --date 1899-12-29) ) / (3600*24)" | bc -l\n45220.95620370370370370370\n
Run Code Online (Sandbox Code Playgroud)\n

更好的计算可能是这样的(对浮点结果进行四舍五入):

\n
$ echo "x=( $(date +%s --date 2023-10-21) - $(date +%s --date 1899-12-29) ) / (3600*24) + 0.5 ; scale=0; x/1" | bc -l\n45221\n
Run Code Online (Sandbox Code Playgroud)\n
\n

所有这些意味着依赖date命令的计算永远不应该被视为整日,但也应该考虑秒数。

\n
\n

您可以使用其他工具:

\n
    \n
  • 例如,LibreOffice Calc似乎可以正确计算日期(日)差异,如下面的屏幕截图所示:
  • \n
\n

计算日期差异

\n
    \n
  • 作为替代命令行实用程序,您可以按照@steeldriver的建议使用datediff。但是,它不支持 1601-01-01 之前的日期(“按设计,不支持 1601-01-01 之前的日期。 ”),更不用说负年份了:
  • \n
\n
$ dateutils.ddiff 1901-01-01 1601-01-01\n-109572\n$ dateutils.ddiff 1901-01-01 1600-12-31\nddiff: cannot make sense of `1600-12-31\' using the given input formats\n
Run Code Online (Sandbox Code Playgroud)\n
    \n
  • 以下Python代码将显示日期差异(尽管它不支持负年份):
  • \n
\n
from datetime import date\nprint((date(2023,10,21)-date(1899,12,29)).days)\n
Run Code Online (Sandbox Code Playgroud)\n
\n

您应该仔细考虑日期计算背后的实际需要,特别是对于公历没有意义的日期

\n

  • 看来您更改了时区,因此在午夜跳过了几分钟。尝试打印一些时间戳,每次增加 1 秒:`for i in {-1869875830..-1869875800}; 执行 TZ=亚洲/伊斯坦布尔 date --date @$i; 完成`。当然,没有人有 9 月 31 日这一天。 (2认同)