@alexstukovnikov/oz-time 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,509 @@
1
+ import { add, subtract } from '../modules/arithmetic.js';
2
+ import { format } from '../modules/format.js';
3
+ import { isSame, isBefore, isAfter, isBetween } from '../modules/compare.js';
4
+ import { setTimezone, getTimezoneOffset } from '../modules/timezone.js';
5
+ import { interval as createInterval } from '../modules/interval.js';
6
+ import { duration as createDuration } from '../modules/duration.js';
7
+ import { diff } from '../utils/calendar.js';
8
+ import {
9
+ now as createNow,
10
+ fromTimestamp as createFromTimestamp,
11
+ fromDate as createFromDate,
12
+ fromISO as createFromISO,
13
+ fromComponents as createFromComponents,
14
+ } from './factory.js';
15
+
16
+ /**
17
+ * Основной модуль, содержащий класс {@link OzTime}.
18
+ *
19
+ * @module core/core
20
+ */
21
+
22
+ /**
23
+ * Строка с идентификатором часового пояса в формате IANA.
24
+ *
25
+ * @typedef {string} TimezoneString
26
+ */
27
+
28
+ /**
29
+ * Строка локали, совместимая с Intl API.
30
+ *
31
+ * @typedef {string} LocaleString
32
+ */
33
+
34
+ /**
35
+ * Формат включённости границ диапазона.
36
+ *
37
+ * @typedef {'[]'|'[)'|'(]'|'()'} Inclusivity
38
+ */
39
+
40
+ /**
41
+ * Поддерживаемая единица времени.
42
+ *
43
+ * @typedef {'millisecond'|'second'|'minute'|'hour'|'day'|'month'|'year'} TimeUnit
44
+ */
45
+
46
+ /**
47
+ * Проверяет корректность timestamp.
48
+ *
49
+ * @private
50
+ * @param {number} timestamp - Unix timestamp в миллисекундах.
51
+ * @throws {TypeError} Выбрасывается, если timestamp не является корректным числом.
52
+ * @returns {void}
53
+ */
54
+ function assertValidTimestamp(timestamp) {
55
+ if (typeof timestamp !== 'number' || Number.isNaN(timestamp)) {
56
+ throw new TypeError('OzTime: timestamp must be a valid number');
57
+ }
58
+ }
59
+
60
+ /**
61
+ * Проверяет корректность строки часового пояса.
62
+ *
63
+ * @private
64
+ * @param {TimezoneString} timezone - Идентификатор часового пояса.
65
+ * @throws {TypeError} Выбрасывается, если timezone пустой или не является строкой.
66
+ * @returns {void}
67
+ */
68
+ function assertValidTimezone(timezone) {
69
+ if (typeof timezone !== 'string' || timezone.trim() === '') {
70
+ throw new TypeError('OzTime: timezone must be a non-empty string');
71
+ }
72
+ }
73
+
74
+ /**
75
+ * Проверяет корректность строки локали.
76
+ *
77
+ * @private
78
+ * @param {LocaleString} locale - Локаль форматирования.
79
+ * @throws {TypeError} Выбрасывается, если locale пустая или не является строкой.
80
+ * @returns {void}
81
+ */
82
+ function assertValidLocale(locale) {
83
+ if (typeof locale !== 'string' || locale.trim() === '') {
84
+ throw new TypeError('OzTime: locale must be a non-empty string');
85
+ }
86
+ }
87
+
88
+ /**
89
+ * Неизменяемый объект даты и времени на основе UTC timestamp
90
+ * с дополнительными метаданными о часовом поясе и локали.
91
+ *
92
+ * Класс поддерживает как создание экземпляров через конструктор,
93
+ * так и через статические фабричные методы.
94
+ *
95
+ * @class
96
+ * @example
97
+ * import { OzTime } from '@alexstukovnikov/oz-time';
98
+ *
99
+ * const time = OzTime.fromISO('2024-05-25T12:00:00Z', 'UTC', 'ru-RU');
100
+ * console.log(time.toISOString()); // ожидаемый результат: 2024-05-25T12:00:00.000Z
101
+ *
102
+ * @example
103
+ * import { OzTime } from '@alexstukovnikov/oz-time';
104
+ *
105
+ * const result = OzTime
106
+ * .fromISO('2024-05-25T12:00:00Z', 'UTC', 'ru-RU')
107
+ * .add(1, 'day')
108
+ * .add(2, 'hour')
109
+ * .subtract(30, 'minute')
110
+ * .setTimezone('Europe/Moscow')
111
+ * .format('DD.MM.YYYY HH:mm:ss');
112
+ *
113
+ * console.log(result);
114
+ */
115
+ export class OzTime {
116
+ /**
117
+ * Создаёт новый экземпляр OzTime.
118
+ *
119
+ * @param {number} timestamp - Unix timestamp в миллисекундах.
120
+ * @param {TimezoneString} [timezone='UTC'] - Часовой пояс в формате IANA.
121
+ * @param {LocaleString} [locale='en-US'] - Локаль, используемая для форматирования.
122
+ * @throws {TypeError} Выбрасывается, если timestamp, timezone или locale некорректны.
123
+ */
124
+ constructor(timestamp, timezone = 'UTC', locale = 'en-US') {
125
+ assertValidTimestamp(timestamp);
126
+ assertValidTimezone(timezone);
127
+ assertValidLocale(locale);
128
+
129
+ this._timestamp = timestamp;
130
+ this._timezone = timezone;
131
+ this._locale = locale;
132
+ }
133
+
134
+ /**
135
+ * Создаёт экземпляр {@link OzTime} для текущего момента времени.
136
+ *
137
+ * @param {TimezoneString} [timezone='UTC'] - Часовой пояс в формате IANA.
138
+ * @param {LocaleString} [locale='en-US'] - Локаль форматирования.
139
+ * @returns {OzTime} Экземпляр с текущим временем.
140
+ * @example
141
+ * import { OzTime } from '@alexstukovnikov/oz-time';
142
+ *
143
+ * const current = OzTime.now('Europe/Moscow', 'ru-RU');
144
+ * console.log(current.getTimezone()); // ожидаемый результат: Europe/Moscow
145
+ */
146
+ static now(timezone = 'UTC', locale = 'en-US') {
147
+ return createNow(timezone, locale);
148
+ }
149
+
150
+ /**
151
+ * Создаёт экземпляр {@link OzTime} из Unix timestamp в миллисекундах.
152
+ *
153
+ * @param {number} timestamp - Unix timestamp в миллисекундах.
154
+ * @param {TimezoneString} [timezone='UTC'] - Часовой пояс в формате IANA.
155
+ * @param {LocaleString} [locale='en-US'] - Локаль форматирования.
156
+ * @returns {OzTime} Экземпляр времени.
157
+ * @example
158
+ * import { OzTime } from '@alexstukovnikov/oz-time';
159
+ *
160
+ * const time = OzTime.fromTimestamp(1716638400000, 'UTC', 'ru-RU');
161
+ * console.log(time.toISOString()); // ожидаемый результат: 2024-05-25T12:00:00.000Z
162
+ */
163
+ static fromTimestamp(timestamp, timezone = 'UTC', locale = 'en-US') {
164
+ return createFromTimestamp(timestamp, timezone, locale);
165
+ }
166
+
167
+ /**
168
+ * Создаёт экземпляр {@link OzTime} из объекта {@link Date}.
169
+ *
170
+ * @param {Date} date - Нативный объект Date.
171
+ * @param {TimezoneString} [timezone='UTC'] - Часовой пояс в формате IANA.
172
+ * @param {LocaleString} [locale='en-US'] - Локаль форматирования.
173
+ * @returns {OzTime} Экземпляр времени.
174
+ * @example
175
+ * import { OzTime } from '@alexstukovnikov/oz-time';
176
+ *
177
+ * const time = OzTime.fromDate(new Date('2024-05-25T12:00:00Z'), 'UTC', 'ru-RU');
178
+ * console.log(time.toTimestamp()); // ожидаемый результат: 1716638400000
179
+ */
180
+ static fromDate(date, timezone = 'UTC', locale = 'en-US') {
181
+ return createFromDate(date, timezone, locale);
182
+ }
183
+
184
+ /**
185
+ * Создаёт экземпляр {@link OzTime} из ISO-строки.
186
+ *
187
+ * @param {string} isoString - Строка даты и времени в формате ISO 8601.
188
+ * @param {TimezoneString} [timezone='UTC'] - Часовой пояс в формате IANA.
189
+ * @param {LocaleString} [locale='en-US'] - Локаль форматирования.
190
+ * @returns {OzTime} Экземпляр времени.
191
+ * @example
192
+ * import { OzTime } from '@alexstukovnikov/oz-time';
193
+ *
194
+ * const time = OzTime.fromISO('2024-05-25T12:00:00Z', 'UTC', 'ru-RU');
195
+ * console.log(time.format('DD.MM.YYYY HH:mm')); // ожидаемый результат: 25.05.2024 12:00
196
+ */
197
+ static fromISO(isoString, timezone = 'UTC', locale = 'en-US') {
198
+ return createFromISO(isoString, timezone, locale);
199
+ }
200
+
201
+ /**
202
+ * Создаёт экземпляр {@link OzTime} из отдельных компонентов даты и времени.
203
+ *
204
+ * @param {number} year - Год.
205
+ * @param {number} month - Месяц от 1 до 12.
206
+ * @param {number} day - День месяца.
207
+ * @param {number} [hour=0] - Час от 0 до 23.
208
+ * @param {number} [minute=0] - Минута от 0 до 59.
209
+ * @param {number} [second=0] - Секунда от 0 до 59.
210
+ * @param {number} [ms=0] - Миллисекунда от 0 до 999.
211
+ * @param {TimezoneString} [timezone='UTC'] - Часовой пояс в формате IANA.
212
+ * @param {LocaleString} [locale='en-US'] - Локаль форматирования.
213
+ * @returns {OzTime} Экземпляр времени.
214
+ * @example
215
+ * import { OzTime } from '@alexstukovnikov/oz-time';
216
+ *
217
+ * const time = OzTime.fromComponents(2024, 5, 25, 12, 0, 0, 0, 'UTC', 'ru-RU');
218
+ * console.log(time.toISOString()); // ожидаемый результат: 2024-05-25T12:00:00.000Z
219
+ */
220
+ static fromComponents(year, month, day, hour = 0, minute = 0, second = 0, ms = 0, timezone = 'UTC', locale = 'en-US') {
221
+ return createFromComponents(year, month, day, hour, minute, second, ms, timezone, locale);
222
+ }
223
+
224
+ /**
225
+ * Создаёт новый интервал между двумя значениями {@link OzTime}.
226
+ *
227
+ * @param {OzTime} start - Начало интервала.
228
+ * @param {OzTime} end - Конец интервала.
229
+ * @returns {Interval} Экземпляр интервала.
230
+ * @example
231
+ * import { OzTime } from '@alexstukovnikov/oz-time';
232
+ *
233
+ * const start = OzTime.fromISO('2024-05-25T10:00:00Z');
234
+ * const end = OzTime.fromISO('2024-05-25T12:00:00Z');
235
+ * const range = OzTime.interval(start, end);
236
+ *
237
+ * console.log(range.duration('hour')); // ожидаемый результат: 2
238
+ */
239
+ static interval(start, end) {
240
+ return createInterval(start, end);
241
+ }
242
+
243
+ /**
244
+ * Создаёт новую длительность из фиксированной единицы времени.
245
+ *
246
+ * @param {number} amount - Количество единиц времени.
247
+ * @param {TimeUnit|string} unit - Единица времени.
248
+ * @returns {Duration} Экземпляр длительности.
249
+ * @example
250
+ * import { OzTime } from '@alexstukovnikov/oz-time';
251
+ *
252
+ * const value = OzTime.duration(2, 'hour');
253
+ * console.log(value.asMinutes()); // ожидаемый результат: 120
254
+ */
255
+ static duration(amount, unit) {
256
+ return createDuration(amount, unit);
257
+ }
258
+
259
+ /**
260
+ * Возвращает внутренний Unix timestamp экземпляра в миллисекундах.
261
+ *
262
+ * @returns {number} Unix timestamp в миллисекундах.
263
+ * @example
264
+ * import { OzTime } from '@alexstukovnikov/oz-time';
265
+ *
266
+ * const time = OzTime.fromISO('2024-05-25T12:00:00Z', 'UTC', 'ru-RU');
267
+ * console.log(time.getTimestamp()); // ожидаемый результат: 1716638400000
268
+ */
269
+ getTimestamp() {
270
+ return this._timestamp;
271
+ }
272
+
273
+ /**
274
+ * Возвращает текущий часовой пояс экземпляра.
275
+ *
276
+ * @returns {TimezoneString} Идентификатор часового пояса.
277
+ * @example
278
+ * import { OzTime } from '@alexstukovnikov/oz-time';
279
+ *
280
+ * const time = OzTime.fromISO('2024-05-25T12:00:00Z', 'Europe/Moscow', 'ru-RU');
281
+ * console.log(time.getTimezone()); // ожидаемый результат: Europe/Moscow
282
+ */
283
+ getTimezone() {
284
+ return this._timezone;
285
+ }
286
+
287
+ /**
288
+ * Возвращает текущую локаль экземпляра.
289
+ *
290
+ * @returns {LocaleString} Строка локали.
291
+ * @example
292
+ * import { OzTime } from '@alexstukovnikov/oz-time';
293
+ *
294
+ * const time = OzTime.fromISO('2024-05-25T12:00:00Z', 'UTC', 'ru-RU');
295
+ * console.log(time.getLocale()); // ожидаемый результат: ru-RU
296
+ */
297
+ getLocale() {
298
+ return this._locale;
299
+ }
300
+
301
+ /**
302
+ * Возвращает внутренний Unix timestamp экземпляра в миллисекундах.
303
+ *
304
+ * @returns {number} Unix timestamp в миллисекундах.
305
+ * @example
306
+ * import { OzTime } from '@alexstukovnikov/oz-time';
307
+ *
308
+ * const time = OzTime.fromISO('2024-05-25T12:00:00Z', 'UTC', 'ru-RU');
309
+ * console.log(time.toTimestamp()); // ожидаемый результат: 1716638400000
310
+ */
311
+ toTimestamp() {
312
+ return this._timestamp;
313
+ }
314
+
315
+ /**
316
+ * Преобразует текущее значение времени в строку формата ISO 8601.
317
+ *
318
+ * @returns {string} Строковое представление даты и времени в формате ISO 8601.
319
+ * @example
320
+ * import { OzTime } from '@alexstukovnikov/oz-time';
321
+ *
322
+ * const time = OzTime.fromComponents(2024, 5, 25, 12, 0, 0, 0, 'UTC', 'ru-RU');
323
+ * console.log(time.toISOString()); // ожидаемый результат: 2024-05-25T12:00:00.000Z
324
+ */
325
+ toISOString() {
326
+ return new Date(this._timestamp).toISOString();
327
+ }
328
+
329
+ /**
330
+ * Возвращает новый экземпляр OzTime, у которого timestamp увеличен
331
+ * на указанное количество единиц времени.
332
+ *
333
+ * Исходный экземпляр не изменяется.
334
+ *
335
+ * @param {number} amount - Количество единиц времени.
336
+ * @param {TimeUnit|string} unit - Единица времени.
337
+ * @returns {OzTime} Новый экземпляр OzTime с timestamp, сдвинутым вперёд.
338
+ * @example
339
+ * import { OzTime } from '@alexstukovnikov/oz-time';
340
+ *
341
+ * const nextDay = OzTime
342
+ * .fromISO('2024-05-25T12:00:00Z')
343
+ * .add(1, 'day');
344
+ *
345
+ * console.log(nextDay.toISOString()); // ожидаемый результат: 2024-05-26T12:00:00.000Z
346
+ */
347
+ add(amount, unit) {
348
+ return add(this, amount, unit);
349
+ }
350
+
351
+ /**
352
+ * Возвращает новый экземпляр OzTime, у которого timestamp уменьшен
353
+ * на указанное количество единиц времени.
354
+ *
355
+ * Исходный экземпляр не изменяется.
356
+ *
357
+ * @param {number} amount - Количество единиц времени.
358
+ * @param {TimeUnit|string} unit - Единица времени.
359
+ * @returns {OzTime} Новый экземпляр OzTime с timestamp, сдвинутым назад.
360
+ * @example
361
+ * import { OzTime } from '@alexstukovnikov/oz-time';
362
+ *
363
+ * const prevHour = OzTime
364
+ * .fromISO('2024-05-25T12:00:00Z')
365
+ * .subtract(1, 'hour');
366
+ *
367
+ * console.log(prevHour.toISOString()); // ожидаемый результат: 2024-05-25T11:00:00.000Z
368
+ */
369
+ subtract(amount, unit) {
370
+ return subtract(this, amount, unit);
371
+ }
372
+
373
+ /**
374
+ * Форматирует текущее значение времени по заданному шаблону.
375
+ *
376
+ * @param {string} template - Строка шаблона форматирования.
377
+ * @param {LocaleString} [locale] - Локаль, которая временно переопределяет локаль экземпляра.
378
+ * @returns {string} Отформатированная строка.
379
+ * @example
380
+ * import { OzTime } from '@alexstukovnikov/oz-time';
381
+ *
382
+ * const value = OzTime.fromISO('2024-05-25T12:00:00Z', 'UTC', 'ru-RU');
383
+ * console.log(value.format('DD.MM.YYYY HH:mm')); // ожидаемый результат: 25.05.2024 12:00
384
+ */
385
+ format(template, locale) {
386
+ return format(this, template, locale);
387
+ }
388
+
389
+ /**
390
+ * Проверяет, совпадает ли текущее значение с другим временем
391
+ * на заданной точности.
392
+ *
393
+ * @param {OzTime} other - Второе значение для сравнения.
394
+ * @param {TimeUnit|string} [unit='millisecond'] - Точность сравнения.
395
+ * @returns {boolean} `true`, если значения совпадают.
396
+ * @example
397
+ * import { OzTime } from '@alexstukovnikov/oz-time';
398
+ *
399
+ * const a = OzTime.fromISO('2024-05-25T12:00:00.100Z');
400
+ * const b = OzTime.fromISO('2024-05-25T12:00:00.900Z');
401
+ * console.log(a.isSame(b, 'second')); // ожидаемый результат: true
402
+ */
403
+ isSame(other, unit = 'millisecond') {
404
+ return isSame(this, other, unit);
405
+ }
406
+
407
+ /**
408
+ * Проверяет, находится ли текущее значение раньше другого времени.
409
+ *
410
+ * @param {OzTime} other - Второе значение для сравнения.
411
+ * @param {TimeUnit|string} [unit='millisecond'] - Точность сравнения.
412
+ * @returns {boolean} `true`, если текущее значение меньше.
413
+ * @example
414
+ * import { OzTime } from '@alexstukovnikov/oz-time';
415
+ *
416
+ * const a = OzTime.fromISO('2024-05-25T12:00:00Z');
417
+ * const b = a.add(1, 'day');
418
+ * console.log(a.isBefore(b)); // ожидаемый результат: true
419
+ */
420
+ isBefore(other, unit = 'millisecond') {
421
+ return isBefore(this, other, unit);
422
+ }
423
+
424
+ /**
425
+ * Проверяет, находится ли текущее значение позже другого времени.
426
+ *
427
+ * @param {OzTime} other - Второе значение для сравнения.
428
+ * @param {TimeUnit|string} [unit='millisecond'] - Точность сравнения.
429
+ * @returns {boolean} `true`, если текущее значение больше.
430
+ * @example
431
+ * import { OzTime } from '@alexstukovnikov/oz-time';
432
+ *
433
+ * const a = OzTime.fromISO('2024-05-26T12:00:00Z');
434
+ * const b = OzTime.fromISO('2024-05-25T12:00:00Z');
435
+ * console.log(a.isAfter(b)); // ожидаемый результат: true
436
+ */
437
+ isAfter(other, unit = 'millisecond') {
438
+ return isAfter(this, other, unit);
439
+ }
440
+
441
+ /**
442
+ * Проверяет, попадает ли текущее значение в диапазон между двумя датами.
443
+ *
444
+ * @param {OzTime} start - Левая граница диапазона.
445
+ * @param {OzTime} end - Правая граница диапазона.
446
+ * @param {TimeUnit|string} [unit='millisecond'] - Точность сравнения.
447
+ * @param {Inclusivity} [inclusivity='[]'] - Формат включённости границ.
448
+ * @returns {boolean} `true`, если значение находится внутри диапазона.
449
+ * @example
450
+ * import { OzTime } from '@alexstukovnikov/oz-time';
451
+ *
452
+ * const current = OzTime.fromISO('2024-05-25T12:00:00Z');
453
+ * const start = current.subtract(1, 'day');
454
+ * const end = current.add(1, 'day');
455
+ * console.log(current.isBetween(start, end)); // ожидаемый результат: true
456
+ */
457
+ isBetween(start, end, unit = 'millisecond', inclusivity = '[]') {
458
+ return isBetween(this, start, end, unit, inclusivity);
459
+ }
460
+
461
+ /**
462
+ * Возвращает новый экземпляр с тем же timestamp, но другим часовым поясом.
463
+ *
464
+ * @param {TimezoneString} timezone - Новый часовой пояс.
465
+ * @returns {OzTime} Новый экземпляр с обновлённым часовым поясом.
466
+ * @example
467
+ * import { OzTime } from '@alexstukovnikov/oz-time';
468
+ *
469
+ * const moscowTime = OzTime
470
+ * .fromISO('2024-05-25T12:00:00Z', 'UTC', 'ru-RU')
471
+ * .setTimezone('Europe/Moscow');
472
+ *
473
+ * console.log(moscowTime.getTimezone()); // ожидаемый результат: Europe/Moscow
474
+ */
475
+ setTimezone(timezone) {
476
+ return setTimezone(this, timezone);
477
+ }
478
+
479
+ /**
480
+ * Возвращает смещение текущего часового пояса относительно UTC в минутах.
481
+ *
482
+ * @returns {number} Смещение в минутах.
483
+ * @example
484
+ * import { OzTime } from '@alexstukovnikov/oz-time';
485
+ *
486
+ * const time = OzTime.fromISO('2024-05-25T12:00:00Z', 'Europe/Moscow', 'ru-RU');
487
+ * console.log(time.getTimezoneOffset()); // ожидаемый результат: 180
488
+ */
489
+ getTimezoneOffset() {
490
+ return getTimezoneOffset(this);
491
+ }
492
+
493
+ /**
494
+ * Вычисляет разницу между текущим значением и другим временем.
495
+ *
496
+ * @param {OzTime} other - Второе значение для сравнения.
497
+ * @param {TimeUnit|string} [unit='millisecond'] - Единица измерения разницы.
498
+ * @returns {number} Разница между двумя значениями.
499
+ * @example
500
+ * import { OzTime } from '@alexstukovnikov/oz-time';
501
+ *
502
+ * const start = OzTime.fromISO('2024-05-25T12:00:00Z');
503
+ * const end = start.add(2, 'hour');
504
+ * console.log(end.diff(start, 'hour')); // ожидаемый результат: 2
505
+ */
506
+ diff(other, unit = 'millisecond') {
507
+ return diff(this, other, unit);
508
+ }
509
+ }