关于Excel序列号转日期JavaScript代码的两处技术疑问
Excel序列号转日期JavaScript代码疑问解答
async function getNewDate(xlSerial) { // milliseconds since 1899-31-12T00:00:00Z, corresponds to xl serial 0. let xlSerialOffset = -2209075200000; let elapsedDays; // each serial up to 60 corresponds to a valid calendar date. // serial 60 is 1900-02-29. This date does not exist on the calendar. // we choose to interpret serial 60 (as well as 61) both as 1900-03-01 // so, if the serial is 61 or over, we have to subtract 1. if (xlSerial < 61) { elapsedDays = xlSerial; } else { elapsedDays = xlSerial - 1; } // javascript dates ignore leap seconds // each day corresponds to a fixed number of milliseconds: // 24 hrs * 60 mins * 60 s * 1000 ms let millisPerDay = 86400000; let jsTimestamp = xlSerialOffset + elapsedDays * millisPerDay; return new Date(jsTimestamp); }
疑问解答
1. 代码中的let xlSerialOffset = -2209075200000;代表什么含义?
这个数值是JavaScript时间戳与Excel序列号起始点的毫秒偏移量:
- Excel的序列号0对应日期
1899-12-31(代码注释里的1899-31-12是笔误,应为12月31日); - JavaScript的时间戳以
1970-01-01T00:00:00Z为零点,计算从该零点到1899-12-31T00:00:00Z的毫秒数,结果就是负数的-2209075200000。用这个偏移量加上Excel序列号对应的毫秒数,就能把Excel的日期基准转换为JavaScript的时间戳基准。
2. 当xlSerial≥61时,为什么要执行elapsedDays = xlSerial - 1的操作?
这是为了修正Excel的历史遗留bug:
- 早期Excel模仿Lotus 1-2-3的日期系统,错误地将1900年判定为闰年,给不存在的
1900-02-29分配了序列号60; - 但实际1900年不是闰年,没有2月29日。代码里将序列号60和61都映射为真实存在的
1900-03-01; - 对于序列号≥61的日期,因为Excel多算了那一天(不存在的1900年2月29日),所以必须减1来对齐真实日历,避免后续所有日期都偏差一天。
内容的提问来源于stack exchange,提问作者wiilan
相关产品推荐
相关产品推荐

