Анализ даты Javascript возвращает странные результаты в Chrome

Я заметил странное поведение Date в Chrome (версия 74.0.3729.131 (официальная сборка) (64-разрядная версия)). Следующий javascript был выполнен в консоли Chrome Dev:

new Date('1894-01-01T00:00:00+01:00')
// result: Mon Jan 01 1894 00:00:00 GMT+0100 (Central European Standard Time)

new Date('1893-01-01T00:00:00+01:00')
// result: Sat Dec 31 1892 23:53:28 GMT+0053 (Central European Standard Time)

Я уже читал о нестандартном анализе даты через Date ctor в разных браузерах, хотя и предоставлял действительные значения ISO8601. Но это более чем странно о_о

В Firefox (Quantum 66.0.3 (64-разрядная версия)) те же вызовы приводят к ожидаемым объектам Date:

new Date('1894-01-01T00:00:00+01:00')
// result: > Date 1892-12-31T23:00:00.000Z

new Date('1893-01-01T00:00:00+01:00')
// result: > Date 1893-12-31T23:00:00.000Z
  • Это ошибка в Хроме?
  • Думаю, мой ввод действителен для ISO8601?
  • Самый главный вопрос, как это исправить? (надеюсь, без разбора входной строки самостоятельно)

Может, в 1893 году были какие-то события, связанные со временем? (по запросу историков ИТТ)

Limbo 09.05.2019 13:38

У меня есть Sun Jan 01 1893 01:02:04 GMT+0202 (Eastern European Standard Time) и Mon Jan 01 1894 01:02:04 GMT+0202 (Eastern European Standard Time). Похоже, что до 1925 года GMT был сдвинут или что-то в этом роде (потому что я получаю четкое смещение по Гринвичу только с 1925 года).

Limbo 09.05.2019 13:46

Ну, к вашему сведению, на моем ПК дата взлома 1924-05-01. Полагаю, Хром каким-то образом использует историческую информацию о времени (в 1924 году был первый хроносигнал из Гринвичской обсерватории, так что, возможно, это как-то повлияло на мировое время). Идея сумасшедшая, я знаю :D

Limbo 09.05.2019 13:57

Интересно: Chrome добавил некоторые изменения в синтаксический анализ даты в версии 67 из-за некоторых обновлений спецификации сценария ecma, касающихся смещений часового пояса: хром-обзор.googlesource.com/c/v8/v8/+/572148

cmxl 09.05.2019 14:32

Возможно релевантные stackoverflow.com/a/56121124/441757 и stackoverflow.com/a/14282490/441757

sideshowbarker 14.05.2019 04:23

время такой беспорядок @_@

cmxl 14.05.2019 14:02
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
9
6
686
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Это может быть тот случай, когда все браузеры следуют своим собственным стандартам кодирования форматов даты (но я не уверен в этом). В любом случае, это просто исправить, применив метод toISOString.

const today = new Date();
console.info(today.toISOString());

хорошо, так что для отображения цели это будет делать. Но мне нужно проверить, будут ли вычисления корректно работать с форматом Chrome.

cmxl 09.05.2019 12:48

Будем надеяться, что вычисления будут работать нормально, поскольку каждый движок JavaScript преобразует даты в целые числа, а затем обрабатывает их, что приводит к единообразию. @cmxl

Danyal Imran 09.05.2019 13:32
Ответ принят как подходящий

Хорошо, похоже, что этого поведения нельзя избежать, поэтому вам следует анализировать даты вручную. Но способ его разбора довольно прост.

Если мы разбираем дату в формате 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

Да, мы не можем этого избежать, потому что это слишком круто. 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.info(testDate1.toLocaleDateString(), testDate1.toLocaleTimeString())
console.info(testDate2.toLocaleDateString(), testDate2.toLocaleTimeString())
console.info(testDate3.toLocaleDateString(), testDate3.toLocaleTimeString())
console.info(testDate4.toLocaleDateString(), testDate4.toLocaleTimeString())

Примечание

В этом случае мы получаем экземпляр Date со всеми его собственными значениями (например, .getHours()), равными нормализованный, включая смещение часового пояса. testDate1.toISOString все равно вернет странный результат. Но если вы работаете с этой датой, она, вероятно, на 100% удовлетворит ваши потребности.

Надеюсь, это помогло :)

Спасибо @Лимбо!

cmxl 09.05.2019 16:09

Другие вопросы по теме