AKA: Почему ваша дата JavaScript всегда отключается на 1 день

Даты JavaScript сбивают с толку. Более того, они могут быть наименее увлекательным предметом для изучения в программировании на JavaScript.

Но что произойдет, если вы создаете приложение Todo - вы знаете, это наиболее часто используемое веб-приложение из существующих, и вы хотите добавить функцию напоминания календаря?

Если в ваших датах неправильно указаны часовые пояса и вы получите ошибку «off by 1», ваш пользователь, пропустивший собеседование, будет В ярости от вашего приложения.

Мое признание о датах JavaScript

Мне потребовалось по крайней мере 3 года программирования, прежде чем я наконец сел, чтобы разобраться в этой теме. И если я должен был догадаться, некоторые из вас, читающих это, находятся в похожем месте, так что приветствую это! 🍻

Осторожно, спойлеры

Даты JavaScript на самом деле не так уж и сложны. Прочитав этот пост, вы поймете, что сложная часть дат JavaScript - это не связанные с JavaScript концепции, такие как часовые пояса и стандарты форматирования.

Большинство людей ищут руководства по датам JavaScript, когда все, что им нужно, - это обзор того, как работает время! (включая меня)

Прежде чем я начну читать… А как насчет MomentJS?

Кажется, сейчас все крутые ребята используют MomentJS (а если еще круче - Luxon).

Не волнуйтесь, я не какой-то пурист в JavaScript и говорю вам всегда работать с обычными объектами даты JS - я просто хочу проработать основные концепции, которые сделают вашу жизнь с Moment / Luxon намного проще.

Наконец, приступим.

Представьте себе: вы кодите 8 часов, ваш мозг немного устал, и вы console.log одно из свиданий во время интенсивного сеанса отладки:

new Date('2020-09-30')
// Output: Tue Sep 29 2020 20:00:00 GMT-0400 (Eastern Daylight Time)

Ваааа ???

Подождите, это сбивает с толку. Вот мой локальный компьютер (компьютер, на котором я сейчас стою в восточной части США):

А вот веб-сервер, на котором я запускаю свое приложение для обучения игре в гольф:

Заметили что-нибудь? На моем локальном компьютере результат .toDateString() был Tue Sep 29 2020, а на моем сервере результат .toDateString() был Wed Sep 30 2020. Более того, оба компьютера вернули одинаковый результат для toISOString() метода!

Либо я схожу с ума, либо мы просто набирали одно и то же на двух разных компьютерах и получили совершенно другой ответ - не говоря уже о том, что один из компьютеров совершенно неверно указал мою дату !! Или сделал это…

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

Это последний раз, когда вас смутят даты JavaScript.

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

Вот часовой пояс моего локального компьютера:

А вот часовой пояс моего сервера:

Как видите, часовой пояс локального компьютера - EST / EDT, а часовой пояс сервера - UTC. Это, наряду с некоторыми особенностями JavaScript, является причиной того, что мы получили такие неожиданные результаты выше. Но это не будет иметь смысла, пока мы больше не исследуем внутренности этого процесса.

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

Что такое UTC? (ключ к пониманию дат JavaScript)

UTC расшифровывается как «универсальное координированное время», и, судя по названию, это основа того, как хранится время. Ну… вроде.

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

ВНИМАНИЕ. Здесь мы отвлечемся на несколько минут, но если мы действительно хотим вспомнить, как работают эти надоедливые даты JavaScript, нам нужен некоторый исторический контекст. Если вы не хотите читать мой краткий урок истории, переходите к следующей части этого поста.

Представьте, что в совершенно солнечный день вы втыкаете в землю совершенно вертикальный столб. Когда солнце встает, этот полюс отбрасывает тень на запад и, наоборот, отбрасывает тень на восток при заходе солнца. Если бы вы посчитали, сколько времени потребовалось этой тени, чтобы перемещаться от точки к точке, вы могли бы (отчасти) отслеживать время.

