@alexstukovnikov/oz-time
v1.0.3
Published
Lightweight JavaScript date-time library
Readme
OzTime
JavaScript-библиотека для работы с датой и временем.
OzTime предоставляет неизменяемые объекты времени, фабричные функции создания экземпляров, арифметику по фиксированным и календарным единицам, сравнение, форматирование, работу с часовыми поясами, интервалы и длительности.
- Документация API: AlexStukovnikov.github.io/oz-time
- Пакет npm:
@alexstukovnikov/oz-time
Содержание
- Почему OzTime
- Возможности
- Установка
- Быстрый старт
- Основные сценарии
- Создание экземпляров
- Арифметика
- Сравнение
- Форматирование
- Часовые пояса
- Интервалы и длительности
- Поддерживаемые единицы времени
- Токены форматирования
- FAQ
- Ограничения и особенности
- Лицензия
Почему OzTime
OzTime подойдёт, если нужна небольшая и понятная библиотека без перегруженного API.
Основные идеи:
- время хранится как Unix timestamp в миллисекундах;
- экземпляры
OzTimeнеизменяемы; - часовой пояс и локаль сохраняются как часть объекта;
- арифметика, сравнение и форматирование работают через единый API.
Библиотека хорошо подходит для:
- прикладных JavaScript-проектов;
- учебных и дипломных проектов;
- небольших библиотек и утилит;
- кода, где важна предсказуемость и неизменяемость.
Возможности
- Неизменяемые экземпляры
OzTime - Фабричные функции:
now,fromTimestamp,fromDate,fromISO,fromComponents - Арифметика по времени:
add,subtract - Сравнение:
isSame,isBefore,isAfter,isBetween - Форматирование по шаблону
- Работа с часовыми поясами:
setTimezone,getTimezoneOffset - Интервалы:
Interval,interval - Длительности:
Duration,duration - Календарные утилиты:
isLeapYear,daysInMonth
Установка
npm install @alexstukovnikov/oz-timeБыстрый старт
import { now, fromISO, duration, interval } from '@alexstukovnikov/oz-time';
const current = now('Europe/Moscow', 'ru-RU');
const release = fromISO('2024-05-25T12:00:00Z', 'UTC', 'ru-RU');
const nextWeek = release.add(7, 'day');
const diffHours = nextWeek.diff(release, 'hour');
console.log(current.getTimezone()); // ожидаемый результат: Europe/Moscow
console.log(nextWeek.format('DD.MM.YYYY HH:mm')); // ожидаемый результат: 01.06.2024 12:00
console.log(diffHours); // ожидаемый результат: 168
const range = interval(release, nextWeek);
console.log(range.contains(release)); // ожидаемый результат: true
const oneHour = duration(1, 'hour');
console.log(oneHour.asMinutes()); // ожидаемый результат: 60Цепочка операций
import { fromISO } from '@alexstukovnikov/oz-time';
const result = fromISO('2024-05-25T12:00:00Z', 'UTC', 'ru-RU')
.add(1, 'day')
.add(2, 'hour')
.subtract(30, 'minute')
.setTimezone('Europe/Moscow')
.format('DD.MM.YYYY HH:mm:ss');
console.log(result);Основные сценарии
| Сценарий | Что использовать | Почему |
| ----------------------------------------- | --------------------------------------- | ----------------------------------------------------------------------------------- |
| Нужен текущий момент времени | now() | Самый простой способ получить новый экземпляр OzTime для текущего момента |
| Есть Unix timestamp в миллисекундах | fromTimestamp() | Подходит для работы с временем из API, БД и системных источников |
| Есть нативный Date | fromDate() | Удобно интегрировать библиотеку в существующий JavaScript-код |
| Есть ISO-строка | fromISO() | Подходит для внешних API и сериализованных значений времени |
| Нужно создать дату вручную из компонентов | fromComponents() | Удобно, когда год, месяц, день и время приходят по отдельности |
| Нужно прибавить или вычесть время | add() / subtract() | Возвращают новый экземпляр и не изменяют исходный объект |
| Нужно сравнить два значения | isSame() / isBefore() / isAfter() | Дают читаемый API для логики сравнения |
| Нужно проверить попадание в диапазон | isBetween() | Удобнее, чем писать проверку вручную |
| Нужно получить строковое представление | format() | Форматирование по шаблону с токенами |
| Нужно изменить отображаемый часовой пояс | setTimezone() | Меняет timezone у нового экземпляра, не меняя абсолютный момент времени |
| Нужно узнать смещение относительно UTC | getTimezoneOffset() | Полезно для отображения, отладки и расчётов |
| Нужно описать диапазон времени | Interval / interval() | Подходит для проверки попадания, пересечений и длительности интервала |
| Нужно описать фиксированную длительность | Duration / duration() | Удобно для преобразования между миллисекундами, секундами, минутами, часами и днями |
| Нужно проверить високосный год | isLeapYear() | Простая календарная утилита |
| Нужно узнать число дней в месяце | daysInMonth() | Удобно для валидации и генерации дат |
Создание экземпляров
import { now, fromTimestamp, fromDate, fromISO, fromComponents } from '@alexstukovnikov/oz-time';
const a = now('Europe/Moscow', 'ru-RU');
const b = fromTimestamp(1716638400000, 'UTC', 'ru-RU');
const c = fromDate(new Date('2024-05-25T12:00:00Z'), 'UTC', 'ru-RU');
const d = fromISO('2024-05-25T12:00:00Z', 'UTC', 'ru-RU');
const e = fromComponents(2024, 5, 25, 12, 0, 0, 0, 'UTC', 'ru-RU');now()— создаёт экземплярOzTimeдля текущего момента времени.fromTimestamp()— создаёт экземпляр из Unix timestamp в миллисекундах.fromDate()— создаёт экземпляр из объектаDate.fromISO()— создаёт экземпляр из ISO-строки.fromComponents()— создаёт экземпляр из отдельных компонентов даты и времени.
Арифметика
Все арифметические операции возвращают новый экземпляр OzTime и не изменяют исходный объект.
Добавление и вычитание
import { fromISO } from '@alexstukovnikov/oz-time';
const time = fromISO('2024-05-25T12:00:00Z');
console.log(time.add(1, 'day').toISOString()); // ожидаемый результат: 2024-05-26T12:00:00.000Z
console.log(time.subtract(2, 'hour').toISOString()); // ожидаемый результат: 2024-05-25T10:00:00.000ZРазница между датами
import { fromISO } from '@alexstukovnikov/oz-time';
const start = fromISO('2024-05-25T12:00:00Z');
const end = fromISO('2024-05-25T15:00:00Z');
console.log(end.diff(start, 'hour')); // ожидаемый результат: 3Календарная арифметика
import { fromISO } from '@alexstukovnikov/oz-time';
const date = fromISO('2024-01-31T00:00:00Z');
const result = date.add(1, 'month');
console.log(result.toISOString()); // ожидаемый результат: 2024-02-29T00:00:00.000ZСравнение
import { fromISO } from '@alexstukovnikov/oz-time';
const a = fromISO('2024-05-25T12:00:00.100Z');
const b = fromISO('2024-05-25T12:00:00.900Z');
const c = fromISO('2024-05-26T12:00:00Z');
console.log(a.isSame(b, 'second')); // ожидаемый результат: true
console.log(a.isBefore(c)); // ожидаемый результат: true
console.log(c.isAfter(a)); // ожидаемый результат: true
console.log(a.isBetween(a.subtract(1, 'day'), c)); // ожидаемый результат: trueФорматирование
Функция format() и метод OzTime#format() поддерживают шаблоны форматирования.
import { fromISO } from '@alexstukovnikov/oz-time';
const time = fromISO('2024-05-25T12:00:00Z', 'UTC', 'ru-RU');
console.log(time.format('DD.MM.YYYY HH:mm')); // ожидаемый результат: 25.05.2024 12:00
console.log(time.format('dddd, D MMMM YYYY', 'ru-RU')); // пример: суббота, 25 мая 2024Часовые пояса
OzTime хранит абсолютное время как timestamp, а часовой пояс используется как метаданные для отображения и форматирования.
Смена часового пояса
import { fromISO } from '@alexstukovnikov/oz-time';
const time = fromISO('2024-05-25T12:00:00Z', 'UTC', 'ru-RU');
const moscow = time.setTimezone('Europe/Moscow');
console.log(moscow.getTimezone()); // ожидаемый результат: Europe/MoscowСмещение относительно UTC
import { fromISO } from '@alexstukovnikov/oz-time';
const time = fromISO('2024-05-25T12:00:00Z', 'Europe/Moscow', 'ru-RU');
console.log(time.getTimezoneOffset()); // ожидаемый результат: 180Интервалы и длительности
Интервалы
Интервал представляет диапазон между двумя экземплярами OzTime, включая границы.
import { interval, fromISO } from '@alexstukovnikov/oz-time';
const start = fromISO('2024-05-25T10:00:00Z');
const end = fromISO('2024-05-25T12:00:00Z');
const range = interval(start, end);
console.log(range.contains(fromISO('2024-05-25T11:00:00Z'))); // ожидаемый результат: true
console.log(range.duration('hour')); // ожидаемый результат: 2Пересечение интервалов
import { Interval, fromISO } from '@alexstukovnikov/oz-time';
const a = new Interval(fromISO('2024-05-25T10:00:00Z'), fromISO('2024-05-25T12:00:00Z'));
const b = new Interval(fromISO('2024-05-25T11:00:00Z'), fromISO('2024-05-25T13:00:00Z'));
console.log(a.overlaps(b)); // ожидаемый результат: trueДлительности
Duration используется для работы с фиксированными единицами времени.
import { duration } from '@alexstukovnikov/oz-time';
const twoHours = duration(2, 'hour');
console.log(twoHours.asMilliseconds()); // ожидаемый результат: 7200000
console.log(twoHours.asMinutes()); // ожидаемый результат: 120
console.log(twoHours.asHours()); // ожидаемый результат: 2Сложение длительностей
import { duration } from '@alexstukovnikov/oz-time';
const a = duration(30, 'minute');
const b = duration(45, 'minute');
console.log(a.add(b).asMinutes()); // ожидаемый результат: 75Поддерживаемые единицы времени
Поддерживаются канонические имена и алиасы.
| Единица | Каноническое имя | Алиасы |
| ------------ | ---------------- | -------------------- |
| Миллисекунда | millisecond | milliseconds, ms |
| Секунда | second | seconds, s |
| Минута | minute | minutes, m |
| Час | hour | hours, h |
| День | day | days, d |
| Месяц | month | months |
| Год | year | years, y |
Фиксированные единицы:
millisecondsecondminutehourday
Календарные единицы:
monthyear
Токены форматирования
| Токен | Описание | Пример |
| ------ | ---------------------------------- | ------------- |
| YYYY | Год из 4 цифр | 2024 |
| YY | Короткий год | 24 |
| MMMM | Полное название месяца | май / May |
| MMM | Короткое название месяца | мая / May |
| MM | Месяц с ведущим нулём | 05 |
| M | Месяц без ведущего нуля | 5 |
| dddd | Полное название дня недели | суббота |
| ddd | Короткое название дня недели | сб |
| DD | День месяца с ведущим нулём | 25 |
| D | День месяца без ведущего нуля | 25 |
| HH | Часы в 24-часовом формате | 09, 18 |
| H | Часы в 24-часовом формате без нуля | 9, 18 |
| hh | Часы в 12-часовом формате | 01, 12 |
| h | Часы в 12-часовом формате без нуля | 1, 12 |
| mm | Минуты | 07 |
| ss | Секунды | 05 |
| SSS | Миллисекунды | 123 |
| A | AM/PM | AM, PM |
FAQ
Чем fromISO() отличается от fromTimestamp()?
fromISO() принимает строку в формате ISO 8601 и сначала парсит её, а fromTimestamp() принимает уже готовое число миллисекунд. Если данные приходят из JSON API как строка, чаще удобнее fromISO(). Если уже есть timestamp из базы, системы или вычислений, лучше использовать fromTimestamp().
Меняет ли setTimezone() сам момент времени?
Нет. setTimezone() не меняет абсолютный момент времени. Он возвращает новый экземпляр с тем же timestamp, но с другим часовым поясом для форматирования и вычисления смещения.
Изменяют ли методы add() и subtract() текущий объект?
Нет. OzTime построен как неизменяемый объект. Все операции возвращают новый экземпляр, а исходный объект остаётся без изменений.
Почему Duration не поддерживает month и year?
Потому что Duration предназначен только для фиксированных единиц времени, которые можно точно перевести в миллисекунды. Месяцы и годы имеют переменную длину, поэтому для них используется календарная арифметика через OzTime#add() и OzTime#diff().
Почему diff(..., 'month') и diff(..., 'year') работают не так, как разница в миллисекундах?
Потому что для месяцев и лет применяется календарная логика, а не деление на фиксированное число миллисекунд. Это позволяет корректнее учитывать разную длину месяцев и переходы между датами.
Что лучше использовать: метод экземпляра или функцию модуля?
Если уже есть экземпляр OzTime, обычно удобнее использовать методы экземпляра: time.add(...), time.format(...), time.isBefore(...). Если нужен функциональный стиль или работаешь с импортированными утилитами напрямую, можно использовать функции модулей.
В каком часовом поясе хранится время внутри OzTime?
Внутри хранится Unix timestamp в миллисекундах. Это абсолютное значение времени. Часовой пояс хранится отдельно как метаданные экземпляра.
Можно ли использовать библиотеку без locale и timezone?
Да. По умолчанию используются:
timezone = 'UTC'locale = 'en-US'
Когда использовать Interval, а когда Duration?
Используй Interval, когда есть начало и конец диапазона. Используй Duration, когда нужна именно фиксированная длина времени, например 2 часа, 30 минут или 7 дней.
Ограничения и особенности
- Внутреннее значение времени хранится как Unix timestamp в миллисекундах
- Часовой пояс не меняет абсолютный момент времени, а влияет на форматирование и вычисление смещения
- Методы
add,subtract,setTimezoneи другие операции не изменяют текущий экземпляр, а возвращают новый Durationподдерживает только фиксированные единицы времени- Календарная арифметика через
monthиyearучитывает реальную длину месяцев - Разница в
monthиyearсчитается календарно, а не через точное число миллисекунд - Поддержка часовых поясов зависит от
Intlи доступных IANA time zone в среде выполнения
Лицензия
ISC
