如何将MS Excel中的date从浮动转换为date格式?

尝试使用ruby脚本中的roo gemparsing和XLSX文件。

在Excel中,date以DDDDD.ttttt格式存储为浮点数或整数,从1900-01-00 (00 no 01)计数。 所以为了转换date,如40396 – 你会采取1900-01-00 + 40396 ,你应该得到2010-10-15,但我得到2010-08-08。

我正在使用active_support / time来计算,如下所示:

 Time.new("1900-01-01") + 40396.days 

我在做我的计算错误还是有积极支持的错误?

我在Windows 7上运行ruby 1.9.3-mri + latest active_support gem(3.2.1)

编辑

我正在用错误的数据查看Excel中较旧的文件 – 我的脚本/控制台正在提取正确的数据 – 因此我的困惑 – 除了使用正确的文件之外,我一切正常。 该死的全能者!

感谢大家的回复,我会在这里保留这个问题,以防有人需要关于如何使用ruby从excel转换date的信息。

另外对于碰到这个问题的其他人 – 电子表格gem不支持正确读取XLSX文件(v 0.7.1) – 所以我使用roo来读取,而使用axlsx来写入。

由于Excel 1-2-3中的一个错误,Excel和其他电子表格程序已经仔细保持了30多年的兼容性,所以在您的date编号中有一个错误的错误。

原来第一天的意图是在1900年1月1日(如你所说,这将使第0天等于“1900年1月0日”,即1899年12月31日)。 但是莲花错误地认为1900年是一个闰年,所以一天的数字是一个。 使用这些数字以1900年为正常的日历,12月31日为第1天,第0天为第30天。 因此,基于Lotus的电子表格中的date算术的时代是1899年12月30日星期六。(现代Excel和其他一些电子表格扩展了Lotus的bug兼容性,足以继续在1900年1月1日标注该date“是一个星期六,但是其他基于Lotus的电子表格却没有,而Ruby肯定不会。)

即使允许这个错误,但是,你陈述的例子是不正确的:莲花天40396是2010年8月6日,而不是10月15日。 我已经在Excel,LibreOffice和Google表格中确认了这个对应关系。 你必须在某处交叉例子。

在任何情况下,Ruby的Time类都不支持在1900年以前的date算术,所以直接使用它与1899-12-30的基准date是有问题的。 任何时候你想在Ruby中处理1970年以前的date,你最好使用DateTime ,它支持基于第二的算术,因此可以很好的与ActiveSupport助手一起工作,比如.days

 require 'date' DateTime.new(1899,12,30) + 40396.days # => Fri, 06 Aug 2010 00:00:00 +0000 

如果您想要Time对象,则可以在结果上调用to_time

或者,你可以利用另一个已知的信件。 Ruby(以及POSIX系统)的时间零点是1970年1月1日UTC的午夜。 1970年1月1日是莲花日25,569。 Time对这样的最近的date没有任何困难,所以只要你记得以UTC来计算,你可以这样做:

 Time.at( (40396 - 25569).days ).utc # => 2010-08-06 00:00:00 UTC 

在任何一种情况下,您可能都希望为纪元date(date时间对象或值25,569)声明一个符号常量。

如果您不需要ActiveSupport作为其他任何东西,就可以将这些调用replace为乘以86,400的.days,并且不希望仅为此加载。

你做错了你的计算。 你如何达到2010-10-15的预期效果?

在Excel中, 403962010-08-06 (当然不是使用1904年的日历)。 为了演示,请将40396键入Excel单元格中,并将格式设置为yyyy-mm-dd

或者:

 40396 / 365.2422 = 110.6 (years -- 1900 + 110 = 2010) 0.6 * 12 = 7.2 (months -- January = 1; 1 + 7 = 8; 8 = August) 0.2 * 30 = 6 (days) 

Excel的日历不正确地包括1900-02-29; 占2010-08-08结果之间的一天差额; 我不确定第二天差异的原因。

“Excel将date和时间存储为表示自1900年1月 – 0日以来的天数的数字,再加上24小时日的小数部分:ddddd.tttttt。这称为序列date或序列date时间。 ( http://www.cpearson.com/excel/datetime.htm

如果您的列包含date时间,而不是date,则以下代码非常有用:

  dt = DateTime.new(1899, 12, 30) + excel_value.to_f 

另外请记住,在excel工作表中有两种date模式,基于1900和基于1904,通常在默认情况下为在mac上创build的电子表格启用。 如果您一直find4年的date,则应该使用不同的基准date:

  dt = DateTime.new(1904, 1, 1) + excel_value.to_f 

您可以为任何电子表格启用/禁用1904date模式,但如果您在添加数据后更改设置,则date将在电子表格中显示4年。 一般来说,你应该总是使用1900date模式,因为大多数野外的Excel用户都是基于Windows的。

注意:这个方法的一个问题是舍入可能会出现+/- 1秒。 对我来说,我input的date“足够接近”,但只是要记住。 一个更好的解决scheme可能会使用舍入小数秒来解决这个问题。

Interesting Posts