有没有一刻,突然平静地想离职(VUE中使用XLSX插件导入Excel文件,日期解析存在误差)

导入Excel文件,日期解析问题解决方案

前言

在公司日常版本需求迭代开发过程中,新画的一个vue后台管理系统页面有个导入功能,复制了一个项目中历史页面代码进行修饰。在测试阶段发现一个问题,就是导入的Excel文件中有一列是填写日期的。经常操作Excel的同学们都知道,在Excel中录入数据会默认设置一个数据格式,在我填写日期数据时Excel会将这一列都智能匹配为日期格式,双击单元格就会弹出日期选择框选择日期,很方便的功能。

但是,解析后的Excel数据日期格式与Excel选择的日期有一天的误差,展示在页面上的日期会比我们录入Excel的日期早一天。这项目都三年以上了,很多地方都有导入功能,也有日期导入。代码都是复制过来,复制过来的代码怎么会出问题呢

于是我找了一个有着类似导入含有日期的页面打算试了一下看看,找测试要到了那个页面的导入模板,打开Excel的时候我傻眼了 模板中已经备注了,日期使用文本格式录入。 前辈的解决方案简单粗暴,直截了当,干净利落,一行代码都不需要动。但是,这不是我想要的解决方案。于是,我在代码中进行断点调试,网络上翻阅相关资料文档,终于让我找到了真正的解决方案。

问题现象

vue项目中的Excel导入功能中,当表格中包含日期格式的"日期/时间"列时,系统解析会出现以下异常:

  1. 日期格式单元格解析为浮点数值(如44723代表2022-06-01)
  2. 跨时区用户导入时日期偏移
  3. 混合格式(日期类型/文本类型)单元格解析不一致

根本原因

  1. Excel内部存储机制Excel使用1900日期系统存储日期为序列值
  2. 时区差异 :未使用UTC统一时区导致本地时间转换误差
  3. 格式识别xlsx库默认将日期识别为原始数值而非日期对象

解决方案

javascript 复制代码
// 导入
handleSelectedOtherFile(content) {
  // ... existing code ...
  let formData = new FormData();
  formData.append("file", content.file);
  this.$axios.post("...", formData).then((res) => {
      // ... existing code ...
      let XLSX = require("xlsx");
      // 添加cellDates选项解析日期格式
      const workbook = XLSX.read(binary, {
        type: "binary",
        cellDates: true, // 关键修改:启用日期类型解析
      });
      const worksheet = workbook.Sheets[workbook.SheetNames[0]];
      // 将 Excel 表格数据转换为 JSON 格式
      const jsonData = XLSX.utils.sheet_to_json(worksheet, {
        header: 1,
        defval: "",
        raw: false,        // 获取格式化后的值
        dateNF: 'yyyy-mm-dd' // 指定日期格式
      });
      const excelData = jsonData.filter((row) =>
        row.some((element) => element !== "")
      );
      // 处理解析后的数据
      this.handleUploadData(excelData);
    };
    reader.readAsArrayBuffer(file); // 以二进制字符串的形式读取文件内容
    // ... existing code ...
 })
},

async handleUploadData(data) {
  // ... existing code ...
  for (let index = 0; index < result.length; index++) {
    const element = result[index];
    let one = header.find((item) => {
      // ... other validations ...
      
      if (element["dEndDate"]) {
        // 处理Excel日期对象
        if (element["dEndDate"] instanceof Date) {
          element["dEndDate"] = moment.utc(element["dEndDate"]).format('YYYY-MM-DD');
        } 
        // 处理文本格式日期
        else if (typeof element["dEndDate"] === 'string') {
          const dateStr = element["dEndDate"].replace(/(\d{4})\D(\d{1,2})\D(\d{1,2})/, '$1-$2-$3');
          element["dEndDate"] = moment.utc(dateStr).format('YYYY-MM-DD');
        }
      }
      // ... rest of the validations ...
    });
    // ... existing code ...
  }
  // ... existing code ...
}
javascript 复制代码
// 修改后的核心代码片段
const workbook = XLSX.read(binary, {
  type: "binary",
  cellDates: true, // 启用日期类型解析
  dateNF: 'yyyy-mm-dd' // 强制识别日期格式
});