Но есть проблема… Если я поставлю вертикальный столб в землю в том месте, где я живу в США, тени не будут отбрасываться в том же направлении, в то время как кто-то ставит столб в земле где-то в Ирландии.

Чтобы решить эту проблему, нам нужны общая контрольная точка и стандарт времени. В какой-то момент некоторые ученые подумали, что использование долготы 0 ° (также известной как «нулевой меридиан», который, оказывается, соответствует Гринвичу, Великобритания), было бы хорошей «универсальной точкой отсчета», чтобы поставить этот пресловутый «полюс в землю».

Следующая задача - вычислить «время» на основе этого «столба в земле». Раньше его рассчитывали с использованием среднего времени по Гринвичу (стандарт GMT - начался в 1847 году), но где-то в начале 1960-х некоторые инженеры решили, что нам нужен новый стандарт с более последовательным расчетом, чем по Гринвичу.

В 1970 году был окончательно доработан стандарт UTC, но в 1972 году была внесена поправка, чтобы периодически добавлять дополнительные секунды, чтобы обеспечить согласование всемирного координированного времени со средним солнечным временем (которое незначительно неточные из-за неравномерности вращения Земли).

Сегодня есть 3 основных способа вычисления «времени» (которые начинают значить все меньше и меньше для меня, когда я пишу это):

  1. Среднее солнечное время (UT1)
  2. Универсально координированное время (UTC)
  3. Международное атомное время (TAI)

TAI является наиболее точным и рассчитывается Атомными часами.

UTC является производным TAI, но к нему добавлены дополнительные секунды, чтобы оставаться синхронизированным с UT1.

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

ЛЮБОПЫТНЫЙ ФАКТ

Последняя дополнительная секунда была добавлена ​​30 июня 2015 года, а в 2023 году на Всемирной конференции по радиосвязи будет обсуждаться возможное удаление дополнительных секунд из стандарта времени UTC, который не был изменен. с 1972 г.

Все вращается вокруг UTC

С 1972 года мир работает на основе этого стандарта UTC, который считается +/- 0, когда речь идет о часовых поясах:

Если мы переместимся на запад от часового пояса UTC, каждый последующий часовой пояс станет на 1 час более отрицательным, в то время как противоположное применяется при путешествии на восток.

И, как вы могли догадаться, поскольку мир является сферой, перемещение на восток в конечном итоге приведет вас к «западному» часовому поясу, поэтому, например, часовой пояс -10 эквивалентен часовому поясу +14.

Часовые пояса можно определить двумя способами (а как насчет перехода на летнее время?)

Мы можем говорить о часовых поясах двумя способами:

  1. В качестве числовой ссылки на «нулевую точку», которая является часовым поясом UTC.
  2. Как общеизвестное имя, например «UTC» или «EST».

Единственное, что мы ДОЛЖНЫ помнить, это то, что UTC не меняется. НИКОГДА.

Я живу в восточной части США, поэтому с 4 ноября 2019 г. → 7 марта 2020 г. я жил в часовом поясе EST или в поясе Стандартное восточное время (Северная Америка) из официального списка часовых поясов. Часовой пояс EST также может называться UTC-05, потому что он находится на 5 часов к западу от часового пояса UTC.

Но что произойдет 8 марта 2020 года - в первый день перехода на летнее время в США?

Если всемирное координированное время никогда не меняется, то как мы узнаем, что сейчас летнее время?

8 марта 2020 г. (первый день перехода на летнее время в США) мой часовой пояс меняется с EST → EDT, или «Восточное стандартное время (Северная Америка)» → «Восточное летнее время (Северная Америка). ».

EDT также может называться «UTC-04», потому что мы «рванулись вперед» в результате перехода на летнее время, и теперь я отстаю всего на 4 часа от UTC.

