我从不同的Date
收到3种格式的APIs
UTC
格式:2014-01-01T00:00:00.000Z
(String
)GMT
格式:Thu, 29 Nov 2018 17:30:56 GMT
(String
)unixTimeStamp
:1558606726
(number
)此外,UTC
格式有时可能最后没有Z
,因此常规解析会产生时间差。
function formatDate(dateString) {
var dateTime, utcFormatRegex, zeroHourOffsetRegex;
// Some APIs return a Date in standard ISO UTC format may not have Z at the end
utcFormatRegex = /^\d{4}-\d{2}-\d{2}T.*$/;
zeroHourOffsetRegex = /^.*Z$/;
if (utcFormatRegex.test(dateString) && !zeroHourOffsetRegex.test(dateString)) {
dateString+='Z';
}
dateTime = new Date(dateString);
}
鉴于所有不同格式都有解析函数,我需要一个函数,该函数根据regex
和parse
来确定我们应该使用哪个解析函数。如果正则表达式不是理想的解决方案,那我该怎么办呢?
我要说的是,应该有一个比“如果没有Z然后加一个”更健壮的解决方案,以使其在单个日期时间解析器中进行解析。如果我们得到另一个日期时间格式,该格式不能很好地与Z匹配,该怎么办?届时我们将进行多项更改。
答案 0 :(得分:1)
使用正则表达式是可以的,但是您需要严格测试期望的格式。如果您得到了意外的东西,则抛出错误。当前内置解析器的缺点之一是无法指定严格的解析,例如如果提供的格式不正确,则解析器将引发错误。
有些库可以提供帮助,搜索会发现很多库。
但是,如果您只需要在OP中支持3种格式,则可能适合以下内容:
/* Return a Date where the input may be:
** string: ISO 8601 timestamp that should be treated as UTC
** whether it has a trailing Z or not
** string: Timestamp in the format (using moment.js tokens):
** ddd, DD MMM YYYY HH:mm:ss GMT
** nunber: UNIX time value, seconds since 1970-01-01 UTC
*/
function toDate(value) {
// Parse the string & fail early if it fails
let d = new Date(value);
// Throw error if couldn't parse value
if (isNaN(d.getTime())) {
throw 'Invalid timestamp: ' + value;
}
// Otherwise, do the work
let days = 'Sun Mon Tue Wed Thu Fri Sat'.split(' ');
let months = 'Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec'.split(' ');
// Test for time value first as that's the easiest
if (typeof value == 'number' && !isNaN(value)) {
return new Date(value * 1000);
// Test for ISO 8601 next
} else if (/^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d\.\d\d\dZ?$/.test(value)) {
return new Date(/Z$/.test(value)? value : value + 'Z');
// Test for random format
} else if (/^[a-z]{3}, \d?\d [a-z]{3} \d{4} \d\d:\d\d:\d\d GMT$/i.test(value)) {
let b = value.split(/ |:/);
if (days.includes(b[0].substr(0,3)) && months.includes(b[2])) {
let x = new Date(Date.UTC(
b[3], // year
months.indexOf(b[2]), // month, zero indexed
b[1], // day
b[4], b[5], b[6] // hh:mm:ss
));
// Check value was a valid date, only need to check some parts
if (x.getUTCFullYear() == b[3] &&
x.getUTCDate() == b[1] &&
x.getUTCHours() == b[4] &&
x.getUTCSeconds() == b[6]) {
return x;
} else {
throw 'Invalid timestamp: ' + value;
}
}
// Throw error as must be unknown format
} else {
throw 'Unknown format: ' + value;
}
}
// Minimal testing
var isoString0 = '2014-01-01T00:00:00.000Z',
isoString1 = '2014-01-01T00:00:00.000', // no Z, parse as UTC anyway
randomString = 'Thu, 29 Nov 2018 17:30:56 GMT',
unixTimeValue = 1558606726, // Assume seconds
invalidDate0 = '2018-02-29T00:00:00.000Z', // no 29 Feb in 2018, fail built-in parse
invalidDate1 = 'Thu, 29 Feb 2018 17:30:56 GMT', // no 29 Feb in 2018, fail manual parse
invalidFormat = '6/6/2019'; // Unknown format
[isoString0, isoString1, randomString, unixTimeValue, invalidDate0,
invalidDate1, invalidFormat].forEach(s => {
var result;
try {
result = toDate(s);
console.log(s + ' =>\n' + result.toISOString());
} catch (e) {
console.log(e);
}
});