简短回答(针对日期 > 1900-02-28)
new Date(Date.UTC(0, 0, excelSerialDate - 1));
简短回答(对于小于等于1900年02月28日的日期)
new Date(Date.UTC(0, 0, excelSerialDate));
为什么这个方案可行
我很喜欢@leggett和@SteveR的答案,它们大多数情况下都可以解决问题,但是我想要深入了解Date.UTC()
的工作原理。
注意:时区偏移可能会导致问题,尤其是对于较早的日期(1970年前)。请参见Browsers, time zones, Chrome 67 Error (historic timezone changes)因此,如果可能的话,我想保持在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中的日期基于
1970年1月1日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天。我们必须将日期参数减1。
new Date(Date.UTC(0, 0, 732 - 1, 0, 0, 0, 0)) gives "1902-01-01T00:00:00.000Z"
需要注意的是,如果我们使用新的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];
}
SSF.format(fmt, val, opts)
。文档在这里。 - xianshenglu