Посмотрите, как это работает ?? UTC никогда не меняется, но часовой пояс, в котором вы живете, ДЕЙСТВУЕТ. Для большинства это не имеет значения, потому что, когда я говорю: «Мероприятие начинается в 10 утра по восточному стандартному времени», никто не будет спрашивать меня, говорю ли я о EST или EDT. Никого не волнует, потому что наши смартфоны делают «закулисные» преобразования.

Но как разработчики JavaScript, мы сами пишем эти преобразования, и поэтому, вероятно, должны разбираться в этом материале!

Но… Моя дата в JavaScript говорит: «GMT-0400».

Помните - JavaScript - это странно. И, как ни странно, он все еще использует «GMT» или «Среднее время по Гринвичу» для представления, но не вычисления дат.

Когда вы видите «GMT» в своем мозгу, просто думайте «UTC».

И когда вы видите «GMT-0400», это то же самое, что сказать «UTC-04», «EDT» или «Восточное летнее время (Северная Америка)», как мы определили в предыдущем разделе.

JavaScript был изобретен в 90-х, поэтому я действительно не уверен, почему они не использовали просто «UTC-0400», а не «GMT-0400», но это вопрос другого дня.

Но как насчет эпохи UNIX?

Итак, вернемся к компьютерам. Вы наверняка слышали термин «эпоха UNIX», который определяется как 1 января 1970 года.

Вот он в формате ISO 8601 (подробнее об этом позже):

1970-01-01T00:00:00Z

В то время как инженеры «времени» усердно работали над определением стандарта UTC в начале 1970-х, компьютерные инженеры также усердно работали над созданием компьютеров. Когда вы создаете компьютер, вы должны указать ему точку отсчета и «тиковую» частоту, чтобы он запомнил, который сейчас час. И эта точка отсчета была произвольно выбрана как полночь 1 января 1970 года.

Некоторые источники спорят об истинной причине этой даты, но, в конце концов, это не имеет значения. Это просто ориентир. Не стесняйтесь оставлять свои теории (или истории) по этому поводу в комментариях - я бы с удовольствием их прочитал.

Так что же такое дата в JavaScript?

Дата в JavaScript - это количество миллисекунд, прошедших с полуночи 1 января 1970 года (часовой пояс UTC).

Хм ... Эта дата звучит знакомо ...

При работе с датами JavaScript вы должны ВСЕГДА помнить это определение. В объекте Date есть множество функций-прототипов, таких как getDate(), getUTCDate() и toISOString, но есть только 1 метод, который дает вам истинное представление даты JavaScript:

const myDate = new Date('2020-01-01');
console.log(myDate.valueOf()) // 1577836800000

Метод valueOf() сообщает нам, что полночь 1 января 2020 года (часовой пояс UTC) составляет 1577836800000 миллисекунд после полуночи 1 января 1970 года (часовой пояс UTC).

И если вы похожи на меня, вас, вероятно, интересует часть .032876712. Это високосные годы. С 1970 года у нас были високосные годы:

1972, 1976, 1980, 1984, 1988, 1992, 1996, 2000, 2004, 2008, 2012, 2016, 2020

Поскольку мы используем 1 января 2020 года, а дополнительный день добавляется в феврале, нам нужно исключить високосный год 2020 из расчета, что оставляет нам 12 високосных лет с 1 января 1970 года. А если преобразовать годы в дни:

Вот так мы получаем лишние десятичные дроби 😆

Итак, если мы хотим вычислить дату до 1 января 1970 года, возможно ли это?

Конечно! Значение будет просто отрицательным.

const d = new Date('1912-06-23');
console.log(d.valueOf()) // -1815350400000

Возможные выходные значения объекта даты

Когда мы напечатали valueOf() дату, указанную выше, вы могли заметить, что на выходе получилось число. Это первый из трех возможных выходов объекта Date:

  1. Примитивное значение объекта даты (число)
  2. ISO 8601 (строка)
  3. Стандартный формат JavaScript (строка)

