您的日期编号存在差一错误 - 由于 Lotus 1-2-3 中的一个错误,Excel 和其他电子表格程序 30 多年来一直小心翼翼地保持与该程序的兼容性。
最初,第 1 天是 1900 年 1 月 1 日(正如您所说,这将使第 0 天等于 1899 年 12 月 31 日)。但是 Lotus 错误地将 1900 年视为闰年,因此,如果您使用现在的 Lotus 数字并向后计数,正确地使 1900 年成为平年,那么 1900 年 3 月 1 日之前的所有日期数字都太高了。第 1 天变为 1899 年 12 月 31 日,第 0 天则移回 30 日。因此,基于 Lotus 的电子表格中日期算术的纪元实际上是 1899 年 12 月 30 日星期六。(现代 Excel 和其他一些电子表格将 Lotus 错误兼容性扩展得足够远,足以显示 1900 年 2 月实际上有第 29 天,因此它们将标记日期0 “12 月 31 日”,同时同意这是星期六!但其他基于 Lotus 的电子表格不会这样做,Ruby 当然也不会。)
然而,即使考虑到此错误,您所说的示例也是不正确的:莲花日编号 40,396 是 2010 年 8 月 6 日,而不是 10 月 15 日。我已经在 Excel、LibreOffice 和 Google 表格中确认了这一对应关系,所有这些都一致。你一定在某个地方交叉过例子。
这是进行转换的一种方法:
Time.utc(1899,12,30) + 40396.days #=> 2010-08-06 00:00:00 UTC
或者,您可以利用另一个已知的对应关系。 Ruby(以及一般的 POSIX 系统)的零时间是 1970 年 1 月 1 日午夜 GMT。 1970年1月1日是莲花日25,569。只要您记得以 UTC 进行计算,您还可以执行以下操作:
Time.at( (40396 - 25569).days ).utc # => 2010-08-06 00:00:00 UTC
在任何一种情况下,您可能都想为纪元日期声明一个符号常量(或者是Time
代表 1899-12-30 或 POSIX“第 0 天”值 25,569 的对象)。
您可以将这些调用替换为.days
如果不需要,可以乘以 86400(每天秒数)active_support/core_ext/integer/time
对于其他任何事情,并且不想仅仅为此加载它。