Это действительно дубликат Почему Date.parse дает неверные результаты? , но это может показаться не очевидным на первый взгляд.
Первое правило из парсинга меток времени является «не использовать встроенный синтаксический анализатор», даже для 2 или 3 форматов, поддерживаемых ECMA-262.
Чтобы надежно проанализировать метку времени, вы должны знать формат. Встроенные парсеры пробуют и работают, поэтому между ними есть различия, которые могут привести к неожиданным результатам. Просто бывает, что '2020-01-01T00: 00: 00 + 00: 00', вероятно, является единственным поддерживаемым форматом, который фактически надежно анализируется. Но он отличается немного от строгого ISO 8601, и разные браузеры отличаются тем, насколько строго они применяют правила синтаксического анализа ECMAScript, поэтому очень легко ошибиться.
Вы можете преобразовать его в «локальная» временная метка, просто обрезав информацию о смещении, то есть «2020-01-01T00: 00: 00», однако Safari по крайней мере ошибается и все равно обрабатывает ее как UT C. Сам ECMAScrip несовместим с ISO 8601, рассматривая формы ISO 8601 только для даты как UT C (т. Е. '2020-01-01' как UT C, когда ISO 8601 говорит, что он должен рассматриваться как локальный).
Так что, просто напишите свой собственный парсер или используйте библиотеку, есть из чего выбирать. Если вам нужен только синтаксический анализ и форматирование, то некоторые из них будут сокращены менее чем на 2 тыс. (И есть примеров по SO ).
Написание собственного не так сложно, если вы просто хочу поддерживать форматы, похожие на ISO 8601, например
// Parse ISO 8601 timestamps in YYYY-MM-DDTHH:mm:ss±HH:mm format
// Optional "T" date time separator and
// Optional ":" offset hour minute separator
function parseIso(s, local) {
let offset = (s.match(/[+-]\d\d:?\d\d$/) || [])[0];
let b = s.split(/\D/g);
// By default create a "local" date
let d = new Date(
b[0],
b[1]-1,
b[2] || 1,
b[3] || 0,
b[4] || 0,
b[5] || 0
);
// Use offset if present and not told to ignore it
if (offset && !local){
let sign = /^\+/.test(offset)? 1 : -1;
let [h, m] = offset.match(/\d\d/g);
d.setMinutes(d.getMinutes() - sign * (h*60 + m*1) - d.getTimezoneOffset());
}
return d;
}
// Samples
['2020-01-01T00:00:00+00:00', // UTC, ISO 8601 standard
'2020-01-01 00:00:00+05:30', // IST, missing T
'2020-01-01T00:00:00-0400', // US EST, missing T and :
'2020-01-01 00:00:00', // No timezone, local always
'2020-01-01' // Date-only as local (differs from ECMA-262)
].forEach(s => {
console.log(s);
console.log('Using offset\n' + parseIso(s).toString());
console.log('Ignoring offset\n' + parseIso(s, true).toString());
});