Вот примеры каждого из них:

const myDate = new Date('2020-09-30');
// Primitive value (number)
myDate.valueOf() // 1601424000000
// ISO 8601 (string)
myDate.toISOString() // "2020-09-30T00:00:00.000Z"
// JavaScript Standard Format (string)
myDate.toString() // "Tue Sep 29 2020 20:00:00 GMT-0400 (Eastern Daylight Time)"

Примитивное значение даты JavaScript простое. Как мы уже говорили, он представляет собой числовое значение в миллисекундах с полуночи 1 января 1970 года (часовой пояс UTC).

Формат ISO 8601 немного сбивает с толку, но если разбить его по частям, он уже не выглядит таким устрашающим. ISO 8601 на самом деле не имеет ничего общего с JavaScript - это глобальный стандарт для времени и даты (подробнее об этом в Приложении, если вам интересно).

Мы поговорим об этом формате немного позже, а пока просто помните, что T - это индикатор времени, а Z - индикатор часового пояса. В данном случае Z происходит от Zulu Time, которое является эталоном военного часового пояса для часового пояса UTC. Так что помните:

Z === “Zulu Time” (military) === UTC time (JavaScript)

Каждый раз, когда вы используете toISOString() в объекте JavaScript Date, вы ВСЕГДА получаете представление даты в формате UTC, обозначенное Z.

И последнее, но не менее важное - стандартный формат даты JavaScript.

На мой взгляд, это самый запутанный вывод из всех. Примитивное значение печатает количество миллисекунд, прошедших с эпохи, что легко понять. Значение ISO 8601 печатает значение даты, представленное в стандартизированном формате, который никогда не изменяется. Но стандартный формат JavaScript? Он не только печатает часовой пояс, о котором мы еще не много говорили, но также дает неожиданные результаты, как показано выше (вход 30 сентября меняется на выход 29 сентября)!

Давайте разгадываем эту загадку JavaScript раз и навсегда.

Повесть о двух компьютерах (и почему они не могут прийти к единому мнению, какая это дата!)

В начале этой публикации, до того, как мы узнали что-либо о UTC, я показал пример того, как даты JavaScript могут отображаться по-разному в зависимости от компьютера, который вы используете, и что часовой пояс компьютера.

В этом разделе мы собираемся использовать два компьютера и одну дату (30 сентября 2020 года - день написания), чтобы точно продемонстрировать, почему ваша дата «отклонена на 1».

Вот два разных компьютера с разными часовыми поясами, как показано на снимке экрана ниже. Обратите внимание, как напечатанные часовые пояса выглядят немного иначе, чем часовые пояса, о которых мы говорили ранее. Это потому, что существует два официальных списка часовых поясов - обычный и компьютерный. В первой части поста мы использовали обычный список, а ниже мы используем компьютерный список. Настоящей разницы нет, только семантика.

Итак, помните, когда мы рассматриваем эти примеры:

Давайте начнем с простого свидания и получим его примитивное значение.

Все идет нормально. Мы передали значение '2020-09-30' в качестве входа и получили тот же результат - 1601424000000.

Теперь давайте посмотрим, что произойдет, если мы напечатаем это как время UTC:

Все еще хорошо здесь. Как и ожидалось, они показывают те же значения. Давайте посмотрим на это как на строку ISO, которая должна быть тем же, что и строка UTC.

И снова мы получаем то же значение, что и ожидалось. Но теперь пришло время по-настоящему повеселиться:

Вот почему даты в JavaScript сбивают с толку так много людей (включая меня в прошлом).

Давайте подумаем ... Мы знаем следующее:

  • Мы использовали входное значение 2020-09-30
  • Примитивное значение даты в JavaScript составляет 1601424000000 миллисекунд с полуночи 1 января 1970 г. (время UTC).
  • Если мы конвертируем примитивное значение во время UTC, оно представляет собой полночь 30 сентября 2020 года.

