Изготовление сайтов в Донецке, ДНР. Управление датами и временем в JavaScript с помощью date-fns

Работать с датами в JavaScript очень сложно. Собственные методы работы с датами часто многословны и иногда непоследовательны, что также делает их подверженными ошибкам. Но хорошие новости не за горами. Существует несколько библиотек, которые избавляют от устаревших манипуляций. Эти библиотеки для JavaScript — то же, что jQuery для родного DOM API.

Позвольте привести пример. Это принятый ответ на вопрос о переполнении стека с вопросом, как получить последний день месяца:

var t = new Date () ;

alert (new Date (t.getFullYear (), t.getMonth () + 1, 0, 23, 59, 59));

Конечно, это работает, но не сразу понятно, что представляют цифры после getMonth. Теперь сравните это со значительно более читаемым:

const today = new Date () ;

console.log (lastDayOfMonth (today));

Этот lastDayOfMonthметод предоставляется date-fns, самопровозглашенным всеобъемлющим набором инструментов для управления датами JavaScript в браузере и Node.js.

В этой статье я собираюсь показать вам, как начать работу с date-fns. После прочтения вы сможете добавить его в свои проекты и воспользоваться многочисленными вспомогательными методами для удобного управления датами. Это сделает код похожим t.getMonth () + 1, 0, 23, 59, 59на прошлое.

Итак, почему бы просто не использовать Moment.js?

Moment.js — фантастическая библиотека для работы с датами в JavaScript — она имеет множество замечательных функций и предлагает целый ряд полезных утилит. Это, однако, не без его критиков.

Многие люди ссылаются на тот факт, что объекты Moment изменяемы (например, такие операции, как add, или subtractизменяют исходный объект Moment), как на то, что это сбивает с толку разработчиков и является источником ошибок.

Он также подвергся критике из-за своего большого размера. Moment плохо сочетается с современными алгоритмами «дрожания дерева», и если вам требуется интернационализация или поддержка часовых поясов, вы можете быстро найти довольно большой пакет JavaScript.

Это зашло так далеко, что инструменты разработчика Chrome теперь подчеркивают тот факт, что использование Moment может привести к снижению производительности.

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

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

Это делает date-fns одной из лучших альтернатив Moment.js.

Установка

Начиная со второй версии библиотеки, единственный способ установить date-fns — это пакет npm.

npm install date-fns

Или через пряжу:

yarn add date-fns

Вы можете использовать date-fns как с системой модулей CommonJS, так и с модулями ES:

// CommonJS

const { lastDayOfMonth } = require (‘date-fns’) ;

или:

// ES Modules

import { lastDayOfMonth } from ‘date-fns’;

К сожалению, в настоящее время нет доступной CDN-версииdate-fns. Его удаление и возможное восстановление обсуждается в этом выпуске GitHub. Но это не значит, что вы не можете использовать его в браузере, просто вам нужно будет ввести шаг объединения в свой рабочий процесс.

Давайте посмотрим, как это сделать сейчас.

Как связать date-fns для использования в браузере

Я предполагаю, что на вашем компьютере установлены Node и npm. Если нет, обратитесь к нашему руководству по установке Node.

Далее устанавливаем Parcel. Это упаковщик (похожий на Webpack), который позволит вам упаковать ваш JavaScript и обслуживать его в браузере.

npm install -g parcel-bundler

Далее создайте новый проект с package.jsonфайлом.

mkdir datefns

cd datefns

npm init -y

Установите библиотеку date-fns, как указано выше:

npm install date-fns

Примечание. Это создаст date-fnsпапку внутри node_modulesпапки в каталоге вашего проекта. Если вы заглянете внутрь date-fnsпапки, вы увидите гораздо больше папок и файлов. Не волнуйтесь, мы не будем отправлять большую часть этого клиенту. Мы выберем только те функции, которые нам нужны, а затем прогоним все через участок, чтобы сделать минимизированный и древовидный пакет.

Теперь создайте два файла index.htmlи index.js.