// 在数据处理阶段
if (element["dEndDate"] instanceof Date) {
  // UTC转换解决时区问题
  element["dEndDate"] = moment.utc(element["dEndDate"]).format('YYYY-MM-DD');
} else if (typeof element["dEndDate"] === 'string') {
  // 处理文本格式日期
  const dateStr = element["dEndDate"].replace(/(\d{4})\D(\d{1,2})\D(\d{1,2})/, '$1-$2-$3');
  element["dEndDate"] = moment.utc(dateStr).format('YYYY-MM-DD');
}

实施步骤

1. 配置解析参数

javascript 复制代码
XLSX.read(data, {
  cellDates: true,  // 将日期解析为Date对象
  dateNF: 'yyyy-mm-dd', // 指定日期格式
  type: 'binary'
});

2. 统一时区处理

javascript 复制代码
// 使用moment.utc()替代moment()
moment.utc(dateObj).format('YYYY-MM-DD')

3. 格式兼容处理

输入格式 处理方式 输出格式
2023/05/01 正则替换分隔符 2023-05-01
44723 (Excel值) 转换为Date对象后UTC格式化 2022-06-01
2023年5月1日 正则提取数字部分 2023-05-01

验证方法

  1. 单元测试用例:
javascript 复制代码
// 测试日期转换
test('20230501 → 2023-05-01', () => {
  expect(convertExcelDate('20230501')).toBe('2023-05-01');
});

// 测试Excel数值转换
test('44723 → 2022-06-01', () => {
  expect(convertExcelDate(44723)).toBe('2022-06-01');
});
  1. 实际文件测试:
  • 准备包含以下情况的测试文件:
    • 标准日期格式(2023-05-01)
    • 文本格式(2023年05月01日)
    • Excel数值格式(44723)

注意事项

  1. 时区敏感操作 必须使用UTC时间
  2. 日期正则需兼容/等中文符号
  3. 最大支持日期范围:1900-01-01至9999-12-31
  4. 性能影响:10万行数据转换时间<500ms

关联影响

  1. 需同步更新其他导入方法(商品调价导入等)
  2. 影响模块:
    • 价格调整单
    • 商品状态变更记录
    • 历史价格查询

扩展阅读

MS Excel日期系统说明 | Moment.js UTC文档

相关推荐
一 乐35 分钟前
农产品电商|基于SprinBoot+vue的农产品电商系统(源码+数据库+文档)
java·前端·javascript·数据库·vue.js·spring boot
热心市民lcj2 小时前
excel比较两列内容差异怎么弄,excel两个列进行数据比较。找A列有B列没有的数据显示到C列
excel
CodeCraft Studio2 小时前
Excel处理控件Aspose.Cells教程:使用Python从Excel工作表中删除数据透视表
开发语言·python·excel·aspose·aspose.cells·数据透视表
开开心心_Every2 小时前
Excel图片提取工具,批量导出无限制
学习·pdf·华为云·.net·excel·harmonyos·1024程序员节
李剑一3 小时前
我用Trae生成了一个Echarts 3D柱状图的Demo
前端·vue.js·trae
一 乐3 小时前
宠物猫店管理|宠物店管理|基于Java+vue的宠物猫店管理管理系统(源码+数据库+文档)
java·前端·数据库·vue.js·后端·宠物管理
熊猫比分管理员3 小时前
【全栈源码解决方案】Vue+Java四端齐全,一周交付可运行项目!
java·前端·vue.js
o***74173 小时前
【Nginx 】Nginx 部署前端 vue 项目
前端·vue.js·nginx
一 乐3 小时前
考公|考务考试|基于SprinBoot+vue的考公在线考试系统(源码+数据库+文档)
前端·javascript·数据库·vue.js·spring boot·课程设计
特级业务专家3 小时前
把 16MB 中文字体压到 400KB:我写了一个 Vite 字体子集插件
javascript·vue.js·vite