Итак, что мы можем сделать здесь, так это то, что некоторые методы даты JavaScript выводят «истинное» значение хранящейся внутри даты , в то время как другие методы выводят «относительное» значение внутренней даты, основанное на часовом поясе компьютера, печатающего это значение.

Помните, что компьютер слева находится в часовом поясе EDT, то есть «UTC-04».

Итак, если внутреннее значение этой даты равно 160142400000 (полночь, 30 сентября 2020 года по всемирному координированному времени), то, если мы конвертируем это значение во время EDT, мы должны вычесть 4 часа. Если мы вычтем 4 часа, начиная с полуночи, тогда «относительное» значение часового пояса этой даты будет 20:00. (т.е. 20:00), 29 сентября 2020 г.

Хорошо, я понял, но почему JavaScript так делает?

Итак, вот как работают даты в JavaScript:

  1. Вы вводите такое значение, как 2020-09-30
  2. JavaScript предполагает, что это значение - время UTC.
  3. JavaScript сохраняет его как время UTC
  4. JavaScript выводит его в ваше местное время при использовании toString() метода или когда вы console.log дату

Настоящий вопрос ... Если JavaScript предполагает, что вы вводите значение UTC, то почему он не предполагает, что вы хотите выводить значение UTC?

Что ж, в глазах JavaScript, когда вы набирали 2020-09-30, вы не были достаточно конкретны.

Итак, давайте поговорим о том, как можно избежать этой проблемы.

Как думать о датах JavaScript

При работе с датами JavaScript нам необходимо задать себе следующие вопросы:

  1. Какое у меня было входное значение и указывал ли я часовой пояс? (т.е. 2020-09-30 против 2020–09–30 GMT-0400)
  2. Каково значение моей даты в формате UTC? (вы всегда можете найти это, используя .toISOString())
  3. Какой метод JavaScript я использую для отображения даты и в каком часовом поясе будет выводиться мое значение?

Допустим, вы создаете приложение, которое позволяет пользователю указывать день рождения в своем профиле. А представьте, что день рождения нашего пользователя 28 июня 1971 года, и он живет во Флориде (восточный часовой пояс).

Итак, вы очень быстро кодируете приложение и спрашиваете пользователя о его / ее дне рождения:

Пользователь выбрал 28 июня, но ваше веб-приложение показывает 27 июня при печати в виде строки 😢

Вот код этого веб-приложения - посмотрим, заметите ли вы ошибку:

Давайте пройдемся по нашему контрольному списку ранее:

  1. Что такое входное значение и указывал ли я часовой пояс? - по умолчанию ввод HTML5 будет записывать выбранную дату в формате UTC. Технически мы указываем часовой пояс, но это значение по умолчанию - UTC.
  2. Каково значение этой даты по всемирному координированному времени? - если бы вы напечатали console.log(dateValue.toISOString()), вы бы получили 1971-06-28T00:00:00.000Z, который представляет значение UTC.
  3. Какой метод JavaScript я использую для отображения даты? - Здесь мы ошиблись. Наше входное значение было записано в формате UTC, но поскольку мы использовали методы getDate(), getMonth() и getFullYear(), они преобразуют необработанную дату в местный часовой пояс пользователя, который является восточным стандартным часовым поясом (Северная Америка)!

Итак, как это исправить?

Есть два метода:

  1. Самый простой - отображение даты в формате UTC (в соответствии с тем, как она была введена)
  2. Сложнее - спросите у пользователя его часовой пояс и укажите этот часовой пояс при сохранении даты.

При использовании первого метода все, что вам нужно сделать, это изменить это:

const day = dateValue.getDate();
const month = dateValue.getMonth() + 1; // Return Value is 0 indexed
const year = dateValue.getFullYear();

к этому:

const day = dateValue.getUTCDate();
const month = dateValue.getUTCMonth() + 1; // Return Value is 0 indexed
const year = dateValue.getUTCFullYear();