<! DOCTYPE html>

 

 

 

 

 

 

 

 

import { lastDayOfMonth } from ‘date-fns’;

const today = new Date () ;

console.log (lastDayOfMonth (today));

Запустите встроенный сервер разработки посылки:

parcel index.html

И перейдите по адресу http: //localhost:1234. Вы не увидите ничего отображаемого на странице, но если вы откроете консоль браузера. вы должны, чтобы он зарегистрировал последний день текущего месяца.

Когда дело доходит до развертывания, вы можете запустить:

parcel build index.js —experimental-scope-hoisting

чтобы Parcel выводил в папку минимизированный и древовидный пакет dist.

Базовое использование Date-fns

Теперь, когда мы готовы, давайте посмотрим, что может сделать date-fns.

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

Измените HTML-код с нашей страницы примера выше, чтобы он выглядел следующим образом:

 

 

The date today is

 

Мы index.jsхотим импортировать formatфункцию, которой мы можем передать сегодняшнюю дату и строку формата. Затем мы хотим вывести результат на страницу.

import { format } from ‘date-fns’;

const today = new Date () ;

const formattedDate = format (today, ‘dd.MM.yyyy’) ;

document.querySelector (‘h1 > span’).textContent = formattedDate;

Конечно, мы не ограничены dd.MM.yyyyформатом, давайте попробуем что-то другое:

const formattedDate = format (today, ‘PPPP’) ;

Это отформатирует вывод следующим образом: Wednesday, September 16th, 2020. Вы можете найти полный список параметров форматирования в документации.

Изменить язык

Если у вас есть веб-сайт на нескольких языках, date-fns упрощает интернационализацию времени и даты. Поприветствуем наших немецких гостей:

Heute ist

И в файле JavaScript мы можем импортировать немецкую локаль и передать ее formatфункции:

import { format } from ‘date-fns’;

import { de } from ‘date-fns/locale’;

const today = new Date () ;

const formattedDate = format (today, ‘PPPP’, { locale: de }) ;

document.querySelector (‘h1 > span’).textContent = formattedDate;

Это выведет что-то вроде строк: Heute ist Mittwoch, 16. September 2020.

Может показаться сложным требовать и передавать локали в качестве параметров, но в отличие от Moment.js, который раздувает вашу сборку всеми локалями по умолчанию, date-fns заставляет разработчиков вручную запрашивать локали по мере необходимости.

Вы можете просмотреть список доступных локалей, заглянув в node_modules/date-fns/localeпапку в вашем проекте.

Неизменность, чистота и простота

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

Позвольте мне продемонстрировать это на примере Moment.js. Как упоминалось ранее, даты в Moment изменяемы, что может привести к неожиданному поведению.

const moment = require (‘moment’) ;

const now = new Date () ;

const mNow = moment (now) ;

mNow.add (‘day’, 3) ;

console.log (mNow.toDate ());

mNow.add (3, ‘day’) ;

console.log (mNow.toDate ());

// 2020-09-19T10:08:36.999Z

// 2020-09-22T10:08:36.999Z

Здесь есть несколько вещей, на которые следует обратить внимание. Функция Moment addне привередлива к порядку, в котором она принимает свои аргументы (хотя первый метод теперь выдает предупреждение об устаревании). Но еще больше сбивает с толку то, что если вы вызываете addнесколько раз подряд, вы не получите тот же результат, потому что объекты Moment изменяемы:

mNow.add (3, ‘day’) ; // add 3 days

mNow.add (3, ‘day’) ; // adds 3 **more** days

Теперь сравните это с date-fns, которая хранит аргументы в одном порядке и всегда возвращает один и тот же результат, возвращая новый Dateобъект для каждого вызова.

import { addDays } from ‘date-fns’;

const today = new Date () ;

const threeDaysTime = addDays (3, today) ;

const sixDaysTime = addDays (threeDaysTime, 3) ;

console.log (today) ; // Wed Sep 16 2020 12:11:55 GMT+0200

