简短的回答
new Date(Date.UTC(0, 0, excelSerialDate - 1));
为什么这样有效
我真的很喜欢@leggett 和@SteveR 的答案,虽然它们大部分都有效,但我想更深入地了解它们是如何Date.UTC()
工作的。
注意:时区偏移可能存在问题,尤其是对于较旧的日期(1970 年之前)。请参阅浏览器、时区、Chrome 67 错误(历史时区更改),因此我想留在 UTC,并且尽可能不依赖任何时间变化。
Excel 日期是基于 1900 年 1 月 1 日的整数(在 PC上。在 MAC 上它基于 1904 年 1 月 1 日)。假设我们在 PC 上。
1900-01-01 is 1.0
1901-01-01 is 367.0, +366 days (Excel incorrectly treats 1900 as a leap year)
1902-01-01 is 732.0, +365 days (as expected)
JS 中的日期基于Jan 1st 1970 UTC
. 如果我们使用Date.UTC(year, month, ?day, ?hour, ?minutes, ?seconds)
它将返回自基准时间以来的毫秒数,以 UTC 为单位。它有一些有趣的功能,我们可以利用这些功能为我们带来好处。
的参数的所有正常范围Date.UTC()
都是从 0 开始的,除了day
. 它确实接受这些范围之外的数字,并将输入转换为溢出或下溢其他参数。
Date.UTC(1970, 0, 1, 0, 0, 0, 0) is 0ms
Date.UTC(1970, 0, 1, 0, 0, 0, 1) is 1ms
Date.UTC(1970, 0, 1, 0, 0, 1, 0) is 1000ms
它也可以做早于 1970-01-01 的日期。在这里,我们将天从 0 递减到 1,并增加小时、分钟、秒和毫秒。
Date.UTC(1970, 0, 0, 23, 59, 59, 999) is -1ms
它甚至足够聪明,可以将 0-99 范围内的年份转换为 1900-1999
Date.UTC(70, 0, 0, 23, 59, 59, 999) is -1ms
现在,我们如何表示 1900-01-01?为了更容易根据我喜欢的日期查看输出
new Date(Date.UTC(1970, 0, 1, 0, 0, 0, 0)).toISOString() gives "1970-01-01T00:00:00.000Z"
new Date(Date.UTC(0, 0, 1, 0, 0, 0, 0)).toISOString() gives "1900-01-01T00:00:00.000Z"
现在我们必须处理时区。Excel 在其日期表示中没有时区的概念,但 JS 有。解决这个问题的最简单方法,恕我直言,将所有输入的 Excel 日期视为 UTC(如果可以的话)。
从 Excel 日期 732.0 开始
new Date(Date.UTC(0, 0, 732, 0, 0, 0, 0)).toISOString() gives "1902-01-02T00:00:00.000Z"
由于上面提到的闰年问题,我们知道它会关闭 1 天。我们必须将 day 参数减 1。
new Date(Date.UTC(0, 0, 732 - 1, 0, 0, 0, 0)) gives "1902-01-01T00:00:00.000Z"
需要注意的是,如果我们使用 new Date(year, month, day) 构造函数构造日期,则参数使用您当地的时区。我在 PT (UTC-7/UTC-8) 时区,我得到
new Date(1902, 0, 1).toISOString() gives me "1902-01-01T08:00:00.000Z"
对于我的单元测试,我使用
new Date(Date.UTC(1902, 0, 1)).toISOString() gives "1902-01-01T00:00:00.000Z"
将 excel 序列日期转换为 js 日期的 Typescript 函数是
public static SerialDateToJSDate(excelSerialDate: number): Date {
return new Date(Date.UTC(0, 0, excelSerialDate - 1));
}
并提取 UTC 日期以使用
public static SerialDateToISODateString(excelSerialDate: number): string {
return this.SerialDateToJSDate(excelSerialDate).toISOString().split('T')[0];
}