Причуды свиданий и современные альтернативы их преодолению

Общеизвестно, что объект JavaScript Date неисправен. Пока его не заменит современная альтернатива, фронтенд-разработчикам приходится мириться с его причудами. В этом посте объясняются две особенности, о которых должен знать каждый разработчик внешнего интерфейса, даже если вы используете TypeScript и служебную библиотеку даты, такую ​​как date-fns, zod или Day.js.

TLDR;

  • new Date(null) возвращает эпоху Unix 1970-01-01T00:00:00.000Z ;
  • При синтаксическом анализе значения на дату рассмотрите возможность ручной проверки того, value === null перед передачей значения в библиотеку, например date-fns или zod
  • Вот репозиторий с примерами безопасного синтаксического анализа в (i) обычном TypeScript, (ii) date-fns и (iii) zod.
  • Избегайте одной ошибки при использовании zod для анализа строк даты ISO 8601.

1. new Date(null) Неожиданно возвращает допустимую дату

В JavaScript создание Date путем передачи null конструктору генерирует эпоху Unix, привязанную к вашему местному часовому поясу:

Этот результат является неожиданным и может легко вызвать ошибки внешнего интерфейса. По определению null означает значение, которое пусто или не существует. Если API возвращает { lastModified: null } , держу пари, что ни один бэкэнд-разработчик не ожидает, что клиент установит lastModified в эпоху Unix.

Вот один из способов, которым эта ошибка может проникнуть в ваш код: скажем, вы используете служебную библиотеку даты, например date-fns, и пытаетесь убедиться, что что-то является действительной датой. Проблема new Date(null) по-прежнему останется незамеченной, потому что new Date(null) возвращает действительную дату:

Вы можете подумать про себя: «Меня это не беспокоит, потому что я использую TypeScript!» И в какой-то степени вы будете правы. Если вы используете TypeScript с параметром «strict» равным true, вы получите ошибку компиляции при создании даты с new Date(null).

Однако существует все еще нерешенная проблема. Поскольку new Date(null) возвращает правильную дату, такие библиотеки, как zod, принуждают ее к Date, даже если ваш проект использует TypeScript:

я. Решение

Так что же делать фронтенд-разработчику?

Одним из решений является фильтрация нулевых значений прежде, когда они получат актуальные утилиты. Вот пример, который оборачивает метод парсинга zod и фильтрует null и undefined:

Это репозиторий, который я создал с похожими примерами разбора даты, используя простые TypeScript и date-fns. Репозиторий также включает набор тестов Jest, если вы хотите проверить свои собственные методы анализа даты.

2. Бонус: следите за строками даты «ГГГГ-ММ-ДД» при использовании Zod

Ниже приведен краткий пример, показывающий один «подводный камень» при использовании zod для разбора строк даты:

Суть в том, что, в отличие от метода date-fns parseISO, zod не выполняет автоматический анализ дат ISO на локальные часовые пояса.

Стандарт ECMAScript для анализа строк даты ISO 8601 ('2023-01-01') имеет недостатки:

  • Стандарт ECMAScript предусматривает, что такие строки по умолчанию относятся к UTC.
  • Однако в действующем стандарте ISO 8601 указывается, что при отсутствии часового пояса такие строки должны по умолчанию указывать местный часовой пояс.

Почему ECMAScript работает именно так? Исходная спецификация комитета по Т39 была ошибочной, и они не могли ее пересмотреть до того, как она станет сетевой реальностью.

Эта проблема хорошо известна, и служебные библиотеки даты, такие как date-fns, предоставляют служебные методы, которые автоматически анализируют строки даты ISO в вашем местном часовом поясе. Если вы привыкли к этому удобству в вашей служебной библиотеке даты, просто имейте в виду, что zod в настоящее время не позаботится об этом за вас.

Наконец, вот шпаргалка для строк даты в JavaScript:

// ISO 8601 without time: defaults to midnight UTC time
const withHyphen = new Date('2023-01-01') // Sat Dec 31 2022 18:00:00 GMT-0600 (Central Standard Time)
withHyphens.getTime() // 1672531200000

// ISO 8601 set to UTC timezone (same as not providing time)
const noOffset = new Date('2023-01-01T00:00:00.000Z') // Sat Dec 31 2022 18:00:00 GMT-0600 (Central Standard Time)
noOffset.getTime() // 1672531200000

// ISO 8601 set to Local Timezone
const withLocalOffset = new Date('2023-01-01T06:00:00.000Z') // Sun Jan 01 2023 00:00:00 GMT-0600 (Central Standard Time)
withHyphens.getTime() // 1672552800000

// Well Recoginized String Format - Defaults to Local Timezone
const withSlashes = new Date('2023/01/01') // Sun Jan 01 2023 00:00:00 GMT-0600 (Central Standard Time)
withSlashes.getTime() // 1672552800000

// Number Arguments - Defaults to Local Timezone
const withArgs = new Date(2023, 0, 1) // Sun Jan 01 2023 00:00:00 GMT-0600 (Central Standard Time)
withArgs.getTime() // 1672552800000

Заключение

Спасибо, что прочитали мой пост о датах в JavaScript. Подводя итог, обратите внимание на значения конструктора null при работе с датами и обратите особое внимание на строки даты в следующем формате: «ГГГГ-ММ-ДД». Библиотеки служебных программ даты и средства проверки схем — отличные инструменты, но все еще есть шероховатости, требующие особого внимания.

О HeroDevs

HeroDevs – это студия разработки программного обеспечения и консалтинга, специализирующаяся на разработке интерфейсов. Наша команда является автором или соавтором таких проектов, как Angular CLI, Angular Universal, Scully, XLTS — расширенная долгосрочная поддержка AngularJS, ng-conf и многих других. Мы работаем с быстрорастущими стартапами и крупнейшими мировыми компаниями, такими как Google, GE, Capital One, Experian, T-Mobile, Corteva и другими. Узнайте больше о нас на herodevs.com.