Однажды я попытался не использовать date-fns

В одном из Pull-запросов моей команды я заметил, что date-fns был добавлен в качестве зависимости для нашей библиотеки компонентов для одного использования: преобразования временной метки в строку «MM/yy», поскольку она представляла собой дату истечения срока действия дебетовой карты.
Вдохновленный статьей You don’t (may not) need lodash/underscore, я подумал — не можем ли мы просто реализовать форматирование двузначного месяца и двузначного года? Это выглядит просто, верно?

Изучив родную документацию Date, у нас есть getMonth — возвращает 0-индексированное целое число, представляющее месяц года. Первая загвоздка здесь — нужно увеличить значение, чтобы получить человекочитаемый месяц. Что касается года, у нас есть getFullYear, что довольно самоочевидно.

Давайте напишем функцию — не обязательно для повторного использования, но скорее для того, чтобы мы могли легко ее протестировать. И давайте напишем самую глупую, и будем улучшать ее тест за тестом 😉

function expiration(date) {
  return `${date.getMonth() + 1}/${date.getFullYear() % 100}`;
}
Вход в полноэкранный режим Выход из полноэкранного режима

Это будет замечательно работать для чего-то вроде

it('should return 11/22 for nov 2022 expiration', () => {
  expect(expiration(new Date(2022, 10)).toEqual('11/22');
});
Войти в полноэкранный режим Выход из полноэкранного режима

но, конечно же, не сработает для однозначных месяцев

it('should return 03/23 for March 2022 expiration', () => {
  expect(expiration(new Date(2023, 2)).toEqual('03/23');
});

// Expected "3/23" to equal "03/23"
Войти в полноэкранный режим Выход из полноэкранного режима

Мы можем решить эту проблему с помощью забавного трюка: просто заполните заголовок 0 любым результатом, а затем сохраните два последних символа, используя отрицательный аргумент для substr.

function expiration(date) {
  return `0${date.getMonth() + 1}`.substr(-2) + 
         `/${date.getFullYear() % 100}`;
}
Вход в полноэкранный режим Выйти из полноэкранного режима

Кажется, закончили? Чего не хватает?
.
.
.
.
.
.
.
.
.
.
.
.
.
.
Вы поняли. Что если остаток в date.getFullYear() % 100 равен одной цифре?

it('should return 03/00 for March 2100 expiration', () => {
  expect(expiration(new Date(2100, 2)).toEqual('03/00');
});

// Expected "03/0" to equal "03/00"
Вход в полноэкранный режим Выйти из полноэкранного режима

что приводит нас к следующему

function expiration(date) {
  return `0${date.getMonth() + 1}`.substr(-2) +
         "/" +
         `0${date.getFullYear() % 100}`.substr(-2);
}
Войти в полноэкранный режим Выйти из полноэкранного режима

Фух! Теперь осталось выяснить только одно: Что такое 00? 2000 или 2100?

Как далеко вы продвинулись в реализации функций, которые доступны в таких библиотеках, как date-fns, lodash?
Стоит ли это хлопот (и рисков!), учитывая, что tree shaking* делает отличную работу по упаковке оптимального производственного JavaScript?

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

*при условии, что вы используете модулизацию кода и зависимостей (т.е. используете es-модули или другие реализации), и что бандлер способен использовать модулизацию для вырезания неиспользуемого кода.

Оцените статью
devanswers.ru
Добавить комментарий