@alexstukovnikov/oz-time 1.0.0 → 1.0.1

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.
package/package.json CHANGED
@@ -1,48 +1,45 @@
1
- {
2
- "name": "@alexstukovnikov/oz-time",
3
- "version": "1.0.0",
4
- "description": "Lightweight JavaScript date-time library",
5
- "repository": {
6
- "type": "git",
7
- "url": "https://github.com/AlexStukovnikov/oz-time.git"
8
- },
9
- "type": "module",
10
- "main": "./dist/oz-time.cjs",
11
- "module": "./dist/oz-time.esm.js",
12
- "exports": {
13
- ".": {
14
- "import": "./dist/oz-time.esm.js",
15
- "require": "./dist/oz-time.cjs"
16
- }
17
- },
18
- "files": [
19
- "dist"
20
- ],
21
- "sideEffects": false,
22
- "scripts": {
23
- "dev": "vite",
24
- "build": "vite build",
25
- "test": "vitest",
26
- "test:run": "vitest run",
27
- "test:coverage": "vitest run --coverage",
28
- "docs": "jsdoc -c jsdoc.json",
29
- "docs:clean": "rimraf docs",
30
- "docs:build": "npm run docs:clean && npm run docs",
31
- "prepublishOnly": "npm run build"
32
- },
33
- "keywords": [
34
- "date",
35
- "time",
36
- "datetime"
37
- ],
38
- "author": "",
39
- "license": "ISC",
40
- "devDependencies": {
41
- "@vitest/coverage-v8": "^4.1.7",
42
- "@vitest/ui": "^4.1.7",
43
- "docdash": "^2.0.2",
44
- "jsdoc": "^4.0.5",
45
- "vite": "^8.0.14",
46
- "vitest": "^4.1.7"
47
- }
48
- }
1
+ {
2
+ "name": "@alexstukovnikov/oz-time",
3
+ "version": "1.0.1",
4
+ "description": "Lightweight JavaScript date-time library",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/AlexStukovnikov/oz-time.git"
8
+ },
9
+ "type": "module",
10
+ "main": "./src/index.js",
11
+ "exports": {
12
+ ".": "./src/index.js"
13
+ },
14
+ "files": [
15
+ "src",
16
+ "README.md"
17
+ ],
18
+ "sideEffects": false,
19
+ "scripts": {
20
+ "dev": "vite",
21
+ "build": "vite build",
22
+ "test": "vitest",
23
+ "test:run": "vitest run",
24
+ "test:coverage": "vitest run --coverage",
25
+ "docs": "jsdoc -c jsdoc.json",
26
+ "docs:clean": "rimraf docs",
27
+ "docs:build": "npm run docs:clean && npm run docs",
28
+ "prepublishOnly": "npm run build"
29
+ },
30
+ "keywords": [
31
+ "date",
32
+ "time",
33
+ "datetime"
34
+ ],
35
+ "author": "",
36
+ "license": "ISC",
37
+ "devDependencies": {
38
+ "@vitest/coverage-v8": "^4.1.7",
39
+ "@vitest/ui": "^4.1.7",
40
+ "docdash": "^2.0.2",
41
+ "jsdoc": "^4.0.5",
42
+ "vite": "^8.0.14",
43
+ "vitest": "^4.1.7"
44
+ }
45
+ }
@@ -0,0 +1,353 @@
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 { diff } from '../utils/calendar.js';
6
+
7
+ /**
8
+ * Основной модуль, содержащий класс {@link OzTime}.
9
+ *
10
+ * @module core/core
11
+ */
12
+
13
+ /**
14
+ * Строка с идентификатором часового пояса в формате IANA.
15
+ *
16
+ * @typedef {string} TimezoneString
17
+ */
18
+
19
+ /**
20
+ * Строка локали, совместимая с Intl API.
21
+ *
22
+ * @typedef {string} LocaleString
23
+ */
24
+
25
+ /**
26
+ * Формат включённости границ диапазона.
27
+ *
28
+ * @typedef {'[]'|'[)'|'(]'|'()'} Inclusivity
29
+ */
30
+
31
+ /**
32
+ * Поддерживаемая единица времени.
33
+ *
34
+ * @typedef {'millisecond'|'second'|'minute'|'hour'|'day'|'month'|'year'} TimeUnit
35
+ */
36
+
37
+ /**
38
+ * Проверяет корректность timestamp.
39
+ *
40
+ * @private
41
+ * @param {number} timestamp - Unix timestamp в миллисекундах.
42
+ * @throws {TypeError} Выбрасывается, если timestamp не является корректным числом.
43
+ * @returns {void}
44
+ */
45
+ function assertValidTimestamp(timestamp) {
46
+ if (typeof timestamp !== 'number' || Number.isNaN(timestamp)) {
47
+ throw new TypeError('OzTime: timestamp must be a valid number');
48
+ }
49
+ }
50
+
51
+ /**
52
+ * Проверяет корректность строки часового пояса.
53
+ *
54
+ * @private
55
+ * @param {TimezoneString} timezone - Идентификатор часового пояса.
56
+ * @throws {TypeError} Выбрасывается, если timezone пустой или не является строкой.
57
+ * @returns {void}
58
+ */
59
+ function assertValidTimezone(timezone) {
60
+ if (typeof timezone !== 'string' || timezone.trim() === '') {
61
+ throw new TypeError('OzTime: timezone must be a non-empty string');
62
+ }
63
+ }
64
+
65
+ /**
66
+ * Проверяет корректность строки локали.
67
+ *
68
+ * @private
69
+ * @param {LocaleString} locale - Локаль форматирования.
70
+ * @throws {TypeError} Выбрасывается, если locale пустая или не является строкой.
71
+ * @returns {void}
72
+ */
73
+ function assertValidLocale(locale) {
74
+ if (typeof locale !== 'string' || locale.trim() === '') {
75
+ throw new TypeError('OzTime: locale must be a non-empty string');
76
+ }
77
+ }
78
+
79
+ /**
80
+ * Неизменяемый объект даты и времени на основе UTC timestamp
81
+ * с дополнительными метаданными о часовом поясе и локали.
82
+ *
83
+ * @class
84
+ */
85
+ export class OzTime {
86
+ /**
87
+ * Создаёт новый экземпляр OzTime.
88
+ *
89
+ * @param {number} timestamp - Unix timestamp в миллисекундах.
90
+ * @param {TimezoneString} [timezone='UTC'] - Часовой пояс в формате IANA.
91
+ * @param {LocaleString} [locale='en-US'] - Локаль, используемая для форматирования.
92
+ * @throws {TypeError} Выбрасывается, если timestamp, timezone или locale некорректны.
93
+ */
94
+ constructor(timestamp, timezone = 'UTC', locale = 'en-US') {
95
+ assertValidTimestamp(timestamp);
96
+ assertValidTimezone(timezone);
97
+ assertValidLocale(locale);
98
+
99
+ this._timestamp = timestamp;
100
+ this._timezone = timezone;
101
+ this._locale = locale;
102
+ }
103
+
104
+ /**
105
+ * Возвращает внутренний Unix timestamp экземпляра в миллисекундах.
106
+ *
107
+ * @returns {number} Unix timestamp в миллисекундах.
108
+ * @example
109
+ * import { fromISO } from '@alexstukovnikov/oz-time';
110
+ *
111
+ * const time = fromISO('2024-05-25T12:00:00Z', 'UTC', 'ru-RU');
112
+ * console.log(time.getTimestamp()); // ожидаемый результат: 1716638400000
113
+ */
114
+ getTimestamp() {
115
+ return this._timestamp;
116
+ }
117
+
118
+ /**
119
+ * Возвращает текущий часовой пояс экземпляра.
120
+ *
121
+ * @returns {TimezoneString} Идентификатор часового пояса.
122
+ * @example
123
+ * import { fromISO } from '@alexstukovnikov/oz-time';
124
+ *
125
+ * const time = fromISO('2024-05-25T12:00:00Z', 'Europe/Moscow', 'ru-RU');
126
+ * console.log(time.getTimezone()); // ожидаемый результат: Europe/Moscow
127
+ */
128
+ getTimezone() {
129
+ return this._timezone;
130
+ }
131
+
132
+ /**
133
+ * Возвращает текущую локаль экземпляра.
134
+ *
135
+ * @returns {LocaleString} Строка локали.
136
+ * @example
137
+ * import { fromISO } from '@alexstukovnikov/oz-time';
138
+ *
139
+ * const time = fromISO('2024-05-25T12:00:00Z', 'UTC', 'ru-RU');
140
+ * console.log(time.getLocale()); // ожидаемый результат: ru-RU
141
+ */
142
+ getLocale() {
143
+ return this._locale;
144
+ }
145
+
146
+ /**
147
+ * Преобразует экземпляр в числовой timestamp.
148
+ *
149
+ * @returns {number} Unix timestamp в миллисекундах.
150
+ * @example
151
+ * const time = fromISO('2024-05-25T12:00:00Z', 'UTC', 'ru-RU');
152
+ console.log(time.toTimestamp()); // ожидаемый результат: 1716638400000
153
+ */
154
+ toTimestamp() {
155
+ return this._timestamp;
156
+ }
157
+
158
+ /**
159
+ * Преобразует текущее значение времени в строку формата ISO 8601.
160
+ *
161
+ * @returns {string} Строковое представление даты и времени в формате ISO 8601.
162
+ * @example
163
+ * import { fromComponents } from '@alexstukovnikov/oz-time';
164
+ *
165
+ * const time = fromComponents(2024, 5, 25, 12, 0, 0, 0, 'UTC', 'ru-RU');
166
+ * console.log(time.toISOString()); // ожидаемый результат: 2024-05-25T12:00:00.000Z
167
+ */
168
+ toISOString() {
169
+ return new Date(this._timestamp).toISOString();
170
+ }
171
+
172
+ /**
173
+ * Возвращает новый экземпляр OzTime, у которого timestamp увеличен
174
+ * на указанное количество единиц времени.
175
+ *
176
+ * Исходный экземпляр не изменяется.
177
+ *
178
+ * @param {number} amount - Количество единиц времени.
179
+ * @param {TimeUnit|string} unit - Единица времени.
180
+ * @returns {OzTime} Новый экземпляр OzTime с timestamp, сдвинутым вперёд.
181
+ * @example
182
+ * import { fromISO } from '@alexstukovnikov/oz-time';
183
+ *
184
+ * const time = fromISO('2024-05-25T12:00:00Z', 'UTC', 'ru-RU');
185
+ * const nextDay = time.add(1, 'day');
186
+ * console.log(nextDay.toISOString()); // ожидаемый результат: 2024-05-26T12:00:00.000Z
187
+ */
188
+ add(amount, unit) {
189
+ return add(this, amount, unit);
190
+ }
191
+
192
+ /**
193
+ * Возвращает новый экземпляр OzTime, у которого timestamp уменьшен
194
+ * на указанное количество единиц времени.
195
+ *
196
+ * Исходный экземпляр не изменяется.
197
+ *
198
+ * @param {number} amount - Количество единиц времени.
199
+ * @param {TimeUnit|string} unit - Единица времени.
200
+ * @returns {OzTime} Новый экземпляр OzTime с timestamp, сдвинутым назад.
201
+ * @example
202
+ * import { fromISO } from '@alexstukovnikov/oz-time';
203
+ *
204
+ * const time = fromISO('2024-05-25T12:00:00Z', 'UTC', 'ru-RU');
205
+ * const prevHour = time.subtract(1, 'hour');
206
+ * console.log(prevHour.toISOString()); // ожидаемый результат: 2024-05-25T11:00:00.000Z
207
+ */
208
+ subtract(amount, unit) {
209
+ return subtract(this, amount, unit);
210
+ }
211
+
212
+ /**
213
+ * Возвращает строковое представление текущего значения времени по заданному шаблону.
214
+ *
215
+ * @param {string} template - Строка шаблона форматирования.
216
+ * @param {LocaleString} [locale] - Локаль, которая переопределяет локаль экземпляра.
217
+ * @returns {string} Отформатированная строка.
218
+ * @example
219
+ * import { fromISO } from '@alexstukovnikov/oz-time';
220
+ *
221
+ * const time = fromISO('2024-05-25T12:00:00Z', 'UTC', 'ru-RU');
222
+ * console.log(time.format('DD.MM.YYYY HH:mm')); // ожидаемый результат: 25.05.2024 12:00
223
+ */
224
+ format(template, locale) {
225
+ return format(this, template, locale);
226
+ }
227
+
228
+ /**
229
+ * Проверяет, совпадает ли текущее значение с другим значением времени
230
+ * на заданной точности.
231
+ *
232
+ * @param {OzTime} other - Второе значение для сравнения.
233
+ * @param {TimeUnit|string} [unit='millisecond'] - Точность сравнения.
234
+ * @returns {boolean} `true`, если значения совпадают на указанной точности.
235
+ * @example
236
+ * import { fromISO } from '@alexstukovnikov/oz-time';
237
+ *
238
+ * const a = fromISO('2024-05-25T12:00:00.100Z');
239
+ * const b = fromISO('2024-05-25T12:00:00.900Z');
240
+ * console.log(a.isSame(b, 'second')); // ожидаемый результат: true
241
+ */
242
+ isSame(other, unit = 'millisecond') {
243
+ return isSame(this, other, unit);
244
+ }
245
+
246
+ /**
247
+ * Проверяет, находится ли текущее значение раньше другого значения времени
248
+ * на заданной точности.
249
+ *
250
+ * @param {OzTime} other - Второе значение для сравнения.
251
+ * @param {TimeUnit|string} [unit='millisecond'] - Точность сравнения.
252
+ * @returns {boolean} `true`, если текущее значение раньше.
253
+ * @example
254
+ * import { fromISO } from '@alexstukovnikov/oz-time';
255
+ *
256
+ * const a = fromISO('2024-05-25T12:00:00Z');
257
+ * const b = fromISO('2024-05-26T12:00:00Z');
258
+ * console.log(a.isBefore(b)); // ожидаемый результат: true
259
+ */
260
+ isBefore(other, unit = 'millisecond') {
261
+ return isBefore(this, other, unit);
262
+ }
263
+
264
+ /**
265
+ * Проверяет, находится ли текущее значение позже другого значения времени
266
+ * на заданной точности.
267
+ *
268
+ * @param {OzTime} other - Второе значение для сравнения.
269
+ * @param {TimeUnit|string} [unit='millisecond'] - Точность сравнения.
270
+ * @returns {boolean} `true`, если текущее значение позже.
271
+ * @example
272
+ * import { fromISO } from '@alexstukovnikov/oz-time';
273
+ *
274
+ * const a = fromISO('2024-05-26T12:00:00Z');
275
+ * const b = fromISO('2024-05-25T12:00:00Z');
276
+ * console.log(a.isAfter(b)); // ожидаемый результат: true
277
+ */
278
+ isAfter(other, unit = 'millisecond') {
279
+ return isAfter(this, other, unit);
280
+ }
281
+
282
+ /**
283
+ * Проверяет, попадает ли текущее значение времени в диапазон между двумя границами
284
+ * на заданной точности.
285
+ *
286
+ * @param {OzTime} start - Левая граница диапазона.
287
+ * @param {OzTime} end - Правая граница диапазона.
288
+ * @param {TimeUnit|string} [unit='millisecond'] - Точность сравнения.
289
+ * @param {Inclusivity} [inclusivity='[]'] - Формат включённости границ.
290
+ * @returns {boolean} `true`, если значение находится внутри диапазона.
291
+ * @example
292
+ * import { fromISO } from '@alexstukovnikov/oz-time';
293
+ *
294
+ * const current = fromISO('2024-05-25T12:00:00Z');
295
+ * const start = fromISO('2024-05-25T10:00:00Z');
296
+ * const end = fromISO('2024-05-25T14:00:00Z');
297
+ * console.log(current.isBetween(start, end)); // ожидаемый результат: true
298
+ */
299
+ isBetween(start, end, unit = 'millisecond', inclusivity = '[]') {
300
+ return isBetween(this, start, end, unit, inclusivity);
301
+ }
302
+
303
+ /**
304
+ * Возвращает новый экземпляр OzTime с тем же timestamp и locale,
305
+ * но с другим часовым поясом.
306
+ *
307
+ * Абсолютный момент времени при этом не изменяется.
308
+ *
309
+ * @param {TimezoneString} timezone - Новый часовой пояс.
310
+ * @returns {OzTime} Новый экземпляр OzTime с обновлённым часовым поясом.
311
+ * @example
312
+ * import { fromISO } from '@alexstukovnikov/oz-time';
313
+ *
314
+ * const time = fromISO('2024-05-25T12:00:00Z', 'UTC', 'ru-RU');
315
+ * const moscowTime = time.setTimezone('Europe/Moscow');
316
+ * console.log(moscowTime.getTimezone()); // ожидаемый результат: Europe/Moscow
317
+ */
318
+ setTimezone(timezone) {
319
+ return setTimezone(this, timezone);
320
+ }
321
+
322
+ /**
323
+ * Возвращает смещение текущего часового пояса относительно UTC в минутах.
324
+ *
325
+ * @returns {number} Смещение в минутах относительно UTC.
326
+ * @example
327
+ * import { fromISO } from '@alexstukovnikov/oz-time';
328
+ *
329
+ * const time = fromISO('2024-05-25T12:00:00Z', 'Europe/Moscow', 'ru-RU');
330
+ * console.log(time.getTimezoneOffset()); // ожидаемый результат: 180
331
+ */
332
+ getTimezoneOffset() {
333
+ return getTimezoneOffset(this);
334
+ }
335
+
336
+ /**
337
+ * Возвращает числовую разницу между текущим экземпляром и другим значением времени
338
+ * в указанной единице измерения.
339
+ *
340
+ * @param {OzTime} other - Второе значение для сравнения.
341
+ * @param {TimeUnit|string} [unit='millisecond'] - Единица измерения разницы.
342
+ * @returns {number} Разница между двумя значениями времени.
343
+ * @example
344
+ * import { fromISO } from '@alexstukovnikov/oz-time';
345
+ *
346
+ * const start = fromISO('2024-05-25T12:00:00Z');
347
+ * const end = fromISO('2024-05-25T14:00:00Z');
348
+ * console.log(end.diff(start, 'hour')); // ожидаемый результат: 2
349
+ */
350
+ diff(other, unit = 'millisecond') {
351
+ return diff(this, other, unit);
352
+ }
353
+ }
@@ -0,0 +1,194 @@
1
+ import { OzTime } from './core.js';
2
+ import { daysInMonth } from '../utils/calendar.js';
3
+
4
+ /**
5
+ * Фабричные функции для создания экземпляров {@link OzTime}.
6
+ *
7
+ * @module core/factory
8
+ */
9
+
10
+ /**
11
+ * Проверяет корректность timestamp.
12
+ *
13
+ * @private
14
+ * @param {number} timestamp - Unix timestamp в миллисекундах.
15
+ * @throws {TypeError} Выбрасывается, если timestamp некорректен.
16
+ * @returns {void}
17
+ */
18
+ function assertValidTimestamp(timestamp) {
19
+ if (typeof timestamp !== 'number' || Number.isNaN(timestamp)) {
20
+ throw new TypeError('fromTimestamp: timestamp must be a valid number');
21
+ }
22
+ }
23
+
24
+ /**
25
+ * Проверяет корректность объекта Date.
26
+ *
27
+ * @private
28
+ * @param {Date} date - Проверяемый объект Date.
29
+ * @throws {TypeError} Выбрасывается, если date некорректен.
30
+ * @returns {void}
31
+ */
32
+ function assertValidDate(date) {
33
+ if (!(date instanceof Date) || Number.isNaN(date.getTime())) {
34
+ throw new TypeError('fromDate: date must be a valid Date');
35
+ }
36
+ }
37
+
38
+ /**
39
+ * Проверяет, что значение является целым числом.
40
+ *
41
+ * @private
42
+ * @param {number} value - Проверяемое значение.
43
+ * @param {string} name - Имя параметра.
44
+ * @throws {TypeError} Выбрасывается, если значение не является целым числом.
45
+ * @returns {void}
46
+ */
47
+ function assertInteger(value, name) {
48
+ if (!Number.isInteger(value)) {
49
+ throw new TypeError(`${name} must be an integer`);
50
+ }
51
+ }
52
+
53
+ /**
54
+ * Создаёт и возвращает экземпляр {@link OzTime} для текущего момента времени.
55
+ *
56
+ * @param {string} [timezone='UTC'] - Часовой пояс в формате IANA.
57
+ * @param {string} [locale='en-US'] - Локаль форматирования.
58
+ * @returns {OzTime} Экземпляр с текущим временем.
59
+ * @example
60
+ * import { now } from '@alexstukovnikov/oz-time';
61
+ *
62
+ * const current = now('Europe/Moscow', 'ru-RU');
63
+ * console.log(current.getTimezone()); // ожидаемый результат: Europe/Moscow
64
+ */
65
+ export function now(timezone = 'UTC', locale = 'en-US') {
66
+ return new OzTime(Date.now(), timezone, locale);
67
+ }
68
+
69
+ /**
70
+ * Создаёт и возвращает экземпляр {@link OzTime} на основе Unix timestamp.
71
+ *
72
+ * @param {number} timestamp - Unix timestamp в миллисекундах.
73
+ * @param {string} [timezone='UTC'] - Часовой пояс в формате IANA.
74
+ * @param {string} [locale='en-US'] - Локаль форматирования.
75
+ * @throws {TypeError} Выбрасывается, если timestamp некорректен.
76
+ * @returns {OzTime} Экземпляр времени.
77
+ * @example
78
+ * import { fromTimestamp } from '@alexstukovnikov/oz-time';
79
+ *
80
+ * const time = fromTimestamp(1716638400000, 'UTC', 'ru-RU');
81
+ * console.log(time.toISOString()); // ожидаемый результат: 2024-05-25T12:00:00.000Z
82
+ */
83
+ export function fromTimestamp(timestamp, timezone = 'UTC', locale = 'en-US') {
84
+ assertValidTimestamp(timestamp);
85
+ return new OzTime(timestamp, timezone, locale);
86
+ }
87
+
88
+ /**
89
+ * Создаёт и возвращает экземпляр {@link OzTime} на основе объекта {@link Date}.
90
+ *
91
+ * @param {Date} date - Нативный объект Date.
92
+ * @param {string} [timezone='UTC'] - Часовой пояс в формате IANA.
93
+ * @param {string} [locale='en-US'] - Локаль форматирования.
94
+ * @throws {TypeError} Выбрасывается, если date некорректен.
95
+ * @returns {OzTime} Экземпляр времени.
96
+ * @example
97
+ * import { fromDate } from '@alexstukovnikov/oz-time';
98
+ *
99
+ * const time = fromDate(new Date('2024-05-25T12:00:00Z'), 'UTC', 'ru-RU');
100
+ * console.log(time.toTimestamp()); // ожидаемый результат: 1716638400000
101
+ */
102
+ export function fromDate(date, timezone = 'UTC', locale = 'en-US') {
103
+ assertValidDate(date);
104
+ return new OzTime(date.getTime(), timezone, locale);
105
+ }
106
+
107
+ /**
108
+ * Создаёт и возвращает экземпляр {@link OzTime} на основе ISO-строки.
109
+ *
110
+ * @param {string} isoString - Строка даты и времени в формате ISO 8601.
111
+ * @param {string} [timezone='UTC'] - Часовой пояс в формате IANA.
112
+ * @param {string} [locale='en-US'] - Локаль форматирования.
113
+ * @throws {TypeError} Выбрасывается, если строка пустая или не является строкой.
114
+ * @throws {Error} Выбрасывается, если строку не удалось распарсить.
115
+ * @returns {OzTime} Экземпляр времени.
116
+ * @example
117
+ * import { fromISO } from '@alexstukovnikov/oz-time';
118
+ *
119
+ * const time = fromISO('2024-05-25T12:00:00Z', 'UTC', 'ru-RU');
120
+ * console.log(time.format('DD.MM.YYYY HH:mm')); // ожидаемый результат: 25.05.2024 12:00
121
+ */
122
+ export function fromISO(isoString, timezone = 'UTC', locale = 'en-US') {
123
+ if (typeof isoString !== 'string' || isoString.trim() === '') {
124
+ throw new TypeError('fromISO: isoString must be a non-empty string');
125
+ }
126
+
127
+ const ts = Date.parse(isoString);
128
+
129
+ if (Number.isNaN(ts)) {
130
+ throw new Error(`Invalid ISO date string: ${isoString}`);
131
+ }
132
+
133
+ return new OzTime(ts, timezone, locale);
134
+ }
135
+
136
+ /**
137
+ * Создаёт и возвращает экземпляр {@link OzTime} на основе отдельных компонентов даты и времени.
138
+ *
139
+ * @param {number} year - Год.
140
+ * @param {number} month - Месяц от 1 до 12.
141
+ * @param {number} day - День месяца.
142
+ * @param {number} [hour=0] - Час от 0 до 23.
143
+ * @param {number} [minute=0] - Минута от 0 до 59.
144
+ * @param {number} [second=0] - Секунда от 0 до 59.
145
+ * @param {number} [ms=0] - Миллисекунда от 0 до 999.
146
+ * @param {string} [timezone='UTC'] - Часовой пояс в формате IANA.
147
+ * @param {string} [locale='en-US'] - Локаль форматирования.
148
+ * @throws {TypeError} Выбрасывается, если любой числовой параметр не является целым числом.
149
+ * @throws {RangeError} Выбрасывается, если любой компонент даты или времени вне допустимого диапазона.
150
+ * @returns {OzTime} Экземпляр времени.
151
+ * @example
152
+ * import { fromComponents } from '@alexstukovnikov/oz-time';
153
+ *
154
+ * const time = fromComponents(2024, 5, 25, 12, 0, 0, 0, 'UTC', 'ru-RU');
155
+ * console.log(time.toISOString()); // ожидаемый результат: 2024-05-25T12:00:00.000Z
156
+ */
157
+ export function fromComponents(year, month, day, hour = 0, minute = 0, second = 0, ms = 0, timezone = 'UTC', locale = 'en-US') {
158
+ assertInteger(year, 'year');
159
+ assertInteger(month, 'month');
160
+ assertInteger(day, 'day');
161
+ assertInteger(hour, 'hour');
162
+ assertInteger(minute, 'minute');
163
+ assertInteger(second, 'second');
164
+ assertInteger(ms, 'millisecond');
165
+
166
+ if (month < 1 || month > 12) {
167
+ throw new RangeError('month must be between 1 and 12');
168
+ }
169
+
170
+ if (hour < 0 || hour > 23) {
171
+ throw new RangeError('hour must be between 0 and 23');
172
+ }
173
+
174
+ if (minute < 0 || minute > 59) {
175
+ throw new RangeError('minute must be between 0 and 59');
176
+ }
177
+
178
+ if (second < 0 || second > 59) {
179
+ throw new RangeError('second must be between 0 and 59');
180
+ }
181
+
182
+ if (ms < 0 || ms > 999) {
183
+ throw new RangeError('millisecond must be between 0 and 999');
184
+ }
185
+
186
+ const maxDay = daysInMonth(year, month);
187
+
188
+ if (day < 1 || day > maxDay) {
189
+ throw new RangeError(`day must be between 1 and ${maxDay} for ${year}-${month}`);
190
+ }
191
+
192
+ const ts = Date.UTC(year, month - 1, day, hour, minute, second, ms);
193
+ return new OzTime(ts, timezone, locale);
194
+ }
package/src/index.js ADDED
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Публичная точка входа библиотеки OzTime.
3
+ *
4
+ * @module index
5
+ */
6
+
7
+ export { OzTime } from './core/core.js';
8
+ export { now, fromTimestamp, fromDate, fromISO, fromComponents } from './core/factory.js';
9
+
10
+ export { add, subtract } from './modules/arithmetic.js';
11
+
12
+ export { isSame, isBefore, isAfter, isBetween } from './modules/compare.js';
13
+
14
+ export { setTimezone, getTimezoneOffset } from './modules/timezone.js';
15
+
16
+ export { Interval, interval } from './modules/interval.js';
17
+
18
+ export { Duration, duration } from './modules/duration.js';
19
+
20
+ export { format } from './modules/format.js';
21
+
22
+ export { isLeapYear, daysInMonth } from './utils/calendar.js';