И после этих изменений вуаля! Оно работает!

Второй способ более сложный, но все же может работать. Допустим, вы попросили этого пользователя выбрать свой часовой пояс, и он выбрал часовой пояс «EDT - Eastern Daylight Time (North America)».

Получив эту информацию, вы можете использовать следующий код JavaScript (хотя я не рекомендую):

Как видите, это намного больше строк кода и немного повторяющийся - определенно не рекомендуется.

Многочисленные способы использования дат JavaScript

Пример в предыдущем разделе выделяет конкретный сценарий «ошибок», но есть много других способов работы с датами JS.

Например, в объект Date можно передать что угодно:

// EXAMPLE #1
// Inputs as arguments
// Date(year, month, day, hour, minute, second, millisecond)
// Note: the month is 0-indexed (I have no clue why...)
new Date(2020, 11, 2, 7, 10);
// EXAMPLE #2
// Inputs as various strings
// This works with pretty much anything you can think of
new Date('Jan 20 2020');
new Date('January 20 2020');
new Date('Jan-20-2020');
new Date('Jan 20 2020 02:20:10')
// EXAMPLE #3
// Inputs as numbers (milliseconds)
new Date(102031203)
// EXAMPLE #4
// Inputs as ISO 8601 (we are about to talk about this)
new Date('2020-01-20T00:00Z')
// EXAMPLE #5
// Inputs with timezone specifications
new Date('Jan 20 2020 02:20:10 -10:00') // SPECIAL CASE
new Date('Jan 20 2020 02:20:10 -1000') // SPECIAL CASE
new Date('Jan 20 2020 02:20:10 (EDT)') // SPECIAL CASE
// EXAMPLE #6
// The current moment, specified in the user's local timezone
new Date(Date.now()) // SPECIAL CASE

Помните, всегда обращайте внимание на вводимые значения! В примерах 1–4 мы указываем эти даты во времени UTC! Примеры 5 и 6 - единственные случаи, когда мы указываем даты в соответствии с определенным часовым поясом. В примере 5 мы делаем это явно. В примере 6 статический метод Date.now() автоматически вычисляет текущую дату и время в часовом поясе вашего компьютера. Этот метод возвращает собственное значение Date - количество миллисекунд с полуночи 1 января 1970 года по всемирному координированному времени, поэтому нам нужно передать это значение в конструктор Date(), чтобы получить фактический объект даты.

Другими словами, если вы планируете мероприятие Livestream, которое состоится в Калифорнии 10 августа 2020 г. (помните, что это будет летнее время) в 20:00, вам необходимо ввести его как (где PDT - тихоокеанское летнее время) :

const myEventDate = new Date('Aug 10 2020 08:00:00 PDT');

и отобразить его как:

myEventDate.toString();

Это гарантирует, что у любого, кто читает это со своего персонального компьютера (в другом часовом поясе), будет отображаться время и дата этого события Livestream по их местному времени. Не стесняйтесь попробовать сами! В выводе myEventDate.toString() должны быть указаны время и дата события, преобразованного в ВАШ часовой пояс.

Должен быть более простой способ сделать это (MomentJS и LuxonJS)

Нет, вы не застряли с ванильным объектом Date в JavaScript. Существуют библиотеки, такие как Moment and Luxon (Luxon - новейший проект от создателей Moment), которые предоставляют вам быстрые и простые методы для создания и форматирования дат.

Тем не менее, я рекомендую полностью и внимательно прочитать этот пост хотя бы один или два раза, прежде чем использовать эти библиотеки, потому что, хотя в этих библиотеках есть много вспомогательных методов для работы с датами JavaScript, они не меняют внутреннюю работу дат JavaScript и все равно будут бросьте свой мозг на сюрприз, если вы не понимаете основных концепций!

Вот та же проблема, что и ранее, продемонстрированная с MomentJS. И запомни:

