Ваш путеводитель по часовым поясам в Интернете: понимание временных меток и дат Javascript

Ваш путеводитель по часовым поясам в Интернете: понимание временных меток и дат Javascript

4 января 2024 г.

Введение

Работа с часовыми поясами иногда становится запутанной, особенно если вы только начали работать над приложением, зависящим от часового пояса, и раньше у вас никогда не было такого опыта. Мир часовых поясов очень нестабильен. Каждый год на Земле происходит множество изменений часовых поясов, и обычные разработчики об этом не задумываются (да и не должны). Но для лучшего понимания того, как существует этот мир часовых поясов и как он связан с объектом даты Javascript, я хочу рассмотреть здесь есть пара вещей. Ниже я приведу несколько примеров, о которых вы, вероятно, никогда не задумывались. Голый со мной; вы найдете для себя что-то новое.

Инструменты

Если вы хотите следовать всем примерам из этой статьи, вам нужны только вкладки Консоль и Датчики в Chrome. Если вы не знаете, как найти функцию Датчики, используйте эту горячую клавишу в Инструментах разработчика Chrome:

ctrl + shift + p – Windows

⌘ + Shift + p – Mac

Затем введите «Показать датчики» — вы получите такую ​​опцию:

Когда вы нажмете «Ввод», откроется вкладка Датчики, где вы сможете изменить свое местоположение, часовой пояс и региональные стандарты.

О чем я буду говорить

Я хочу обсудить две вещи: во-первых, что такое временная метка, и, во-вторых, что означают UTC/GMT, CST, CDT, Америка/Чикаго и т. д.? Почему все это существует? Как они работают с объектом Javascript Date? Я постараюсь разъяснить вам это.

Без лишних слов, давайте начнем.

Временная метка

Предположим, что вы космонавт, летающий вокруг Земли на МКС, в какой-то момент вы решили запустить секундомер, который измеряет миллисекунды (Javascript использует миллисекунды под капотом объекта Date). С того момента, как вы запустите секундомер, вы никогда его не остановите. Поэтому количество миллисекунд растет со временем. Для каждого момента времени прошло некоторое количество миллисекунд. Неважно, где вы живете на Земле, на каком континенте, в стране, городе или улице – момент времени на этом секундомере одинаков для всех. Это звучит довольно очевидно, но я обнаружил, что это сбивает с толку многих людей. Считайте этот секундомер временной меткой. Другими словами, каждое состояние Земли во времени имеет номер. Ок, теперь у нас постоянно растут миллисекунды, но это не очень удобно для человека. Вы не можете сказать кому-то, что давайте встретимся где-нибудь в будущем в 1893456000000 мс.

Здесь начинают действовать часовые пояса. Дата и время, когда наш воображаемый космонавт запустил секундомер, — полночь 1 января 1970 года (вы, наверное, слышали о Эпохе Unix).

Ниже для наглядности приведен небольшой пример с тремя разными временными метками и соответствующими датами.

Хорошо, мы знаем, что в 0 мс у нас есть дата 01 января 1970 года 00:00:00, но другой вопрос, где именно? Ответ ниже на скриншоте. Эта линия, пересекающая часть планеты, называется UTC (или UTC+0). Таким образом, при 0 мс во всех местоположениях, лежащих на этой линии, указана полночь 1 января 1970 года.

Карта

Если вы хотите увидеть точные местоположения, вы можете найти их здесь

Ниже я расскажу подробнее об аббревиатуре UTC.

Самое важное здесь — понимать, что за объектом Date в Javascript находится временная метка. Все, что ниже, возвращает временную метку (число).

Number(new Date());
new Date().valueOf();
new Date()[Symbol.toPrimitive]('number');

Но не делайте этого в коде, потому что есть более правильный способ получить текущую метку времени из объекта Date:

new Date().getTime();

Хорошо, теперь, когда мы знаем, что такое отметка времени в Javascript, давайте поговорим подробнее о часовых поясах и о том, как они работают с объектом Date Javascript.

Часовой пояс и названия часовых поясов

