0
点赞
收藏
分享

微信扫一扫

记一次神奇的时间转换问题(SheetJS)

最近在写一个功能,使用SheetJS读取Excel表格,在读取日期的时候发现了一个隐藏很深的坑,特此记录一下。
SheetJS读取Excel文件时,可指定参数 cellDates: true,这样当单元格内存储的为日期时,可以将读取到的值直接转化为Date对象。

const workbook = XLSX.read(buffer, { type: 'binary',cellDates: true });

但测试时发现,读取到的值和实际时间总有43秒的误差:
Excel中的值
实际读取到的值
经过搜索,发现这是一个历史原因导致的BUG:

在GitHub上也有相关的讨论
GitHub: The exported date is 43 seconds longer

这个Issue里给出了解决方法:

方法1

手动修复 getTimezoneOffset 的精度

import XLSX from 'xlsx';
const basedate = new Date(1899, 11, 30, 0, 0, 0);
const dnthresh = basedate.getTime() + (new Date().getTimezoneOffset() - basedate.getTimezoneOffset()) * 60000;

const day_ms = 24 * 60 * 60 * 1000;
const days_1462_ms = 1462 * day_ms;

function datenum(v: Date, date1904: boolean) {
  let epoch = v.getTime();
  if (date1904) {
    epoch -= days_1462_ms;
  }
  return (epoch - dnthresh) / day_ms;
}

export function fixImportedDate(date: Date, isDate1904: boolean) {
  const parsed = XLSX.SSF.parse_date_code(datenum(date, false), { date1904: isDate1904 });
  // return `${parsed.y}-${parsed.m}-${parsed.d}`;
  return new Date(parsed.y, parsed.m, parsed.d, parsed.H, parsed.M, parsed.S);
}
方法2

不使用cellDates: true,直接用SSF模块转换日期格式单元格里的值

import XLSX from 'xlsx';

export function parseExcelDate(n: number, isDate1904: boolean) {
  const parsed = XLSX.SSF.parse_date_code(n, { date1904: isDate1904 });
  // return `${parsed.y}-${parsed.m}-${parsed.d}`;
  return new Date(parsed.y, parsed.m, parsed.d, parsed.H, parsed.M, parsed.S);
}

后记

真是醉了,写个代码还能学到历史……

举报

相关推荐

0 条评论