Объект Date встроен в JavaScript с первых версий языка и
долгое время оставался единственным инструментом для работы с датой и
временем. Несмотря на широкое распространение, API Date
имеет ряд архитектурных недостатков:
Пример создания даты:
const date = new Date();
console.log(date);
Создание конкретной даты:
const date = new Date(2025, 0, 15);
Результат:
2025-01-14T18:00:00.000Z
Месяцы в Date начинаются с нуля:
0 -> январь
1 -> февраль
11 -> декабрь
Подобное поведение считается одной из наиболее частых причин ошибок.
DateОбъекты Date являются mutable-типами.
const date = new Date();
date.setFullYear(2030);
console.log(date);
Изменение происходит непосредственно внутри объекта. Это усложняет:
В js-joda все объекты immutable.
const { LocalDate } = require('@js-joda/core');
const date = LocalDate.now();
const changed = date.plusYears(5);
console.log(date);
console.log(changed);
Исходный объект не изменяется.
Date и js-jodaDateDate представляет собой timestamp — количество
миллисекунд с эпохи Unix.
Внутри объект хранит:
milliseconds since 1970-01-01T00:00:00Z
Все операции строятся вокруг этой модели.
Даже если используется локальное время, внутреннее представление остаётся UTC.
js-jodajs-joda разделяет временные сущности на независимые
типы:
| Тип | Назначение |
|---|---|
LocalDate |
дата без времени |
LocalTime |
время без даты |
LocalDateTime |
дата и время без timezone |
ZonedDateTime |
дата и время с timezone |
Instant |
момент времени UTC |
Period |
календарный период |
Duration |
временная длительность |
Такое разделение исключает множество логических ошибок.
Dateconst date = new Date();
console.log(date.getFullYear());
console.log(date.getMonth());
console.log(date.getDate());
Недостатки:
js-jodaconst { LocalDate } = require('@js-joda/core');
const date = LocalDate.now();
console.log(date.year());
console.log(date.monthValue());
console.log(date.dayOfMonth());
API ближе к предметной области и легче читается.
Dateconst now = new Date();
console.log(now.getHours());
console.log(now.getMinutes());
console.log(now.getSeconds());
Вся информация хранится в одном объекте.
js-jodaconst { LocalTime } = require('@js-joda/core');
const time = LocalTime.now();
console.log(time.hour());
console.log(time.minute());
console.log(time.second());
Время отделено от даты.
Это особенно важно для:
Dateconst date = new Date('2025-01-01');
console.log(date);
Результат зависит от timezone системы.
Одинаковый код может вести себя по-разному:
js-joda и timezoneДля timezone используется пакет:
npm install @js-joda/timezone
Пример:
const {
ZonedDateTime,
ZoneId
} = require('@js-joda/core');
require('@js-joda/timezone');
const zoned = ZonedDateTime.now(
ZoneId.of('Europe/Moscow')
);
console.log(zoned.toString());
Timezone становится частью модели данных.
Dateconst date = new Date();
console.log(date.getUTCFullYear());
console.log(date.getUTCHours());
Для UTC существует отдельный набор методов.
API быстро становится громоздким:
getHours
getUTCHours
setHours
setUTCHours
js-jodaconst { Instant } = require('@js-joda/core');
const instant = Instant.now();
console.log(instant.toString());
Instant всегда представляет UTC-время.
Dateconst date = new Date();
date.setDate(date.getDate() + 5);
console.log(date);
Проблемы:
js-jodaconst { LocalDate } = require('@js-joda/core');
const date = LocalDate.now();
const result = date
.plusDays(5)
.minusMonths(1)
.plusYears(2);
console.log(result);
Код выглядит декларативно.
Dateconst a = new Date('2025-01-01');
const b = new Date('2025-01-10');
console.log(a < b);
Сравнение основано на timestamp.
js-jodaconst { LocalDate } = require('@js-joda/core');
const a = LocalDate.parse('2025-01-01');
const b = LocalDate.parse('2025-01-10');
console.log(a.isBefore(b));
console.log(a.isAfter(b));
console.log(a.equals(b));
Методы выражают намерение напрямую.
Dateconst date = new Date();
console.log(date.toISOString());
console.log(date.toLocaleDateString());
Проблемы:
js-jodaДля форматирования используется:
npm install @js-joda/locale
Пример:
const {
LocalDate,
DateTimeFormatter
} = require('@js-joda/core');
const date = LocalDate.now();
const formatter =
DateTimeFormatter.ofPattern('dd.MM.yyyy');
console.log(date.format(formatter));
Dateconst date = new Date('2025-01-15');
Поведение строкового парсинга частично зависит от реализации JavaScript-движка.
js-jodaconst { LocalDate } = require('@js-joda/core');
const date = LocalDate.parse('2025-01-15');
console.log(date);
Стандартизированное поведение.
Moment.js долгое время являлся стандартом де-факто для работы с датами в JavaScript.
Однако библиотека имеет серьёзные ограничения:
Команда Moment.js официально перевела библиотеку в режим maintenance.
const moment = require('moment');
const date = moment();
date.add(1, 'day');
console.log(date);
Объект изменяется.
js-jodaconst { LocalDate } = require('@js-joda/core');
const date = LocalDate.now();
const next = date.plusDays(1);
console.log(date);
console.log(next);
| Библиотека | Размер |
|---|---|
| Moment.js | большой |
| js-joda | меньше |
| date-fns | очень маленький |
| Day.js | маленький |
js-joda хорошо подходит для production-среды с высокими
требованиями к производительности.
Moment работает вокруг одного универсального объекта:
moment()
Он содержит:
js-joda использует строгую типовую модель.
Пример:
LocalDate
LocalTime
LocalDateTime
ZonedDateTime
Instant
Подход заимствован из Java API java.time.
date-fns использует набор независимых функций.
Пример:
import { addDays } from 'date-fns';
const result = addDays(new Date(), 5);
Преимущества:
Несмотря на удобство, date-fns продолжает использовать
нативный Date.
Следовательно сохраняются проблемы:
import {
addDays,
subMonths
} from 'date-fns';
const result =
subMonths(
addDays(new Date(), 5),
1
);
const result = LocalDate.now()
.plusDays(5)
.minusMonths(1);
Методы читаются естественнее.
Day.js создавался как компактная альтернатива Moment.js.
API намеренно повторяет Moment.
const dayjs = require('dayjs');
const result = dayjs()
.add(1, 'day')
.subtract(2, 'month');
console.log(result.format());
| Характеристика | Day.js | js-joda |
|---|---|---|
| Immutable | да | да |
| Размер | очень маленький | средний |
| Типовая модель | нет | да |
| Timezone API | плагины | полноценная модель |
| Java Time API | нет | да |
Luxon создан автором Moment.js как современная альтернатива.
Luxon уже использует immutable-модель.
const { DateTime } = require('luxon');
const now = DateTime.now();
console.log(now.toISO());
Преимущества:
Недостатки:
Преимущества:
DateНативная реализация обычно очень быстрая.
Но сложность логики вокруг timezone часто приводит к ошибкам.
Одна из самых тяжёлых библиотек.
Особенно при:
Особенности производительности:
Date в большинстве
операций.Библиотека хорошо подходит для:
Datenew Date('2025-01-01')
Результат может интерпретироваться:
Поведение зависит от среды выполнения.
js-jodaLocalDate.parse('2025-01-01')
Всегда создаётся именно календарная дата без timezone.
DateDate позволяет смешивать:
Всё хранится в одном объекте.
js-jodaТипы разделены:
LocalDate
LocalTime
LocalDateTime
Instant
ZonedDateTime
Это уменьшает количество логических ошибок на этапе разработки.
js-joda особенно востребован в системах, где критична
точность работы со временем:
Главные причины:
js-jodajs-joda подходит в случаях:
java.time;DateНативного Date обычно хватает для:
Подходит для:
Подходит для:
Подходит для:
Лучший выбор для: