1 起因
safari浏览器的new Date(dateStr: string) 格局要求如下:
/*** dateStr里 必须要有 d(日);月、日和时分秒 都不必满足补0规定;但有 时钟 必须有 分钟 ***/new Date('yyyy/MM/dd HH:mm:ss');new Date('yyyy/MM/dd HH:mm');new Date('yyyy/M/d');new Date('yyyy/M/dd');new Date('yyyy/MM/d');new Date('yyyy/M'); // Invalid Datenew Date('yyyy/MM'); // Invalid Datenew Date('yyyy/MM HH'); // Invalid Datenew Date('yyyy/MM HH:mm:ss'); // Invalid Date/*** dateStr里 不用肯定要有 d(日);但 M(月) 、d(日)和时分秒 都必须满足 小于10后面补0;而且如存在时分秒,必须用T连贯; 而且有 时钟 必须有 分钟 ***/new Date('yyyy-MM-ddTHH:mm:ss');new Date('yyyy-MM-ddTHH:mm');new Date('yyyy-MM-dd');new Date('yyyy-MM');new Date('yyyy-M'); // Invalid Datenew Date('yyyy-M-d'); // Invalid Datenew Date('yyyy/MM HH'); // Invalid Datenew Date('yyyy-MM-dd H:MM'); // Invalid Date
2 解决
2.1 自定义一个构造函数
class MyDate extends Date { constructor() constructor(value: number | string) constructor(year: number, month: number, date?: number, hours?: number, minutes?: number, seconds?: number, ms?: number) constructor(...args: any) { super(...args); if (this.toString() === 'Invalid Date' && args.length === 1 && typeof args[0] === 'string') { const dateStr = args[0]; const dateReg: any = { year: '0*(\\d+)', // 日期的分隔符 splitChar: '(?:([ \\/\\-]))?', month: '(?:0*([1-9]|(?:1[0-2])))?', date: '(?:0*([1-9]|(?:[1-2]\\d)|(?:3[0-1])))?', hour: '(?:0*((?:1?\\d)|(?:2[0-3]))?)', minute: '(?::0*([1-5]?\\d)?:*)', second: '(?::0*([1-5]?\\d))?', millisecond: '(?::0*(\\d{0,3}))?', // 零点整 zeroOClock: '(?:(24)(?::0*:*)(?::0*){0,2})', }; // 后面一种状况匹配24点前,后一种是匹配24点整 dateReg.time = `(?:(?:${dateReg.hour}${dateReg.minute}${dateReg.second}${dateReg.millisecond})|${dateReg.zeroOClock})`; const regStr = new RegExp(`^${dateReg.year}${dateReg.splitChar}${dateReg.month}(?:\\2${dateReg.date})?(?:[ T]+${dateReg.time}:?)?$`); const dateMathArr = dateStr.match(regStr); if (dateMathArr) { return new Date(...(dateMathArr .slice(1, 2) as Array<string | number>) .concat( // d(日): 数字代表的月份比理论月份(字符串传入的)大1,所以须要减去1 (Number(dateMathArr[3]) || 1) - 1, (dateMathArr[4] || 1), // H(时),因为匹配time时有两种状况,所以须要兼容第二种状况 dateMathArr.pop() || dateMathArr[5] || 0, // MM:SS:MS dateMathArr .slice(6, 9) .map(item => item || 0), )); } } }}// 应用const myDate = new MyDate('2022-1-1');
2.2 重写Date函数
Date = function(Date) { MyDate.prototype = Date.prototype; // 将Date结构器的属性办法,复制到MyDate结构器上 var propertys = Object.getOwnPropertyNames(Date.prototype.constructor); if(propertys && propertys.length > 0){ for(var i = 0; i < propertys.length; i++){ var name = propertys[i]; MyDate[name] = Date.prototype.constructor[name]; } } return MyDate; function MyDate() { // 只对不反对的日期格局做解决 const thisDate = new Date(...arguments); if (thisDate.toString() === 'Invalid Date' && arguments.length === 1 && typeof arguments[0] === 'string') { const dateStr = arguments[0]; const dateReg = { year: '0*(\\d+)', // 日期的分隔符 splitChar: '(?:([ \\/\\-]))?', month: '(?:0*([1-9]|(?:1[0-2])))?', date: '(?:0*([1-9]|(?:[1-2]\\d)|(?:3[0-1])))?', hour: '(?:0*((?:1?\\d)|(?:2[0-3]))?)', minute: '(?::0*([1-5]?\\d)?:*)', second: '(?::0*([1-5]?\\d))?', millisecond: '(?::0*(\\d{0,3}))?', // 零点整 zeroOClock: '(?:(24)(?::0*:*)(?::0*){0,2})', }; // 后面一种状况匹配24点前,后一种是匹配24点整 dateReg.time = `(?:(?:${dateReg.hour}${dateReg.minute}${dateReg.second}${dateReg.millisecond})|${dateReg.zeroOClock})`; const regStr = new RegExp(`^${dateReg.year}${dateReg.splitChar}${dateReg.month}(?:\\2${dateReg.date})?(?:[ T]+${dateReg.time}:?)?$`); const dateMathArr = dateStr.match(regStr); if (dateMathArr) { const date = new Date(...dateMathArr .slice(1, 2) .concat( // d(日): 数字代表的月份比理论月份(字符串传入的)大1,所以须要减去1 (dateMathArr[3] || 1) - 1, (dateMathArr[4] || 1), // H(时),因为匹配time时有两种状况,所以须要兼容第二种状况 dateMathArr.pop() || dateMathArr[5] || 0, // MM:SS:MS dateMathArr .slice(6, 9) .map(item => item || 0)) ); if (date && date.toString() !== 'Invalid Date') return date; } } return thisDate; }}(Date);// 应用const myDate = new Date('2022-1-1');
2.2.1 简配版
没有对日期字符串里的数字做更深刻的测验,只反对失常的日期字符串;
Date = function(Date) { MyDate.prototype = Date.prototype; // 将Date结构器的属性办法,复制到MyDate结构器上 var propertys = Object.getOwnPropertyNames(Date.prototype.constructor); if(propertys && propertys.length > 0){ for(var i = 0; i < propertys.length; i++){ var name = propertys[i]; MyDate[name] = Date.prototype.constructor[name]; } } return MyDate; function MyDate() { // 只对不反对的日期格局做解决 const thisDate = new Date(...arguments); if (thisDate.toString() === 'Invalid Date' && arguments.length === 1 && typeof arguments[0] === 'string') { const dateStr = arguments[0]; const dateMathArr = dateStr.match(/^(\d+)(?:([ \/\-])(\d+))?(?:\2(\d+))?(?:[ T]+(?:(\d+))(?::(\d+))(?::(\d+))?(?::(\d+))?)?$/); if (dateMathArr) { const date = new Date(...dateMathArr .slice(1, 2) .concat((dateMathArr[3] || 1) - 1, dateMathArr.slice(4).map((item, index) => item || (index > 0 ? 0 : 1)))); if (date && date.toString() !== 'Invalid Date') return date; } } return thisDate; }}(Date);
3 没有解决的问题
比方日期字符串的第一个数字不是年份,在chrome和safari上解析出的日期不同:
new Date('10')// chrome: Mon Oct 01 2001 00:00:00 GMT+0800 (中国规范工夫)// safari: Fri Jan 01 0010 08:05:43 GMT+0805 (CST)
参考:
- JavaScript new Date()在Safari上的坑
- 重构Date结构器,解决safari浏览器在new Date()报Invalid value