console.log (threeDaysTime) ; // Sat Sep 19 2020 12:12:58 GMT+0200

console.log (sixDaysTime) ; // Invalid Date

Также обратите внимание на то, что имя метода стало более выразительным (addDaysвместо простого add), сохраняя согласованность и наличие одного метода для выполнения одной и только одной операции.

Сравнение дат

Если вы посмотрите на список сообщений на канале JavaScript SitePoint, вы увидите, что некоторые из них указаны как опубликованные на определенную дату, тогда как другие указаны как опубликованные X дней назад. Это может занять некоторое время, если вы попытаетесь реализовать это в ванильном JavaScript, но с date-fns это проще простого — просто используйте метод formatDistance.

Давайте сравним две разные даты.

import { formatDistance } from ‘date-fns’;

const startDate = new Date (2020, 8, 16) ; // (Sep 16 2020)

const endDate = new Date (2020, 11, 25) ; // (Dec 25 2020)

const distanceInWords = formatDistance (startDate, endDate) ;

console.log (`It is ${distanceInWords} until Christmas`) ;

// It is 3 months until Christmas

Обратите внимание, что при работе с JavaScript месяцы отсчитываются от нуля (например, 11-й месяц = ​​декабрь), а дни начинаются с единицы. Это сбивает меня с толку снова и снова.

Работа с коллекциями дат

Date-fns имеет несколько очень удобных вспомогательных методов, которые вы можете использовать для управления коллекциями дат самыми разными способами.

Заказ коллекции фиников

В следующем примере compareAsc используется для сортировки дат по возрастанию. Для этого он возвращает 1, если первая дата предшествует второй, -1, если первая дата предшествует второй, или 0, если даты равны.

import { compareAsc } from ‘date-fns’;

const date1 = new Date ('2005-01-01') ;

const date2 = new Date ('2010-01-01') ;

const date3 = new Date ('2015-01-01') ;

const arr = [date3, date1, date2];

const sortedDates = arr.sort (compareAsc) ;

// [ 2005-01-01, 2010-01-01, 2015-01-01 ]

Как видите, даты расположены в порядке возрастания.

Метод аналога compareAsc— compareDesc.

import { compareDesc } from ‘date-fns’;

...

const sortedDates = arr.sort (compareDesc) ;

// [ 2015-01-01, 2010-01-01, 2005-01-01 ]

Генерация дней между двумя датами

Чтобы сгенерировать дни между двумя датами, вы можете использовать метод addDays, который мы встречали ранее, а также вспомогательную функцию eachDayOfInterval, которая возвращает массив дат в указанном диапазоне.

import { addDays, eachDayOfInterval } from ‘date-fns’;

const today = new Date () ;

const aWeekFromNow = addDays (today, 7) ;

const thisWeek = eachDayOfInterval (

{ start: today, end: aWeekFromNow },

) ;

console.log (thisWeek) ;

/*

[

Wed Sep 16 2020 00:00:00 GMT+0200 (Central European Summer Time),

Thu Sep 17 2020 00:00:00 GMT+0200 (Central European Summer Time),

Fri Sep 18 2020 00:00:00 GMT+0200 (Central European Summer Time),

Sat Sep 19 2020 00:00:00 GMT+0200 (Central European Summer Time),

Sun Sep 20 2020 00:00:00 GMT+0200 (Central European Summer Time),

Mon Sep 21 2020 00:00:00 GMT+0200 (Central European Summer Time),

Tue Sep 22 2020 00:00:00 GMT+0200 (Central European Summer Time),

Wed Sep 23 2020 00:00:00 GMT+0200 (Central European Summer Time)

]

*/

Поиск ближайшей даты

Поиск ближайшей даты к определенной дате в массиве дат можно выполнить с помощью метода NearbyTo. Этот фрагмент кода следует из предыдущего примера:

import { addDays, eachDayOfInterval, closestTo } from ‘date-fns’;

...

