解析xlsx发现关于闰年有趣的事情

2023-04-05  本文已影响0人  啊阿伟啊

[excel] [xlsx] [闰年计算] [日期计算]

起因

最近在使用 golang 解析 xlsx 文件完成一些功能,发现使用 excelize 库解析日期类型的值时,获取到的是一个数字。

Excel中显示 2012/12/1,excelize 解析获得 41244

怎么把获得的数字转换成日期类型,好做后面的操作呢。经过搜索获得了解决方案:

import (
    "fmt"
    "time"
)

func main() {
    days := 41244
    date := time.Date(1900, 1, 1, 0, 0, 0, 0, time.UTC).AddDate(0, 0, days-2)

    fmt.Println(date)  // 2012-12-01 00:00:00 +0000 UTC
}

执行查看

打印结果是正确的,但是为什么要将天数减2才能获取的正确的时间?

关于闰年的计算

Excel 日期的存储

首先,需要知道的是为什么日期类型会变成数字,这个数字代表什么?

Excel 将日期存储为数字,这个数字是从 1900/1/1 起经过的天数。1900/1/1 日是第1天。

如果是这样,应该 days - 1 就可以了,为什么要 days - 2 呢?

如果想要揭开这个谜团,就需要先回答两个问题:

  1. 闰年如何计算?
  2. 1900年是闰年么?

如何计算闰年

关于闰年如何计算。大家一定觉得很简单:

可以被4整除的年份,比如大家最熟悉的年份:2008

那么,因为 1900 % 4 == 0 ,所以 1900 年是闰年啊。

如果你这么想,那就能体会为什么出现上面的问题了。

首先,1900年不是闰年。翻了大半天日历进行确认:

1900年2月

其次,闰年的计算公式不是简单地 “可以被4整除”。闰年的计算:

非整百年份:能被4整除的是闰年。
整百年份:能被400整除的是闰年。
闰年的计算,归结起来就是通常说的:四年一闰;百年不闰,四百年再闰。

看到这个计算公式时,我也是惊到了,因为印象中,一直以来都没有注意过百年的处理条件。

由于1900 年是百年,且不能被 400 整除,所以 1900 年不是闰年。

Excel的bug

Excel使用 1900日期系统,使用从1900/1/1日开始经过的天数表示日期。

但是,Excel错误地假定 1900 年是闰年。所以在 Excel 有一个错误的日期 1900/2/29,这个日期时不存在的,所以从 1900/3/1 之后,每个日期的表示就多了1天。

这就是 days - 2 的原因,需要减去多余的 1900/3/1。不过 1900/2/28 及其之前的日期计算就不需要多减去额外的1天了。

对于这个bug,官方是这么解释的:

微软关于1900问题的回答

简短的说,就是修改这个bug会耗费大量的时间,并产生兼容问题,而这个问题本身产生的问题有限,所以不做修改。

而且为了计算方便,Excel 保留了 1900/1/0 这个日期。

有趣的1582年

在查阅资料的时候,发现了另外一个有意思的故事:

需要注意的是,公历是根据罗马人的“儒略历”改编而成的。由于当时没有了解到每年要多算出0.0078天的问题,从公元前46年到16世纪,一共累计多出了10天。为此,当时的教皇格列高利十三世,将1582年10月5日改为10月15日,并开始了新的闰年规定。即规定公历年份是整百数的,必须是400的倍数才是闰年,不是400的倍数的年份就是平年。
— 摘自百度百科

1582年,为了更正闰年的计算,整整少了10天。我又翻了大半天日历进行确认:

1582年10月

结语

经过这一趟操作下来,有两个感受:

  1. 方案的确定,一定是有取舍的。发生问题后,需要确定影响的范围,如果修改带来的弊远大于利,且问题影响的范围较小,那么可以舍小取大。问题的解决方式不是一成不变的,问题也不是一定必须修改的,需要根据情况而定。
  2. 误差是不可避免的,需要动态的更正、调整。但是解决问题还要限定问题的边界,先处理力所能及范围内的。正如闰年的计算也不是一成不变的,但是对于几千年之后的计算误差,目前也没法精确给出,所以还是解决好几百年内的问题吧:

    由于地球的自转速度逐渐降低,而公转速度则相对更加稳定,所以上述的系统经过更长的周期也会发生微小的误差。据计算,每8000年会有一天的误差,所以英国的天文学家约翰·赫歇耳提议:公元4000年为平年,以此类推,公元12000年、20000年也是平年。但此提议从未被正式采纳。原因是到了4000年,地球自转的精确速度并非如今可以预测,所以届时参照真实数据方可做出判断。因此,在长远的将来,针对闰年的微小调整应该不是由预定的系统决定,而是随时不定性的。

参考

  1. Excel 错误地假定 1900 年是闰年
  2. Leap year problem
  3. 1582年10月为什么少了10天?
  4. 百度百科:闰年
  5. 为什么公历 1900 年不是闰年?
  6. Wikipedia:闰年.
上一篇 下一篇

猜你喜欢

热点阅读