Во-первых, давайте рассмотрим три разные группы часовых поясов, с которыми вы, вероятно, сталкивались.

  1. Часовой пояс UTC. Иногда вы можете видеть, что UTC и GMT используются как взаимозаменяемые. Даже если это не совсем правда, в нашем (не научном) случае давайте считать, что они одинаковы.
  2. Сокращенный часовой пояс (CST, EST, CDT, MST, < код>EST и т. д.)
  3. Часовой пояс IANA (Америка/Чикаго, Европа/Брюссель и т. д.)
  4. Все эти типы представляют собой некоторые географические области, но имеют разные свойства и поведение.

    UTC

    Я немного упомянул UTC в разделе «Метка времени», поскольку мы рассчитываем наш секундомер в географических точках UTC+0. Давайте подробнее углубимся в аббревиатуру UTC. Считайте UTC базовым для всех других типов часовых поясов. Это просто раскол Земли на 24 равных куска по 15° каждый (24 часа * 15° = 360°). Другими словами, Земля вращается на 15° каждый 1 час. Он совершает полный оборот за 24 часа. Каждая из этих 15-градусных частей имитируется названиями UTC, от UTC-11 до UTC+12 (включая UTC+0), что в общей сложности составляет 24.

    Я нашел хорошую картинку, которая иллюстрирует то, что я только что сказал.

    Посмотрите сверху и снизу карты (черные горизонтальные линии). Вверху вы можете увидеть градусы, внизу — часы. Таким образом, вы можете использовать UTC двумя способами.

    Подождите, вы, наверное, скажете, а как насчет UTC-12 или UTC+14, которые существуют для некоторых частей планеты, они находятся за пределами от -11 до +12. И это меня тоже поначалу смутило. Но ответ прост: вам следует просто понимать, что UTC можно использовать в двух разных контекстах. Во-первых, я только что объяснил вам, что касается равных физических частей Земли, а во-вторых, это просто сдвиг во времени.

    Но что значит быть смещенным во времени? Давайте посмотрим, что находится под UTC-12. Вы увидите такое название, как U.S. Отдаленные острова, поэтому вместо того, чтобы оставить эти острова в UTC+12, было просто политическое решение следовать времени UTC-12, чтобы соответствовать времени в других частях страны. Если бы эти острова не были частью США, мы, вероятно, увидели бы другие компенсации.

    Та же история с UTC+14. До 1994 года острова Лайн находились в часовом поясе UTC-10, но местное правительство решило перейти на часовой пояс UTC+14, чтобы соответствовать всем остальным частям республики.

    Другой причиной может быть переход на летнее время при сдвиге времени, например, с UTC+12 на UTC+13.

    Javascript позволяет вам устанавливать еще более экстремальные смещения:

    new Date("2023-07-15T10:00:00.000-23:59")
    

    Или

    new Date("2023-07-15T10:00:00.000+23:59")
    

    Попытка использовать смещение ±24 возвращает неверную дату, поскольку это не имеет смысла, поскольку 24 просто совершает полный оборот вокруг Земли и возвращает вас обратно в UTC+0.

    :::информация Забавно, что на Земле есть две локации, время между которыми составляет более 24 часов. Вот как эти двое (с разницей в 26 часов):

    :::

    Если вы хотите поиграть с UTC, чтобы лучше понять, как оно работает, вы можете найти в Интернете интерактивную карту, например это:

    Выше я упоминал, что UTC является основой объекта Date в Javascript. Это означает, что когда вы создаете новый объект Date, он берет текущее время UTC+0 и добавляет смещение часового пояса местоположения пользователя, чтобы в конечном итоге получить местное время пользователя.

    Например, введите эту дату в консоли браузера:

    new Date('2023-07-15T13:00:00')
    

    Вы получите что-то вроде этого:

    Sat Jul 15 2023 13:00:00 GMT-0500 (Central Daylight Time)
    

    В зависимости от того, где вы находитесь, результаты могут отличаться в зависимости от смещения. В моем случае это GMT-0500 (минус 5 часов). Помните, что здесь мы используем GMT и UTC как взаимозаменяемые слова.

    Расчет:

    Мне нравится думать о создании объекта Date из такой строки следующим образом (и, вероятно, именно так это и работает):

    1. Javascript видит эту строку 2023-07-15T13:00:00, анализирует ее и вычисляет метку времени UTC для этой даты (преобразует строку в метку времени). Он возвращает ту же метку времени, что и этот статический метод с указанными аргументами:
    2. Javascript Дата.UTC(2023, 6, 15, 13, 0, 0, 0); // возвращает 1689426000000

      2. Затем Javascript наблюдает за средой, в которой выполняется код, и проверяет смещение часового пояса от UTC+0.

      Javascript новая дата('2023-07-15').getTimezoneOffset();

      +300 минут в моем случае (может быть и со знаком минус, в зависимости от того, где вы находитесь)

      3. Затем он добавляет +300 минут (или +18000000 мс) к временной метке 1689426000000, которую мы получили на шаге 1.

      4. Затем он создает дату на основе этой отметки времени:

      Javascript новая дата(18000000 + 1689426000000);

      Вы можете проверить, что вы получаете одинаковые результаты при создании этих двух объектов Date (ваши результаты могут отличаться из-за смещения):

      Другими словами, это уравнение верно:

      ( new Date('2023-07-15T13:00:00').getTime() 
        - 
       new Date('2023-07-15').getTimezoneOffset() * 60 * 1000 ) 
       === 
      Date.UTC(2023, 6, 15, 13, 0, 0, 0)
      

      <Местная дата и время> - <Смещение UTC> === <UTC+0 Временная метка>

      Причина, по которой я помещаю строку даты в качестве аргумента здесь:

      new Date('2023-07-15').getTimezoneOffset() // 2023-07-15 argument is set
      

      это то, что в том месте, где вы находитесь, может быть летнее время (и общие исторические изменения влияют на то, что вы можете получить), поэтому для запуска метода таким образом new Date().getTimezoneOffset() может дать вам разные результаты в зависимости от того, где вы находитесь, а также даты и времени запуска этой функции.

      Сокращенный часовой пояс (CST, EST, CDT, MST и т. д.)

      Хорошо, теперь давайте поговорим о названиях часовых поясов, таких как CST (центральное стандартное время). Считайте такие сокращения другими названиями смещений UTC. Людям не очень удобно говорить о часовых поясах на языке UTC. Например, если кто-то спросит вас: «В каком вы часовом поясе?» без сокращенного часового пояса вы ответите что-то вроде «UTC-6». Это бы сработало, но это не очень удобно. Поэтому люди решили создать такие аббревиатуры, как в названии этого раздела. Одно сокращенное имя часового пояса может иметь только одно смещение UTC, но не наоборот.

      Например, следующие сокращения привязаны к определенному смещению.

      Но само смещение UTC может иметь множество сокращений.

      Будьте внимательны, когда используете такие имена. Например, CST может быть центральным стандартным временем, стандартным временем Китая или стандартным временем Кубы. Поэтому постарайтесь не создавать объект Date таким образом:

      new Date('15 Jul 2023 13:00:00 CST')
      

      Потому что это неоднозначно (и его нет в спецификации).

      В моем случае, когда я запускаю эту команду в Chrome

      он ​​рассматривает CST как центральное поясное время. И вполне вероятно, что в Chrome это работает одинаково, где бы вы ни находились. Но это не гарантирует, что так будет всегда.

      Я попытался указать текущее местоположение в Китае.

      Но в любом случае он устанавливает смещение как 360 минут или 6 часов (UTC-06) n

      Таким образом, даже если вы находитесь в Китае, Chrome рассматривает CST как центральное стандартное время Америки, а не стандартное время Китая. Мое первоначальное предположение было ошибочным, что браузер будет использовать смещение в зависимости от местоположения пользователя, если вы используете такие имена, которые имеют несколько переводов.

      n Другой способ проверить смещение (вероятно, более простой визуально) заключается в следующем:

      Вы видите, что возвращаемые даты совпадают, а это значит, что в данном случае

      CST === -06:00 n

      Еще одним свойством сокращенных часовых поясов является то, что они связаны со смещением UTC, а не с географическим разделением UTC. Например, Китай разбросан почти по пяти участкам UTC 15° (или пяти 5-часовым областям), но его местные власти решили сопоставить только одно смещение UTC+8. Таким образом, стандартное время Китая равно смещению UTC+8 (а не срезу UTC).

      Часовой пояс IANA

      Это единственный тип часового пояса, который содержит исторические данные о часовом поясе любых (населенных) мест. Часовые пояса выше, такие как UTC или CST/CDT, — это просто названия конкретных смещений. Да, они распространяются на конкретные регионы планеты, но никаких исторических данных не сохраняют. Например, в некоторых регионах CST применяется в зимнее время, а в летнее время применяется не CST, а CDT. Если какое-либо местоположение решит не использовать летнее время в какой-то момент времени, то в течение года у них будет только CST. Или если правительство региона решит перейти из одного часового пояса в другой, как в примере ниже, когда округ Уэйн в Кентукки в США решил перейти с CST на EST (это произошло 17 августа 2000 года). Но данные часового пояса до этого момента будут потеряны. Вы не можете извлечь эту информацию только из имени CST. Здесь на помощь приходит часовой пояс IANA.

      Представьте себе, что внутри браузера у вас есть такие исторические данные: n

      | Имя IANA | Смещение | Активен с | Активен до | |----|----|----|----| | Америка/Кентукки/Монтичелло | UTC-06 (ЦСТ) | 01 января 1970 г. | 16 августа 2000 г. | | Америка/Кентукки/Монтичелло | UTC-05 (EST) | 17 августа 2000 г. | Текущий |

      Кроме того, вам не нужно думать о летнем времени, когда вы ссылаетесь на имя IANA; он уже наблюдает за ним вместо вас.

      Чтобы лучше понять это, давайте рассмотрим несколько примеров. Вы увидите возможности часового пояса IANA, а также интересные примеры изменения часового пояса.

      :::совет Если вы хотите получить текущий часовой пояс IANA, вы можете ввести эту команду в консоли:

      :::

      Пример №1

      Вопрос: Можно ли изменить часовой пояс географической области?

      Ответ: Да.

      История:

      Давайте рассмотрим этот пример, когда географическая область изменила свой часовой пояс. Округ Уэйн в штате Кентукки в США 17 августа 2000 года был переведен из центрального часового пояса в восточный часовой пояс. Подробнее об этом можно прочитать здесь.

      Для моего примера я взял город Монтичелло из округа Уэйн. Он имеет часовой пояс IANA Америка/Кентукки/Монтичелло

      Поскольку это изменение произошло в 2000 году, то давайте посмотрим, какую дату и время мы получим в 1999 году (до изменения) и в 2001 году (после изменения) n

      Техническая часть (доказательство):

      (new Date(Date.UTC(1999,6,15,13,0,0,0))
        .toLocaleString('en-US', {timeZone: 'America/Kentucky/Monticello'}))
      

      Возвращает 15 июля 1999 г., 8:00:00

      (new Date(Date.UTC(2001,6,15,13,0,0,0))
        .toLocaleString('en-US', {timeZone: 'America/Kentucky/Monticello'}))
      

      Возвращает 15.07.2001, 9:00:00

      Таким образом, в 2000 году он возвращается на 1 час раньше, чем в 2001 году для той же временной метки.

      Эти два вызова отличаются только прошедшим годом статического метода Date.UTC. Таким образом, это доказывает, что часовой пояс IANA имеет историю.

      Пример №2

      Вопрос. Всегда ли географическая зона привязана к одному часовому поясу IANA?

      Ответ: Нет. На самом деле, пример №1 тоже может это доказать, но я решил взять другой пример.

      История:

      Давайте рассмотрим этот пример, который я нашел в журнале IANA здесь .

      По ссылке есть цитата:

      <блок-цитата>

      На северной окраине Чиуауа возобновляются правила летнего времени США. Новая зона Америка/Сьюдад_Хуарес для западной половины, которая воссоединяется с -07 с 30 ноября 2022 г.

      Это означает, что весь штат Чиуауа в Мексике до конца 2022 года жил по одним и тем же правилам часового пояса. У них был часовой пояс Америка/Охинага. Однако местное правительство решило, что в северной части Чиуауа время будет сдвинуто на 1 час во время летнего времени. Для IANA это означает, что они не могут использовать одно и то же имя America/Ojinaga для всего региона. В этом случае у них не было другого выбора, кроме как создать новое имя Америка/Сьюдад_Хуарес.

      Если подвести краткий итог, то до 2022 года Чиуауа имела единое имя IANA Америка/Охинага, после 2022 года Чиуауа разделилась на две половины. Первый живет под старым названием America/Ojinaga, а другой — под часовым поясом America/Ciudad_Juarez.

      n Техническая часть (доказательство):

      На этот раз я хочу показать вам, как браузер синхронизируется с базой данных IANA, когда происходит новое событие изменения часового пояса. Итак, мы знаем, что событие произошло 30 ноября 2022 года. Затем давайте запустим версию Chrome 106 (выпущенную 27 сентября 2022 года), то есть до разделения Чиуауа, а затем запустим версию Chrome 118 (выпущенную 4 октября 2023 года). 118 - потому что на данный момент у меня как раз установлена ​​эта версия, и это далеко в будущем от произошедшего события.

      Запустите это:

      new Date(Date.UTC(2023, 6, 15, 13, 0, 0, 0))
        .toLocaleString('en-US', {timeZone: 'America/Ojinaga'})
      

      Chrome версии 106 возвращает 15 июля 2023 г., 7:00:00

      Chrome версии 118 возвращает 15.07.2023, 8:00:00

      Тот же код, тот же браузер, то же системное время, но разные результаты в зависимости от версии Chrome.

      Кстати, запуск этого часового пояса в версии 106 вызывает ошибку:

      new Date(Date.UTC(2023, 6, 15, 13, 0, 0, 0))
        .toLocaleString('en-US', {timeZone: 'America/Ciudad_Juarez'})
      

      Invalid time zone specified: America/Ciudad_Juarez
      

      потому что на данный момент он не был добавлен.

      Пример №3

      Вопрос. Что, если мы сдвинем системное время ОС, будет ли оно соответствовать историческим изменениям часового пояса?

      Ответ: Да.

      История: 31 декабря 1994 года на островах Лайн (Республика Кирибати) сменили часовой пояс, переведя время на целый день (с UTC-10 на UTC+14). Почему они это сделали, лучше прочитать на в сети, но это интересный случай, который мы можем использовать ради например с часовыми поясами.

      Техническая часть (доказательство):

      Я взял город с названием Лондон, нет, не тот, о котором вы думаете, а тот, что на острове Кирибати — он входит в группу островов.

      Если вам интересно, то этот город находится здесь.

      Добавьте новое местоположение в сенсоры Chrome. Вы можете использовать настройки, которые я установил. н

      Latitude: 1.984623759310528
      Longitude:  -157.47449242454888
      Timezone ID: Pacific/Kiritimati
      Locale: en-US
      

      Хорошо, мы знаем, что в 1995 году в этом месте все изменилось. Итак, попробуем это проверить.

      Но сейчас мы не будем менять версию браузера (на самом деле, это не имеет смысла; конкретно Chrome на тот момент еще не существовало). Давайте изменим системное время (время ОС) где-то на середину 1994 года, затем проверим, какой объект Date мы получим, затем снова переместим системное время на 1996 год и проделаем ту же процедуру.

      Я использую Mac, поэтому я перехожу в «Системные настройки» → «Основные» → «Дата и усиление». Время → Изменить дату и время.

      Хорошо, вот что вернет объект Date за 1994 год:

      После изменения года на 1996:

      Вы видите, что в 1996 году для той же системной даты мы получаем другой день: 16 июля вместо 15 июля.

      Тот же эффект мы можем получить, используя свойство timeZone метода toLocaleString

      н

      Сводка

      Из всего перечисленного:

      • Не следует жестко кодировать часовые пояса IANA непосредственно в веб-приложении, если вы сопоставляете часовые пояса с конкретным местоположением, предполагая, что оно будет постоянным навсегда. Выше я доказал, что часовой пояс IANA для конкретной точки на карте также можно изменить. Вот почему существует такой API.
      • Объект Date — это просто временная метка. Эта временная метка может обрабатываться по-разному в зависимости от того, где находится пользовательский агент (браузер).
      • Смена часового пояса происходит регулярно, вы можете отслеживать это здесь.
      • Зная часовой пояс IANA для определенного места на карте, вы можете получить точную дату и время с учетом исторических изменений часового пояса.


      Оригинал