Ладно, похоже, такого поведения нельзя избежать, поэтому вам нужно разобрать даты вручную.Но способ синтаксического анализа довольно прост.
Если мы анализируем дату в формате ISO 8601, маска строки даты выглядит следующим образом:
<yyyy>-<mm>-<dd>T<hh>:<mm>:<ss>(.<ms>)?(Z|(+|-)<hh>:<mm>)?
1.Получение даты и времени отдельно
Строка T
отделяет дату от времени.Таким образом, мы можем просто разделить строку ISO на T
var isoString = `2019-05-09T13:26:10.979Z`
var [dateString, timeString] = isoString.split("T")
2.Извлечение параметров даты из строки даты
Итак, мы имеем dateString == "2019-05-09"
.Теперь довольно просто получить эти параметры отдельно
var [year, month, date] = dateString.split("-").map(Number)
3.Обработка временной строки
С временной строкой мы должны сделать более сложные действия из-за ее изменчивости.
У нас есть timeString == "13:26:10Z"
Также возможно timeString == "13:26:10"
и timeString == "13:26:10+01:00
var clearTimeString = timeString.split(/[Z+-]/)[0]
var [hours, minutes, seconds] = clearTimeString.split(":").map(Number)
var offset = 0 // we will store offset in minutes, but in negation of native JS Date getTimezoneOffset
if (timeString.includes("Z")) {
// then clearTimeString references the UTC time
offset = new Date().getTimezoneOffset() * -1
} else {
var clearOffset = timeString.split(/[+-]/)[1]
if (clearOffset) {
// then we have offset tail
var negation = timeString.includes("+") ? 1 : -1 // detecting is offset positive or negative
var [offsetHours, offsetMinutes] = clearOffset.split(":").map(Number)
offset = (offsetMinutes + offsetHours * 60) * negation
} // otherwise we do nothing because there is no offset marker
}
На данный момент у нас есть представление данных в числовом формате:
year
, month
, date
, hours
, minutes
, seconds
и offset
в минутах.
4.Использование ... собственного конструктора JS Date
Да, мы не можем избежать этого, потому что это слишком круто.JS Date
автоматически сопоставляет дату для всех отрицательных и слишком больших значений.Таким образом, мы можем просто передать все параметры в необработанном формате, и конструктор JS Date
автоматически создаст для нас правильную дату!
new Date(year, month - 1, date, hours, minutes + offset, seconds)
Вуаля!Вот полностью рабочий пример.
function convertHistoricalDate(isoString) {
var [dateString, timeString] = isoString.split("T")
var [year, month, date] = dateString.split("-").map(Number)
var clearTimeString = timeString.split(/[Z+-]/)[0]
var [hours, minutes, seconds] = clearTimeString.split(":").map(Number)
var offset = 0 // we will store offset in minutes, but in negation of native JS Date getTimezoneOffset
if (timeString.includes("Z")) {
// then clearTimeString references the UTC time
offset = new Date().getTimezoneOffset() * -1
} else {
var clearOffset = timeString.split(/[+-]/)[1]
if (clearOffset) {
// then we have offset tail
var negation = timeString.includes("+") ? 1 : -1 // detecting is offset positive or negative
var [offsetHours, offsetMinutes] = clearOffset.split(":").map(Number)
offset = (offsetMinutes + offsetHours * 60) * negation
} // otherwise we do nothing because there is no offset marker
}
return new Date(year, month - 1, date, hours, minutes + offset, seconds)
}
var testDate1 = convertHistoricalDate("1894-01-01T00:00:00+01:00")
var testDate2 = convertHistoricalDate("1893-01-01T00:00:00+01:00")
var testDate3 = convertHistoricalDate("1894-01-01T00:00:00-01:00")
var testDate4 = convertHistoricalDate("1893-01-01T00:00:00-01:00")
console.log(testDate1.toLocaleDateString(), testDate1.toLocaleTimeString())
console.log(testDate2.toLocaleDateString(), testDate2.toLocaleTimeString())
console.log(testDate3.toLocaleDateString(), testDate3.toLocaleTimeString())
console.log(testDate4.toLocaleDateString(), testDate4.toLocaleTimeString())
Примечание
В этом случае мы получаем Date
экземпляр со всеми его собственными значениями (такими как .getHours()
), равными , нормализованными , включая смещение часового пояса.testDate1.toISOString
все равно выдаст странный результат.Но если вы работаете с этой датой, она, вероятно, будет на 100% соответствовать вашим потребностям.
Надеюсь, что помогло:)