const christmas = new Date (2020, 11, 25) ;

const closestToChristmasDate = closestTo (christmas, thisWeek) ;

console.log (closestToChristmasDate) ;

// Wed Sep 23 2020 00:00:00 GMT+0200 (Central European Summer Time)

Также есть метод closeIndexTo, если вместо этого вы хотите получить индекс массива.

Проверка даты

Последний помощник, на который я хочу обратить внимание, — это метод isValid, который, как следует из названия, проверяет, действительна ли заданная дата.

Однако из-за того, как JavaScript работает с датами, есть пара подводных камней, о которых следует знать:

import { isValid } from ‘date-fns’;

const invalidDate = new Date ('2020, 02, 30') ;

console.log (isValid (invalidDate));

// true, lol, wut?

Простите, если вы думаете, что приведенный выше фрагмент должен выводить false, поскольку 30 февраля 2020 года явно недопустимая дата. Чтобы понять, что происходит, введите new Date ('2020, 02, 30') в консоли браузера. Вы увидите Sun Mar 01 2020, что к вам вернется — JavaScript взял лишний день с конца февраля и превратил его в 1 марта (что, конечно, является допустимой датой).

Чтобы обойти это, мы можем проанализировать дату перед проверкой ее достоверности:

import { isValid, parse } from ‘date-fns’;

const validDate = parse ('29.02.2020', ‘dd.MM.yyyy’, new Date ());

const invalidDate = parse ('30.02.2020', ‘dd.MM.yyyy’, new Date ());

console.log (validDate) ;

// Sat Feb 29 2020 00:00:00 GMT+0100 (Central European Standard Time)

console.log (invalidDate) ;

// Invalid Date

console.log (isValid (validDate));

// true

console.log (isValid (invalidDate));

// false

Это можно легко преобразовать в небольшой вспомогательный метод, полезный, например, для проверки пользовательского ввода в формах.

Часовые пояса

Одним из недостатков date-fns является то, что в настоящее время у него нет вспомогательных функций часового пояса, как у Moment.js, а вместо этого он возвращает локальный часовой пояс, в котором выполняется код.

Этот ответ Stack Overflow дает некоторое представление о том, как нативные Dateобъекты на самом деле не хранят данные «реального часового пояса». В этой ветке вы заметите, что они упоминают метод установки часовых поясов изначально в JavaScript. Это не комплексное решение, но оно работает для многих сценариев, требующих только преобразования вывода (из UTC или местного времени в определенный часовой пояс).

new Date ().toLocaleString («en-US», {timeZone: «America/New_York»}) ;

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

Однако в npm доступен пакет (на основе неслитного запроса на вытягивание для date-fns), который добавляет поддержку часовых поясов для date-fns v2.0.0 с использованием Intl API. Со 140 тысячами загрузок в неделю он кажется популярным, но на момент написания статьи он не обновлялся уже несколько месяцев.

Тем не менее, вот как вы можете его использовать:

npm i date-fns-tz

import { format, utcToZonedTime } from ‘date-fns-tz’;

const today = new Date () ; // Wed Sep 16 2020 13:25:16

const timeZone = ‘Australia/Brisbane’; // Let’s see what time it is Down Under

const timeInBrisbane = utcToZonedTime (today, timeZone) ;

console.log (`

Time in Munich: ${format (today, ‘yyyy-MM-dd HH: mm: ss’) }

Time in Brisbane: ${format (timeInBrisbane, ‘yyyy-MM-dd HH: mm: ss’) }

`) ;

// Time in Munich: 2020-09-16 13:26:48

// Time in Brisbane: 2020-09-16 21:26:48

Вывод

Date-fns — это отличная небольшая библиотека, которая предоставляет целую кучу вспомогательных методов для работы с датами и временем в JavaScript. Он находится в активной разработке, и теперь, когда Moment.js переведен в режим обслуживания, он станет отличной заменой Moment.js.

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

Делитесь нашими материалами с друзьями!

 

 

Заказать разработку сайта