如何解析你,Excel的Date呀

49次阅读

共计 1625 个字符,预计需要花费 5 分钟才能阅读完成。

简单的背景介绍
不久前,我们接了一个自己做前端后端产品的活,从此过上了可怜巴巴敲代码开开心心收获知识的日子呢。
那是一个平平无奇的周一下午
用户小姐姐在群里说,系统筛选工卡有效期不好使。(系统:不不不,不是我的锅
我看了一下数据库,发现,我们原定的有效期格式是这样的

整整齐齐。
数据库中当时的数据是这样的

甚至是这样的

看到这种情况,我觉得肯定是输入的时候输的不太对(年轻…
于是我决定从 Excel 下手
小姐姐们的操作流程是先用我们的系统导出一份 Excel,编辑之后再导入系统的,那只要我把这工卡一列的格式限制为日期,就一定可以统一格式的,嗯。
我们项目使用了 js-xlsx 处理表格的导入导出,下面是导出 Excel 的伪代码:
import * as XLSX from ‘xlsx’;

const xlsxMineType = ‘application/vnd.openxmlformats-
officedocument.spreadsheetml.sheet’
const data = 数据.map((s: any) => ({
ID: s.id,
工卡有效期: s.card_expired,
……
}));

const sheet = XLSX.utils.json_to_sheet(data);
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, sheet, ‘ 员工信息表 ’);
const wbbuf = XLSX.write(wb, {
type: ‘base64’
});

this.success({name: “ 员工信息表.xlsx”, data: wbbuf, type:xlsxMineType});
通过 json_to_sheet 可以拿到包含单元格信息的对象
{
A2: {t: ‘n’, v: 3776},
B2: {t: ‘s’, v: ‘2019-04-01’},
A3: {t: ‘n’, v: 3831},
B3: {t: ‘s’, v: ‘2019-04-01’},
A1: {t: ‘s’, v: ‘ID’},
B1: {t: ‘s’, v: ‘ 工卡有效期 ’},
‘!ref’: ‘A1:B3’
}
对象中以单元格位置作为 key,每个单元格的值(v)、类型(t)等等属性作为 value。其中单元格的类型支持:
b Boolean, n Number, e error, s String, d Date
看起来 Date 类型十分符合上面的要求,就尝试了一下:
const sheet = XLSX.utils.json_to_sheet(data);
// 筛选出除表头的工卡列
Object.keys(sheet).filter(item => /^B/.test(item) && item !== “B1”).forEach(key => {
sheet[key].t = “d”;
})

然鹅,如果工卡有效期本来就为空,这时候导出,打开 Excel 会报错,并且空的位置会变成 NaN

翻阅了各种中英文文档、Issue,导出一百多个员工信息表之后,我发现 Excel 真的很奇妙,或许应该在 js 上来格式化导入的数据,而不是限制单元格的类型。
如果不控制单元格类型的话,那么当管理员输入日期的时候,这个单元格可能是:文本、常规、日期、自定义类型,所以只要保证不管单元格是什么格式,程序都能拿到正确的数据就好了。
当管理员使的工卡有效期的单元格类型是文本或者常规的时候,则比较简单,程序可以按预期解析出来一个相应的字符串,用 moment 解析一下,就可以获得想要的格式的数据了。
那么当有效期单元格的类型是日期和自定义的时候,我们拿到的数据是像下图一样

这也就是之前数据库中奇怪的数字的由来,这个数字的意义,其实是当前日期距离 1900 年 1 月 0 日的天数。还需要注意的是,Excel 中有个 bug:

它以为 1900 年是闰年,所以我们拿到的天数都会多了一天,因为转换之前还需要先进行减一操作…
item. 工卡有效期 = new Date(1900, 0, expried – 1)
这样之后就可以拿到正确的日期啦。咕叽。

正文完
 0