Как видите, здесь та же проблема. Но… Moment немного умнее JavaScript Dates. Если вы введете дату прямо в объект момента, он будет работать:

Moment не только предотвращает распространенные ловушки даты (в большинстве случаев), но также предоставляет простые методы форматирования дат!

Это ни в коем случае не руководство по использованию MomentJS или Luxon - ознакомьтесь с их документацией самостоятельно. Мое намерение здесь состояло в том, чтобы указать, что, хотя эти библиотеки предоставляют простые способы работы с датами JavaScript, они не меняют способ работы дат JS, и вам все равно следует поработать, чтобы понять их!

Приложение: Праймер по ISO 8601 (необязательно)

Помните, что есть 3 возможных формата вывода для дат JavaScript:

  1. Примитивное значение объекта даты (число)
  2. ISO 8601 (строка)
  3. Стандартный формат JavaScript (строка)

В этом приложении мы более подробно рассмотрим стандартный формат ISO 8601.

Так же, как UTC не является специфической концепцией JavaScript, как и ISO 8601.

ISO 8601 является международным стандартом и представлен в двух основных вариантах:

  1. Базовый
  2. Расширенный

JavaScript использует «расширенный» вариант, что означает просто наличие разделителей между различными типами значений. Например, давайте посмотрим на «Базовую» версию даты и времени:

20200930T000000.000Z

Это соответствует полуночи по всемирному координированному времени 30 сентября 2020 года с использованием «Базового» формата стандарта ISO 8601. Но он не очень удобочитаемый, и JavaScript его не принимает:

Единственная разница между «Базовым» и «Расширенным» вариантами ISO 8601 - это использование разделителей. Вот эта же дата в «расширенном» формате:

2020-09-30T00:00:00.000Z

И в этом случае JavaScript принимает его как действительный. Результат - 29 сентября, потому что мой браузер конвертирует UTC (полночь, 30 сентября) в EST (20:00, 29 сентября). Он выполняет это преобразование, потому что я живу в часовом поясе EST (объяснено в основном сообщении).

Вот детали:

По большей части это не требует пояснений. YYYY представляет полный год, MM представляет месяц, дополненный нулями, если необходимо (например, 01 для января), аDD представляет день, дополненный нулями, если необходимо.

T - это просто индикатор того, что «мы собираемся ввести значения времени, а не значения даты».

Опять же, HH, MM, SS и SSS представляют часы, минуты, секунды и миллисекунды соответственно.

Z представляет часовой пояс UTC. Каждый раз, когда вы добавляете этот Z в конец строки даты ISO, ваша дата будет интерпретироваться как время UTC. Если вы его не укажете, дата будет интерпретироваться как местное время.

Последнее, что вам нужно знать о строках ISO 8601, это то, что они гибкие. С их помощью вы можете уменьшить специфичность. Например, действительны все следующие строки ISO:

new Date('2020Z') // 2020-01-01T00:00:00.000Z
new Date('2020-05Z') // 2020-05-01T00:00:00.000Z
new Date('2020-05-10T00:00Z') // 2020-05-10T00:00:00.000Z

И если мы отбросим это Z, даты останутся действительными, но они будут интерпретироваться как местное время (если вы не понимаете этого сейчас, ничего страшного, мы рассмотрим это позже)

// Adding the Z interprets dates as UTC time
new Date('2020-05-10T00:00Z') // 2020-05-10T00:00:00.000Z
// Dropping the Z interprets dates as local time
new Date('2020-05-10T00:00') // 2020-05-10T04:00:00.000Z

4000 слов спустя ...

Если вы написали более 4000 слов в посте на JavaScript Dates,

Если вы хотите почитать о более скучных темах, например о датах JavaScript, вот несколько, которые я написал:

Самое запутанное в JavaScript: ключевое слово this

Общие сведения об IP-адресах и домашних сетях