{"_id":"@alexstukovnikov/oz-time","_rev":"4-0de54659b937f8c2f805ab723102e070","name":"@alexstukovnikov/oz-time","dist-tags":{"latest":"1.0.3"},"versions":{"1.0.0":{"name":"@alexstukovnikov/oz-time","version":"1.0.0","keywords":["date","time","datetime"],"author":"","license":"ISC","_id":"@alexstukovnikov/oz-time@1.0.0","maintainers":[{"name":"alexstukovnikov","email":"aleksalexxxey@gmail.com"}],"homepage":"https://github.com/AlexStukovnikov/oz-time#readme","bugs":{"url":"https://github.com/AlexStukovnikov/oz-time/issues"},"dist":{"shasum":"fdd9e67962da6630da271d05a96943a7d05d8e0f","tarball":"https://registry.npmjs.org/@alexstukovnikov/oz-time/-/oz-time-1.0.0.tgz","fileCount":4,"integrity":"sha512-RiSHPCjX5TzwfDZYFrC30jZGM3RV1w6cCeXT+hQfAus5BZeLEzLuceevZ35H12HFyTj6K09oJD+RIGhIlzNv0w==","signatures":[{"sig":"MEUCIHf7fx/DoK8316zeUh9jlxUhMgGULVoXhMzb3B+ig6VuAiEA6NfFpFW3keYjI4vmuLUhPUU2mWuoHQI1EUC/ls0c3NU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":50911},"main":"./dist/oz-time.cjs","type":"module","module":"./dist/oz-time.esm.js","exports":{".":{"import":"./dist/oz-time.esm.js","require":"./dist/oz-time.cjs"}},"gitHead":"d61c68fb03c594d9e863d799da8e3ad724676235","scripts":{"dev":"vite","docs":"jsdoc -c jsdoc.json","test":"vitest","build":"vite build","test:run":"vitest run","docs:build":"npm run docs:clean && npm run docs","docs:clean":"rimraf docs","test:coverage":"vitest run --coverage","prepublishOnly":"npm run build"},"_npmUser":{"name":"alexstukovnikov","email":"aleksalexxxey@gmail.com"},"repository":{"url":"git+https://github.com/AlexStukovnikov/oz-time.git","type":"git"},"_npmVersion":"10.2.5","description":"Lightweight JavaScript date-time library","directories":{},"sideEffects":false,"_nodeVersion":"24.14.1","_hasShrinkwrap":false,"devDependencies":{"vite":"^8.0.14","jsdoc":"^4.0.5","vitest":"^4.1.7","docdash":"^2.0.2","@vitest/ui":"^4.1.7","@vitest/coverage-v8":"^4.1.7"},"_npmOperationalInternal":{"tmp":"tmp/oz-time_1.0.0_1779793368864_0.48327026744146284","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@alexstukovnikov/oz-time","version":"1.0.1","keywords":["date","time","datetime"],"author":"","license":"ISC","_id":"@alexstukovnikov/oz-time@1.0.1","maintainers":[{"name":"alexstukovnikov","email":"aleksalexxxey@gmail.com"}],"homepage":"https://github.com/AlexStukovnikov/oz-time#readme","bugs":{"url":"https://github.com/AlexStukovnikov/oz-time/issues"},"dist":{"shasum":"1efcbc63c990cd691fdf2b25fadcc7cc014fb7cf","tarball":"https://registry.npmjs.org/@alexstukovnikov/oz-time/-/oz-time-1.0.1.tgz","fileCount":13,"integrity":"sha512-JPSmuRc23WraiPgy6HGj9JxeTwWt7baIpe98upATCvdlBm8pza7ZIr4rbcXpBRpFFSJM7xXvwla3A4G55ZwreQ==","signatures":[{"sig":"MEUCIQD7Vf826MV5bxvMa8cAmnDVyC8DthUzS+W0mergIs6a1wIgLo55H4y1LCoBgA6RW2FJ2FMbwQHIb3HIkIpDfXpoZIo=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":102096},"main":"./src/index.js","type":"module","exports":{".":"./src/index.js"},"gitHead":"cb53548db7ccf173490bc53d1cb7cf60825a1aab","scripts":{"dev":"vite","docs":"jsdoc -c jsdoc.json","test":"vitest","build":"vite build","test:run":"vitest run","docs:build":"npm run docs:clean && npm run docs","docs:clean":"rimraf docs","test:coverage":"vitest run --coverage","prepublishOnly":"npm run build"},"_npmUser":{"name":"alexstukovnikov","email":"aleksalexxxey@gmail.com"},"repository":{"url":"git+https://github.com/AlexStukovnikov/oz-time.git","type":"git"},"_npmVersion":"10.2.5","description":"Lightweight JavaScript date-time library","directories":{},"sideEffects":false,"_nodeVersion":"24.14.1","_hasShrinkwrap":false,"devDependencies":{"vite":"^8.0.14","jsdoc":"^4.0.5","vitest":"^4.1.7","docdash":"^2.0.2","@vitest/ui":"^4.1.7","@vitest/coverage-v8":"^4.1.7"},"_npmOperationalInternal":{"tmp":"tmp/oz-time_1.0.1_1779804253513_0.5325099305480343","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"@alexstukovnikov/oz-time","version":"1.0.2","keywords":["date","time","datetime"],"author":"","license":"ISC","_id":"@alexstukovnikov/oz-time@1.0.2","maintainers":[{"name":"alexstukovnikov","email":"aleksalexxxey@gmail.com"}],"homepage":"https://github.com/AlexStukovnikov/oz-time#readme","bugs":{"url":"https://github.com/AlexStukovnikov/oz-time/issues"},"dist":{"shasum":"ee83b7652426a8a1496d0dfdc505e590700529d2","tarball":"https://registry.npmjs.org/@alexstukovnikov/oz-time/-/oz-time-1.0.2.tgz","fileCount":13,"integrity":"sha512-CanFrQzmiL90S8vNGGyPuVtt2hnOeovtZYdjMVUxePAKH6XI3ctnOmemypxcCQjWqNu0euFq7dWiwA8Ybm16IQ==","signatures":[{"sig":"MEQCIAFCR1MkcRYegeWpMd4RFIIkjIek88pZTu8WenKeqLgHAiAGG8akPtRUZ06ljKeV/NNHHvd1OeC5Mo2KZEjdjUlcbw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":105971},"main":"./src/index.js","type":"module","exports":{".":"./src/index.js"},"gitHead":"39c22f3d917d70e2fcb48468abbb5029a7cbb8c7","scripts":{"dev":"vite","docs":"jsdoc -c jsdoc.json","test":"vitest","build":"vite build","test:run":"vitest run","docs:build":"npm run docs:clean && npm run docs","docs:clean":"rimraf docs","test:coverage":"vitest run --coverage","prepublishOnly":"npm run build"},"_npmUser":{"name":"alexstukovnikov","email":"aleksalexxxey@gmail.com"},"repository":{"url":"git+https://github.com/AlexStukovnikov/oz-time.git","type":"git"},"_npmVersion":"10.2.5","description":"Lightweight JavaScript date-time library","directories":{},"sideEffects":false,"_nodeVersion":"24.14.1","_hasShrinkwrap":false,"devDependencies":{"vite":"^8.0.14","jsdoc":"^4.0.5","vitest":"^4.1.7","docdash":"^2.0.2","@vitest/ui":"^4.1.7","@vitest/coverage-v8":"^4.1.7"},"_npmOperationalInternal":{"tmp":"tmp/oz-time_1.0.2_1779807493564_0.8244508229293321","host":"s3://npm-registry-packages-npm-production"}},"1.0.3":{"name":"@alexstukovnikov/oz-time","version":"1.0.3","description":"Lightweight JavaScript date-time library","repository":{"type":"git","url":"git+https://github.com/AlexStukovnikov/oz-time.git"},"type":"module","main":"./src/index.js","exports":{".":"./src/index.js"},"sideEffects":false,"scripts":{"dev":"vite","build":"vite build","test":"vitest","test:run":"vitest run","test:coverage":"vitest run --coverage","docs":"jsdoc -c jsdoc.json","docs:clean":"rimraf docs","docs:build":"npm run docs:clean && npm run docs","prepublishOnly":"npm run build"},"keywords":["date","time","datetime"],"author":"","license":"ISC","devDependencies":{"@vitest/coverage-v8":"^4.1.7","@vitest/ui":"^4.1.7","docdash":"^2.0.2","jsdoc":"^4.0.5","vite":"^8.0.14","vitest":"^4.1.7"},"_id":"@alexstukovnikov/oz-time@1.0.3","gitHead":"e3d38c8ff1d3eca661ce822f141e3f1c7246a892","bugs":{"url":"https://github.com/AlexStukovnikov/oz-time/issues"},"homepage":"https://github.com/AlexStukovnikov/oz-time#readme","_nodeVersion":"24.14.1","_npmVersion":"10.2.5","dist":{"integrity":"sha512-NeQoN5FV4Uu5YT8Uk46rGZWIqC0vYfMIqYwAN9Qp37rhhxHLGsgpyX5RpsJqqKj0LMq/Dv/BNaIVwy9dE0x2/g==","shasum":"6ea58cdb1e144bbdc77e82e73a04c8eaad2e0290","tarball":"https://registry.npmjs.org/@alexstukovnikov/oz-time/-/oz-time-1.0.3.tgz","fileCount":13,"unpackedSize":105405,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIDbfZsG0hb/FofJjWYXpKzAknYydKzRu/T+F0wcAcrlHAiEA+aPsJ3HaB+kHZ9u4e4mPtCojXLUu5EStcYNmwEK4Y08="}]},"_npmUser":{"name":"alexstukovnikov","email":"aleksalexxxey@gmail.com"},"directories":{},"maintainers":[{"name":"alexstukovnikov","email":"aleksalexxxey@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/oz-time_1.0.3_1780812973418_0.5189999553468658"},"_hasShrinkwrap":false}},"time":{"created":"2026-05-26T11:02:48.710Z","modified":"2026-06-07T06:16:13.675Z","1.0.0":"2026-05-26T11:02:49.018Z","1.0.1":"2026-05-26T14:04:13.660Z","1.0.2":"2026-05-26T14:58:13.719Z","1.0.3":"2026-06-07T06:16:13.574Z"},"bugs":{"url":"https://github.com/AlexStukovnikov/oz-time/issues"},"license":"ISC","homepage":"https://github.com/AlexStukovnikov/oz-time#readme","keywords":["date","time","datetime"],"repository":{"type":"git","url":"git+https://github.com/AlexStukovnikov/oz-time.git"},"description":"Lightweight JavaScript date-time library","maintainers":[{"name":"alexstukovnikov","email":"aleksalexxxey@gmail.com"}],"readme":"# OzTime\r\n\r\nJavaScript-библиотека для работы с датой и временем.\r\n\r\n`OzTime` предоставляет неизменяемые объекты времени, фабричные функции создания экземпляров, арифметику по фиксированным и календарным единицам, сравнение, форматирование, работу с часовыми поясами, интервалы и длительности.\r\n\r\n- Документация API: [AlexStukovnikov.github.io/oz-time](https://AlexStukovnikov.github.io/oz-time/)\r\n- Пакет npm: [`@alexstukovnikov/oz-time`](https://www.npmjs.com/package/@alexstukovnikov/oz-time)\r\n\r\n## Содержание\r\n\r\n- [Почему OzTime](#почему-oztime)\r\n- [Возможности](#возможности)\r\n- [Установка](#установка)\r\n- [Быстрый старт](#быстрый-старт)\r\n- [Основные сценарии](#основные-сценарии)\r\n- [Создание экземпляров](#создание-экземпляров)\r\n- [Арифметика](#арифметика)\r\n- [Сравнение](#сравнение)\r\n- [Форматирование](#форматирование)\r\n- [Часовые пояса](#часовые-пояса)\r\n- [Интервалы и длительности](#интервалы-и-длительности)\r\n- [Поддерживаемые единицы времени](#поддерживаемые-единицы-времени)\r\n- [Токены форматирования](#токены-форматирования)\r\n- [FAQ](#faq)\r\n- [Ограничения и особенности](#ограничения-и-особенности)\r\n- [Лицензия](#лицензия)\r\n\r\n## Почему OzTime\r\n\r\n`OzTime` подойдёт, если нужна небольшая и понятная библиотека без перегруженного API.\r\n\r\nОсновные идеи:\r\n\r\n- время хранится как Unix timestamp в миллисекундах;\r\n- экземпляры `OzTime` неизменяемы;\r\n- часовой пояс и локаль сохраняются как часть объекта;\r\n- арифметика, сравнение и форматирование работают через единый API.\r\n\r\nБиблиотека хорошо подходит для:\r\n\r\n- прикладных JavaScript-проектов;\r\n- учебных и дипломных проектов;\r\n- небольших библиотек и утилит;\r\n- кода, где важна предсказуемость и неизменяемость.\r\n\r\n## Возможности\r\n\r\n- Неизменяемые экземпляры `OzTime`\r\n- Фабричные функции: `now`, `fromTimestamp`, `fromDate`, `fromISO`, `fromComponents`\r\n- Арифметика по времени: `add`, `subtract`\r\n- Сравнение: `isSame`, `isBefore`, `isAfter`, `isBetween`\r\n- Форматирование по шаблону\r\n- Работа с часовыми поясами: `setTimezone`, `getTimezoneOffset`\r\n- Интервалы: `Interval`, `interval`\r\n- Длительности: `Duration`, `duration`\r\n- Календарные утилиты: `isLeapYear`, `daysInMonth`\r\n\r\n## Установка\r\n\r\n```bash\r\nnpm install @alexstukovnikov/oz-time\r\n```\r\n\r\n## Быстрый старт\r\n\r\n```js\r\nimport { now, fromISO, duration, interval } from '@alexstukovnikov/oz-time';\r\n\r\nconst current = now('Europe/Moscow', 'ru-RU');\r\nconst release = fromISO('2024-05-25T12:00:00Z', 'UTC', 'ru-RU');\r\n\r\nconst nextWeek = release.add(7, 'day');\r\nconst diffHours = nextWeek.diff(release, 'hour');\r\n\r\nconsole.log(current.getTimezone()); // ожидаемый результат: Europe/Moscow\r\nconsole.log(nextWeek.format('DD.MM.YYYY HH:mm')); // ожидаемый результат: 01.06.2024 12:00\r\nconsole.log(diffHours); // ожидаемый результат: 168\r\n\r\nconst range = interval(release, nextWeek);\r\nconsole.log(range.contains(release)); // ожидаемый результат: true\r\n\r\nconst oneHour = duration(1, 'hour');\r\nconsole.log(oneHour.asMinutes()); // ожидаемый результат: 60\r\n```\r\n\r\n### Цепочка операций\r\n\r\n```js\r\nimport { fromISO } from '@alexstukovnikov/oz-time';\r\n\r\nconst result = fromISO('2024-05-25T12:00:00Z', 'UTC', 'ru-RU')\r\n    .add(1, 'day')\r\n    .add(2, 'hour')\r\n    .subtract(30, 'minute')\r\n    .setTimezone('Europe/Moscow')\r\n    .format('DD.MM.YYYY HH:mm:ss');\r\n\r\nconsole.log(result);\r\n```\r\n\r\n## Основные сценарии\r\n\r\n| Сценарий                                  | Что использовать                        | Почему                                                                              |\r\n| ----------------------------------------- | --------------------------------------- | ----------------------------------------------------------------------------------- |\r\n| Нужен текущий момент времени              | `now()`                                 | Самый простой способ получить новый экземпляр `OzTime` для текущего момента         |\r\n| Есть Unix timestamp в миллисекундах       | `fromTimestamp()`                       | Подходит для работы с временем из API, БД и системных источников                    |\r\n| Есть нативный `Date`                      | `fromDate()`                            | Удобно интегрировать библиотеку в существующий JavaScript-код                       |\r\n| Есть ISO-строка                           | `fromISO()`                             | Подходит для внешних API и сериализованных значений времени                         |\r\n| Нужно создать дату вручную из компонентов | `fromComponents()`                      | Удобно, когда год, месяц, день и время приходят по отдельности                      |\r\n| Нужно прибавить или вычесть время         | `add()` / `subtract()`                  | Возвращают новый экземпляр и не изменяют исходный объект                            |\r\n| Нужно сравнить два значения               | `isSame()` / `isBefore()` / `isAfter()` | Дают читаемый API для логики сравнения                                              |\r\n| Нужно проверить попадание в диапазон      | `isBetween()`                           | Удобнее, чем писать проверку вручную                                                |\r\n| Нужно получить строковое представление    | `format()`                              | Форматирование по шаблону с токенами                                                |\r\n| Нужно изменить отображаемый часовой пояс  | `setTimezone()`                         | Меняет timezone у нового экземпляра, не меняя абсолютный момент времени             |\r\n| Нужно узнать смещение относительно UTC    | `getTimezoneOffset()`                   | Полезно для отображения, отладки и расчётов                                         |\r\n| Нужно описать диапазон времени            | `Interval` / `interval()`               | Подходит для проверки попадания, пересечений и длительности интервала               |\r\n| Нужно описать фиксированную длительность  | `Duration` / `duration()`               | Удобно для преобразования между миллисекундами, секундами, минутами, часами и днями |\r\n| Нужно проверить високосный год            | `isLeapYear()`                          | Простая календарная утилита                                                         |\r\n| Нужно узнать число дней в месяце          | `daysInMonth()`                         | Удобно для валидации и генерации дат                                                |\r\n\r\n## Создание экземпляров\r\n\r\n```js\r\nimport { now, fromTimestamp, fromDate, fromISO, fromComponents } from '@alexstukovnikov/oz-time';\r\n\r\nconst a = now('Europe/Moscow', 'ru-RU');\r\nconst b = fromTimestamp(1716638400000, 'UTC', 'ru-RU');\r\nconst c = fromDate(new Date('2024-05-25T12:00:00Z'), 'UTC', 'ru-RU');\r\nconst d = fromISO('2024-05-25T12:00:00Z', 'UTC', 'ru-RU');\r\nconst e = fromComponents(2024, 5, 25, 12, 0, 0, 0, 'UTC', 'ru-RU');\r\n```\r\n\r\n- `now()` — создаёт экземпляр `OzTime` для текущего момента времени.\r\n- `fromTimestamp()` — создаёт экземпляр из Unix timestamp в миллисекундах.\r\n- `fromDate()` — создаёт экземпляр из объекта `Date`.\r\n- `fromISO()` — создаёт экземпляр из ISO-строки.\r\n- `fromComponents()` — создаёт экземпляр из отдельных компонентов даты и времени.\r\n\r\n## Арифметика\r\n\r\nВсе арифметические операции возвращают новый экземпляр `OzTime` и не изменяют исходный объект.\r\n\r\n### Добавление и вычитание\r\n\r\n```js\r\nimport { fromISO } from '@alexstukovnikov/oz-time';\r\n\r\nconst time = fromISO('2024-05-25T12:00:00Z');\r\n\r\nconsole.log(time.add(1, 'day').toISOString()); // ожидаемый результат: 2024-05-26T12:00:00.000Z\r\nconsole.log(time.subtract(2, 'hour').toISOString()); // ожидаемый результат: 2024-05-25T10:00:00.000Z\r\n```\r\n\r\n### Разница между датами\r\n\r\n```js\r\nimport { fromISO } from '@alexstukovnikov/oz-time';\r\n\r\nconst start = fromISO('2024-05-25T12:00:00Z');\r\nconst end = fromISO('2024-05-25T15:00:00Z');\r\n\r\nconsole.log(end.diff(start, 'hour')); // ожидаемый результат: 3\r\n```\r\n\r\n### Календарная арифметика\r\n\r\n```js\r\nimport { fromISO } from '@alexstukovnikov/oz-time';\r\n\r\nconst date = fromISO('2024-01-31T00:00:00Z');\r\nconst result = date.add(1, 'month');\r\n\r\nconsole.log(result.toISOString()); // ожидаемый результат: 2024-02-29T00:00:00.000Z\r\n```\r\n\r\n## Сравнение\r\n\r\n```js\r\nimport { fromISO } from '@alexstukovnikov/oz-time';\r\n\r\nconst a = fromISO('2024-05-25T12:00:00.100Z');\r\nconst b = fromISO('2024-05-25T12:00:00.900Z');\r\nconst c = fromISO('2024-05-26T12:00:00Z');\r\n\r\nconsole.log(a.isSame(b, 'second')); // ожидаемый результат: true\r\nconsole.log(a.isBefore(c)); // ожидаемый результат: true\r\nconsole.log(c.isAfter(a)); // ожидаемый результат: true\r\nconsole.log(a.isBetween(a.subtract(1, 'day'), c)); // ожидаемый результат: true\r\n```\r\n\r\n## Форматирование\r\n\r\nФункция `format()` и метод `OzTime#format()` поддерживают шаблоны форматирования.\r\n\r\n```js\r\nimport { fromISO } from '@alexstukovnikov/oz-time';\r\n\r\nconst time = fromISO('2024-05-25T12:00:00Z', 'UTC', 'ru-RU');\r\n\r\nconsole.log(time.format('DD.MM.YYYY HH:mm')); // ожидаемый результат: 25.05.2024 12:00\r\nconsole.log(time.format('dddd, D MMMM YYYY', 'ru-RU')); // пример: суббота, 25 мая 2024\r\n```\r\n\r\n## Часовые пояса\r\n\r\n`OzTime` хранит абсолютное время как timestamp, а часовой пояс используется как метаданные для отображения и форматирования.\r\n\r\n### Смена часового пояса\r\n\r\n```js\r\nimport { fromISO } from '@alexstukovnikov/oz-time';\r\n\r\nconst time = fromISO('2024-05-25T12:00:00Z', 'UTC', 'ru-RU');\r\nconst moscow = time.setTimezone('Europe/Moscow');\r\n\r\nconsole.log(moscow.getTimezone()); // ожидаемый результат: Europe/Moscow\r\n```\r\n\r\n### Смещение относительно UTC\r\n\r\n```js\r\nimport { fromISO } from '@alexstukovnikov/oz-time';\r\n\r\nconst time = fromISO('2024-05-25T12:00:00Z', 'Europe/Moscow', 'ru-RU');\r\nconsole.log(time.getTimezoneOffset()); // ожидаемый результат: 180\r\n```\r\n\r\n## Интервалы и длительности\r\n\r\n### Интервалы\r\n\r\nИнтервал представляет диапазон между двумя экземплярами `OzTime`, включая границы.\r\n\r\n```js\r\nimport { interval, fromISO } from '@alexstukovnikov/oz-time';\r\n\r\nconst start = fromISO('2024-05-25T10:00:00Z');\r\nconst end = fromISO('2024-05-25T12:00:00Z');\r\nconst range = interval(start, end);\r\n\r\nconsole.log(range.contains(fromISO('2024-05-25T11:00:00Z'))); // ожидаемый результат: true\r\nconsole.log(range.duration('hour')); // ожидаемый результат: 2\r\n```\r\n\r\n### Пересечение интервалов\r\n\r\n```js\r\nimport { Interval, fromISO } from '@alexstukovnikov/oz-time';\r\n\r\nconst a = new Interval(fromISO('2024-05-25T10:00:00Z'), fromISO('2024-05-25T12:00:00Z'));\r\n\r\nconst b = new Interval(fromISO('2024-05-25T11:00:00Z'), fromISO('2024-05-25T13:00:00Z'));\r\n\r\nconsole.log(a.overlaps(b)); // ожидаемый результат: true\r\n```\r\n\r\n### Длительности\r\n\r\n`Duration` используется для работы с фиксированными единицами времени.\r\n\r\n```js\r\nimport { duration } from '@alexstukovnikov/oz-time';\r\n\r\nconst twoHours = duration(2, 'hour');\r\n\r\nconsole.log(twoHours.asMilliseconds()); // ожидаемый результат: 7200000\r\nconsole.log(twoHours.asMinutes()); // ожидаемый результат: 120\r\nconsole.log(twoHours.asHours()); // ожидаемый результат: 2\r\n```\r\n\r\n### Сложение длительностей\r\n\r\n```js\r\nimport { duration } from '@alexstukovnikov/oz-time';\r\n\r\nconst a = duration(30, 'minute');\r\nconst b = duration(45, 'minute');\r\n\r\nconsole.log(a.add(b).asMinutes()); // ожидаемый результат: 75\r\n```\r\n\r\n## Поддерживаемые единицы времени\r\n\r\nПоддерживаются канонические имена и алиасы.\r\n\r\n| Единица      | Каноническое имя | Алиасы               |\r\n| ------------ | ---------------- | -------------------- |\r\n| Миллисекунда | `millisecond`    | `milliseconds`, `ms` |\r\n| Секунда      | `second`         | `seconds`, `s`       |\r\n| Минута       | `minute`         | `minutes`, `m`       |\r\n| Час          | `hour`           | `hours`, `h`         |\r\n| День         | `day`            | `days`, `d`          |\r\n| Месяц        | `month`          | `months`             |\r\n| Год          | `year`           | `years`, `y`         |\r\n\r\nФиксированные единицы:\r\n\r\n- `millisecond`\r\n- `second`\r\n- `minute`\r\n- `hour`\r\n- `day`\r\n\r\nКалендарные единицы:\r\n\r\n- `month`\r\n- `year`\r\n\r\n## Токены форматирования\r\n\r\n| Токен  | Описание                           | Пример        |\r\n| ------ | ---------------------------------- | ------------- |\r\n| `YYYY` | Год из 4 цифр                      | `2024`        |\r\n| `YY`   | Короткий год                       | `24`          |\r\n| `MMMM` | Полное название месяца             | `май` / `May` |\r\n| `MMM`  | Короткое название месяца           | `мая` / `May` |\r\n| `MM`   | Месяц с ведущим нулём              | `05`          |\r\n| `M`    | Месяц без ведущего нуля            | `5`           |\r\n| `dddd` | Полное название дня недели         | `суббота`     |\r\n| `ddd`  | Короткое название дня недели       | `сб`          |\r\n| `DD`   | День месяца с ведущим нулём        | `25`          |\r\n| `D`    | День месяца без ведущего нуля      | `25`          |\r\n| `HH`   | Часы в 24-часовом формате          | `09`, `18`    |\r\n| `H`    | Часы в 24-часовом формате без нуля | `9`, `18`     |\r\n| `hh`   | Часы в 12-часовом формате          | `01`, `12`    |\r\n| `h`    | Часы в 12-часовом формате без нуля | `1`, `12`     |\r\n| `mm`   | Минуты                             | `07`          |\r\n| `ss`   | Секунды                            | `05`          |\r\n| `SSS`  | Миллисекунды                       | `123`         |\r\n| `A`    | AM/PM                              | `AM`, `PM`    |\r\n\r\n## FAQ\r\n\r\n### Чем `fromISO()` отличается от `fromTimestamp()`?\r\n\r\n`fromISO()` принимает строку в формате ISO 8601 и сначала парсит её, а `fromTimestamp()` принимает уже готовое число миллисекунд. Если данные приходят из JSON API как строка, чаще удобнее `fromISO()`. Если уже есть timestamp из базы, системы или вычислений, лучше использовать `fromTimestamp()`.\r\n\r\n### Меняет ли `setTimezone()` сам момент времени?\r\n\r\nНет. `setTimezone()` не меняет абсолютный момент времени. Он возвращает новый экземпляр с тем же timestamp, но с другим часовым поясом для форматирования и вычисления смещения.\r\n\r\n### Изменяют ли методы `add()` и `subtract()` текущий объект?\r\n\r\nНет. `OzTime` построен как неизменяемый объект. Все операции возвращают новый экземпляр, а исходный объект остаётся без изменений.\r\n\r\n### Почему `Duration` не поддерживает `month` и `year`?\r\n\r\nПотому что `Duration` предназначен только для фиксированных единиц времени, которые можно точно перевести в миллисекунды. Месяцы и годы имеют переменную длину, поэтому для них используется календарная арифметика через `OzTime#add()` и `OzTime#diff()`.\r\n\r\n### Почему `diff(..., 'month')` и `diff(..., 'year')` работают не так, как разница в миллисекундах?\r\n\r\nПотому что для месяцев и лет применяется календарная логика, а не деление на фиксированное число миллисекунд. Это позволяет корректнее учитывать разную длину месяцев и переходы между датами.\r\n\r\n### Что лучше использовать: метод экземпляра или функцию модуля?\r\n\r\nЕсли уже есть экземпляр `OzTime`, обычно удобнее использовать методы экземпляра: `time.add(...)`, `time.format(...)`, `time.isBefore(...)`. Если нужен функциональный стиль или работаешь с импортированными утилитами напрямую, можно использовать функции модулей.\r\n\r\n### В каком часовом поясе хранится время внутри `OzTime`?\r\n\r\nВнутри хранится Unix timestamp в миллисекундах. Это абсолютное значение времени. Часовой пояс хранится отдельно как метаданные экземпляра.\r\n\r\n### Можно ли использовать библиотеку без locale и timezone?\r\n\r\nДа. По умолчанию используются:\r\n\r\n- `timezone = 'UTC'`\r\n- `locale = 'en-US'`\r\n\r\n### Когда использовать `Interval`, а когда `Duration`?\r\n\r\nИспользуй `Interval`, когда есть начало и конец диапазона. Используй `Duration`, когда нужна именно фиксированная длина времени, например 2 часа, 30 минут или 7 дней.\r\n\r\n## Ограничения и особенности\r\n\r\n- Внутреннее значение времени хранится как Unix timestamp в миллисекундах\r\n- Часовой пояс не меняет абсолютный момент времени, а влияет на форматирование и вычисление смещения\r\n- Методы `add`, `subtract`, `setTimezone` и другие операции не изменяют текущий экземпляр, а возвращают новый\r\n- `Duration` поддерживает только фиксированные единицы времени\r\n- Календарная арифметика через `month` и `year` учитывает реальную длину месяцев\r\n- Разница в `month` и `year` считается календарно, а не через точное число миллисекунд\r\n- Поддержка часовых поясов зависит от `Intl` и доступных IANA time zone в среде выполнения\r\n\r\n## Лицензия\r\n\r\nISC\r\n","readmeFilename":"README.md"}