@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.
- package/README.md +70 -251
- package/package.json +45 -48
- package/src/core/core.js +509 -0
- package/src/core/factory.js +194 -0
- package/src/index.js +22 -0
- package/src/modules/arithmetic.js +100 -0
- package/src/modules/compare.js +197 -0
- package/src/modules/duration.js +165 -0
- package/src/modules/format.js +162 -0
- package/src/modules/interval.js +190 -0
- package/src/modules/timezone.js +112 -0
- package/src/utils/calendar.js +277 -0
- package/src/utils/units.js +135 -0
- package/dist/oz-time.cjs +0 -1
- package/dist/oz-time.esm.js +0 -426
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { OzTime } from '../core/core.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Модуль форматирования экземпляров {@link OzTime}.
|
|
5
|
+
*
|
|
6
|
+
* @module modules/format
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Проверяет, является ли значение экземпляром OzTime.
|
|
11
|
+
*
|
|
12
|
+
* @private
|
|
13
|
+
* @param {*} value - Проверяемое значение.
|
|
14
|
+
* @throws {TypeError} Выбрасывается, если значение не является экземпляром OzTime.
|
|
15
|
+
* @returns {void}
|
|
16
|
+
*/
|
|
17
|
+
function assertOzTime(value) {
|
|
18
|
+
if (!(value instanceof OzTime)) {
|
|
19
|
+
throw new TypeError('format: first argument must be OzTime');
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Дополняет значение ведущими нулями до нужной длины.
|
|
25
|
+
*
|
|
26
|
+
* @private
|
|
27
|
+
* @param {string|number} value - Исходное значение.
|
|
28
|
+
* @param {number} [length=2] - Итоговая длина строки.
|
|
29
|
+
* @returns {string} Строка, дополненная ведущими нулями.
|
|
30
|
+
*/
|
|
31
|
+
function pad(value, length = 2) {
|
|
32
|
+
return String(value).padStart(length, '0');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Возвращает числовые части даты для форматирования.
|
|
37
|
+
*
|
|
38
|
+
* @private
|
|
39
|
+
* @param {OzTime} time - Экземпляр времени.
|
|
40
|
+
* @param {string} locale - Локаль форматирования.
|
|
41
|
+
* @returns {Object.<string, string>} Объект с числовыми частями даты и времени.
|
|
42
|
+
*/
|
|
43
|
+
function getNumericParts(time, locale) {
|
|
44
|
+
const formatter = new Intl.DateTimeFormat(locale, {
|
|
45
|
+
timeZone: time.getTimezone(),
|
|
46
|
+
year: 'numeric',
|
|
47
|
+
month: 'numeric',
|
|
48
|
+
day: 'numeric',
|
|
49
|
+
hour: 'numeric',
|
|
50
|
+
minute: '2-digit',
|
|
51
|
+
second: '2-digit',
|
|
52
|
+
hour12: false,
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const parts = formatter.formatToParts(new Date(time.getTimestamp()));
|
|
56
|
+
return Object.fromEntries(parts.map((part) => [part.type, part.value]));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Возвращает название месяца в нужном формате.
|
|
61
|
+
*
|
|
62
|
+
* @private
|
|
63
|
+
* @param {OzTime} time - Экземпляр времени.
|
|
64
|
+
* @param {string} locale - Локаль форматирования.
|
|
65
|
+
* @param {'long'|'short'|'narrow'} length - Длина названия месяца.
|
|
66
|
+
* @returns {string} Название месяца.
|
|
67
|
+
*/
|
|
68
|
+
function getMonthName(time, locale, length) {
|
|
69
|
+
return new Intl.DateTimeFormat(locale, {
|
|
70
|
+
timeZone: time.getTimezone(),
|
|
71
|
+
month: length,
|
|
72
|
+
}).format(new Date(time.getTimestamp()));
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Возвращает название дня недели в нужном формате.
|
|
77
|
+
*
|
|
78
|
+
* @private
|
|
79
|
+
* @param {OzTime} time - Экземпляр времени.
|
|
80
|
+
* @param {string} locale - Локаль форматирования.
|
|
81
|
+
* @param {'long'|'short'|'narrow'} length - Длина названия дня недели.
|
|
82
|
+
* @returns {string} Название дня недели.
|
|
83
|
+
*/
|
|
84
|
+
function getWeekdayName(time, locale, length) {
|
|
85
|
+
return new Intl.DateTimeFormat(locale, {
|
|
86
|
+
timeZone: time.getTimezone(),
|
|
87
|
+
weekday: length,
|
|
88
|
+
}).format(new Date(time.getTimestamp()));
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Возвращает строковое представление экземпляра {@link OzTime}
|
|
93
|
+
* по заданному шаблону с токенами.
|
|
94
|
+
*
|
|
95
|
+
* Поддерживаются токены `YYYY`, `YY`, `MMMM`, `MMM`, `MM`, `M`, `dddd`, `ddd`,
|
|
96
|
+
* `DD`, `D`, `HH`, `H`, `hh`, `h`, `mm`, `ss`, `SSS` и `A`.
|
|
97
|
+
*
|
|
98
|
+
* @param {OzTime} time - Экземпляр времени для форматирования.
|
|
99
|
+
* @param {string} template - Шаблон форматирования.
|
|
100
|
+
* @param {string} [locale] - Необязательное переопределение локали.
|
|
101
|
+
* @throws {TypeError} Выбрасывается, если первый аргумент не является экземпляром OzTime или template некорректен.
|
|
102
|
+
* @returns {string} Отформатированная строка.
|
|
103
|
+
* @example
|
|
104
|
+
* import { format, fromISO } from '@alexstukovnikov/oz-time';
|
|
105
|
+
*
|
|
106
|
+
* const time = fromISO('2024-05-25T12:00:00Z', 'UTC', 'ru-RU');
|
|
107
|
+
* console.log(format(time, 'DD.MM.YYYY HH:mm')); // ожидаемый результат: 25.05.2024 12:00
|
|
108
|
+
*/
|
|
109
|
+
export function format(time, template, locale) {
|
|
110
|
+
assertOzTime(time);
|
|
111
|
+
|
|
112
|
+
if (typeof template !== 'string' || template.trim() === '') {
|
|
113
|
+
throw new TypeError('format: template must be a non-empty string');
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const usedLocale = locale ?? time.getLocale();
|
|
117
|
+
const parts = getNumericParts(time, usedLocale);
|
|
118
|
+
|
|
119
|
+
const year = Number(parts.year);
|
|
120
|
+
const month = Number(parts.month);
|
|
121
|
+
const day = Number(parts.day);
|
|
122
|
+
const hour24 = Number(parts.hour);
|
|
123
|
+
const minute = Number(parts.minute);
|
|
124
|
+
const second = Number(parts.second);
|
|
125
|
+
const millisecond = new Date(time.getTimestamp()).getUTCMilliseconds();
|
|
126
|
+
|
|
127
|
+
const hour12base = hour24 % 12;
|
|
128
|
+
const hour12 = hour12base === 0 ? 12 : hour12base;
|
|
129
|
+
const meridiem = hour24 >= 12 ? 'PM' : 'AM';
|
|
130
|
+
|
|
131
|
+
const tokens = {
|
|
132
|
+
YYYY: String(year),
|
|
133
|
+
YY: String(year).slice(-2),
|
|
134
|
+
|
|
135
|
+
MMMM: getMonthName(time, usedLocale, 'long'),
|
|
136
|
+
MMM: getMonthName(time, usedLocale, 'short'),
|
|
137
|
+
MM: pad(month),
|
|
138
|
+
M: String(month),
|
|
139
|
+
|
|
140
|
+
dddd: getWeekdayName(time, usedLocale, 'long'),
|
|
141
|
+
ddd: getWeekdayName(time, usedLocale, 'short'),
|
|
142
|
+
|
|
143
|
+
DD: pad(day),
|
|
144
|
+
D: String(day),
|
|
145
|
+
|
|
146
|
+
HH: pad(hour24),
|
|
147
|
+
H: String(hour24),
|
|
148
|
+
|
|
149
|
+
hh: pad(hour12),
|
|
150
|
+
h: String(hour12),
|
|
151
|
+
|
|
152
|
+
mm: pad(minute),
|
|
153
|
+
ss: pad(second),
|
|
154
|
+
SSS: pad(millisecond, 3),
|
|
155
|
+
|
|
156
|
+
A: meridiem,
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
const tokenPattern = /YYYY|MMMM|MMM|MM|M|dddd|ddd|DD|D|HH|H|hh|h|mm|ss|SSS|YY|A/g;
|
|
160
|
+
|
|
161
|
+
return template.replace(tokenPattern, (token) => tokens[token] ?? token);
|
|
162
|
+
}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import { OzTime } from '../core/core.js';
|
|
2
|
+
import { normalizeUnit, isFixedUnit, unitToMilliseconds } from '../utils/units.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Модуль интервалов времени.
|
|
6
|
+
*
|
|
7
|
+
* @module modules/interval
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Проверяет, является ли значение экземпляром OzTime.
|
|
12
|
+
*
|
|
13
|
+
* @private
|
|
14
|
+
* @param {*} value - Проверяемое значение.
|
|
15
|
+
* @param {string} name - Имя параметра.
|
|
16
|
+
* @throws {TypeError} Выбрасывается, если значение не является экземпляром OzTime.
|
|
17
|
+
* @returns {void}
|
|
18
|
+
*/
|
|
19
|
+
function assertOzTime(value, name) {
|
|
20
|
+
if (!(value instanceof OzTime)) {
|
|
21
|
+
throw new TypeError(`${name} must be OzTime`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Представляет замкнутый интервал между двумя значениями времени.
|
|
27
|
+
*
|
|
28
|
+
* @class
|
|
29
|
+
* @example
|
|
30
|
+
* import { Interval, fromISO } from '@alexstukovnikov/oz-time';
|
|
31
|
+
*
|
|
32
|
+
* const start = fromISO('2024-05-25T10:00:00Z');
|
|
33
|
+
* const end = fromISO('2024-05-25T12:00:00Z');
|
|
34
|
+
* const range = new Interval(start, end);
|
|
35
|
+
* console.log(range.contains(fromISO('2024-05-25T11:00:00Z'))); // ожидаемый результат: true
|
|
36
|
+
*/
|
|
37
|
+
export class Interval {
|
|
38
|
+
/**
|
|
39
|
+
* Создаёт новый экземпляр Interval.
|
|
40
|
+
*
|
|
41
|
+
* @param {OzTime} start - Начало интервала.
|
|
42
|
+
* @param {OzTime} end - Конец интервала.
|
|
43
|
+
* @throws {TypeError} Выбрасывается, если start или end не являются экземплярами OzTime.
|
|
44
|
+
* @throws {RangeError} Выбрасывается, если start больше end.
|
|
45
|
+
*/
|
|
46
|
+
constructor(start, end) {
|
|
47
|
+
assertOzTime(start, 'start');
|
|
48
|
+
assertOzTime(end, 'end');
|
|
49
|
+
|
|
50
|
+
if (start.getTimestamp() > end.getTimestamp()) {
|
|
51
|
+
throw new RangeError('Interval: start must be before or equal to end');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
this._start = start;
|
|
55
|
+
this._end = end;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Возвращает начало интервала.
|
|
60
|
+
*
|
|
61
|
+
* @returns {OzTime} Начальная граница интервала.
|
|
62
|
+
* @example
|
|
63
|
+
* import { Interval, fromISO } from '@alexstukovnikov/oz-time';
|
|
64
|
+
*
|
|
65
|
+
* const range = new Interval(
|
|
66
|
+
* fromISO('2024-05-25T10:00:00Z'),
|
|
67
|
+
* fromISO('2024-05-25T12:00:00Z')
|
|
68
|
+
* );
|
|
69
|
+
* console.log(range.getStart().toISOString()); // ожидаемый результат: 2024-05-25T10:00:00.000Z
|
|
70
|
+
*/
|
|
71
|
+
getStart() {
|
|
72
|
+
return this._start;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Возвращает конец интервала.
|
|
77
|
+
*
|
|
78
|
+
* @returns {OzTime} Конечная граница интервала.
|
|
79
|
+
* @example
|
|
80
|
+
* import { Interval, fromISO } from '@alexstukovnikov/oz-time';
|
|
81
|
+
*
|
|
82
|
+
* const range = new Interval(
|
|
83
|
+
* fromISO('2024-05-25T10:00:00Z'),
|
|
84
|
+
* fromISO('2024-05-25T12:00:00Z')
|
|
85
|
+
* );
|
|
86
|
+
* console.log(range.getEnd().toISOString()); // ожидаемый результат: 2024-05-25T12:00:00.000Z
|
|
87
|
+
*/
|
|
88
|
+
getEnd() {
|
|
89
|
+
return this._end;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Проверяет, содержит ли интервал переданное значение времени.
|
|
94
|
+
*
|
|
95
|
+
* @param {OzTime} moment - Проверяемое значение.
|
|
96
|
+
* @throws {TypeError} Выбрасывается, если moment не является экземпляром OzTime.
|
|
97
|
+
* @returns {boolean} `true`, если значение входит в интервал.
|
|
98
|
+
* @example
|
|
99
|
+
* import { Interval, fromISO } from '@alexstukovnikov/oz-time';
|
|
100
|
+
*
|
|
101
|
+
* const range = new Interval(
|
|
102
|
+
* fromISO('2024-05-25T10:00:00Z'),
|
|
103
|
+
* fromISO('2024-05-25T12:00:00Z')
|
|
104
|
+
* );
|
|
105
|
+
* console.log(range.contains(fromISO('2024-05-25T11:00:00Z'))); // ожидаемый результат: true
|
|
106
|
+
*/
|
|
107
|
+
contains(moment) {
|
|
108
|
+
assertOzTime(moment, 'moment');
|
|
109
|
+
|
|
110
|
+
const ts = moment.getTimestamp();
|
|
111
|
+
return ts >= this._start.getTimestamp() && ts <= this._end.getTimestamp();
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Проверяет, пересекается ли текущий интервал с другим интервалом.
|
|
116
|
+
*
|
|
117
|
+
* @param {Interval} other - Второй интервал.
|
|
118
|
+
* @throws {TypeError} Выбрасывается, если other не является экземпляром Interval.
|
|
119
|
+
* @returns {boolean} `true`, если интервалы пересекаются.
|
|
120
|
+
* @example
|
|
121
|
+
* import { Interval, fromISO } from '@alexstukovnikov/oz-time';
|
|
122
|
+
*
|
|
123
|
+
* const a = new Interval(
|
|
124
|
+
* fromISO('2024-05-25T10:00:00Z'),
|
|
125
|
+
* fromISO('2024-05-25T12:00:00Z')
|
|
126
|
+
* );
|
|
127
|
+
* const b = new Interval(
|
|
128
|
+
* fromISO('2024-05-25T11:00:00Z'),
|
|
129
|
+
* fromISO('2024-05-25T13:00:00Z')
|
|
130
|
+
* );
|
|
131
|
+
* console.log(a.overlaps(b)); // ожидаемый результат: true
|
|
132
|
+
*/
|
|
133
|
+
overlaps(other) {
|
|
134
|
+
if (!(other instanceof Interval)) {
|
|
135
|
+
throw new TypeError('other must be Interval');
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const startA = this._start.getTimestamp();
|
|
139
|
+
const endA = this._end.getTimestamp();
|
|
140
|
+
const startB = other.getStart().getTimestamp();
|
|
141
|
+
const endB = other.getEnd().getTimestamp();
|
|
142
|
+
|
|
143
|
+
return startA <= endB && startB <= endA;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Возвращает длительность интервала в фиксированной единице времени.
|
|
148
|
+
*
|
|
149
|
+
* @param {string} [unit='millisecond'] - Фиксированная единица времени.
|
|
150
|
+
* @throws {Error} Выбрасывается, если unit не является фиксированной единицей времени.
|
|
151
|
+
* @returns {number} Длительность интервала в указанной единице.
|
|
152
|
+
* @example
|
|
153
|
+
* import { Interval, fromISO } from '@alexstukovnikov/oz-time';
|
|
154
|
+
*
|
|
155
|
+
* const range = new Interval(
|
|
156
|
+
* fromISO('2024-05-25T10:00:00Z'),
|
|
157
|
+
* fromISO('2024-05-25T12:00:00Z')
|
|
158
|
+
* );
|
|
159
|
+
* console.log(range.duration('hour')); // ожидаемый результат: 2
|
|
160
|
+
*/
|
|
161
|
+
duration(unit = 'millisecond') {
|
|
162
|
+
const normalizedUnit = normalizeUnit(unit);
|
|
163
|
+
|
|
164
|
+
if (!isFixedUnit(normalizedUnit)) {
|
|
165
|
+
throw new Error(`Interval.duration supports only fixed units: ${unit}`);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const diffMs = this._end.getTimestamp() - this._start.getTimestamp();
|
|
169
|
+
return diffMs / unitToMilliseconds(normalizedUnit);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Создаёт и возвращает экземпляр {@link Interval}.
|
|
175
|
+
*
|
|
176
|
+
* @param {OzTime} start - Начало интервала.
|
|
177
|
+
* @param {OzTime} end - Конец интервала.
|
|
178
|
+
* @returns {Interval} Новый экземпляр Interval.
|
|
179
|
+
* @example
|
|
180
|
+
* import { interval, fromISO } from '@alexstukovnikov/oz-time';
|
|
181
|
+
*
|
|
182
|
+
* const range = interval(
|
|
183
|
+
* fromISO('2024-05-25T10:00:00Z'),
|
|
184
|
+
* fromISO('2024-05-25T12:00:00Z')
|
|
185
|
+
* );
|
|
186
|
+
* console.log(range.duration('hour')); // ожидаемый результат: 2
|
|
187
|
+
*/
|
|
188
|
+
export function interval(start, end) {
|
|
189
|
+
return new Interval(start, end);
|
|
190
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { OzTime } from '../core/core.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Модуль для работы с часовыми поясами.
|
|
5
|
+
*
|
|
6
|
+
* @module modules/timezone
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Проверяет корректность идентификатора часового пояса.
|
|
11
|
+
*
|
|
12
|
+
* @private
|
|
13
|
+
* @param {string} timezone - Идентификатор часового пояса в формате IANA.
|
|
14
|
+
* @throws {TypeError} Выбрасывается, если timezone пустой или не является строкой.
|
|
15
|
+
* @throws {Error} Выбрасывается, если timezone не поддерживается.
|
|
16
|
+
* @returns {void}
|
|
17
|
+
*/
|
|
18
|
+
function validateTimezone(timezone) {
|
|
19
|
+
if (typeof timezone !== 'string' || timezone.trim() === '') {
|
|
20
|
+
throw new TypeError('setTimezone: timezone must be a non-empty string');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (!Intl.supportedValuesOf('timeZone').includes(timezone)) {
|
|
24
|
+
throw new Error(`Unsupported timezone: ${timezone}`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Вычисляет смещение часового пояса относительно UTC для конкретного timestamp.
|
|
30
|
+
*
|
|
31
|
+
* @private
|
|
32
|
+
* @param {number} timestamp - Unix timestamp в миллисекундах.
|
|
33
|
+
* @param {string} timeZone - Часовой пояс в формате IANA.
|
|
34
|
+
* @returns {number} Смещение в минутах относительно UTC.
|
|
35
|
+
*/
|
|
36
|
+
function getOffsetMinutesFor(timestamp, timeZone) {
|
|
37
|
+
const date = new Date(timestamp);
|
|
38
|
+
|
|
39
|
+
const formatter = new Intl.DateTimeFormat('en-US', {
|
|
40
|
+
timeZone,
|
|
41
|
+
year: 'numeric',
|
|
42
|
+
month: '2-digit',
|
|
43
|
+
day: '2-digit',
|
|
44
|
+
hour: '2-digit',
|
|
45
|
+
minute: '2-digit',
|
|
46
|
+
second: '2-digit',
|
|
47
|
+
hour12: false,
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
const parts = formatter.formatToParts(date);
|
|
51
|
+
const lookup = Object.fromEntries(parts.map((p) => [p.type, p.value]));
|
|
52
|
+
|
|
53
|
+
const year = Number(lookup.year);
|
|
54
|
+
const month = Number(lookup.month);
|
|
55
|
+
const day = Number(lookup.day);
|
|
56
|
+
const hour = Number(lookup.hour);
|
|
57
|
+
const minute = Number(lookup.minute);
|
|
58
|
+
const second = Number(lookup.second);
|
|
59
|
+
|
|
60
|
+
const utcTimestamp = Date.UTC(year, month - 1, day, hour, minute, second);
|
|
61
|
+
|
|
62
|
+
return (utcTimestamp - timestamp) / 60000;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Возвращает новый экземпляр {@link OzTime} с тем же timestamp и locale,
|
|
67
|
+
* но с другим часовым поясом.
|
|
68
|
+
*
|
|
69
|
+
* Абсолютный момент времени при этом не изменяется.
|
|
70
|
+
*
|
|
71
|
+
* @param {OzTime} time - Исходный экземпляр {@link OzTime}.
|
|
72
|
+
* @param {string} timezone - Новый часовой пояс в формате IANA.
|
|
73
|
+
* @throws {TypeError} Выбрасывается, если первый аргумент не является экземпляром OzTime или timezone некорректен.
|
|
74
|
+
* @throws {Error} Выбрасывается, если timezone не поддерживается.
|
|
75
|
+
* @returns {OzTime} Новый экземпляр OzTime с другим часовым поясом.
|
|
76
|
+
* @example
|
|
77
|
+
* import { setTimezone, fromISO } from '@alexstukovnikov/oz-time';
|
|
78
|
+
*
|
|
79
|
+
* const time = fromISO('2024-05-25T12:00:00Z', 'UTC', 'ru-RU');
|
|
80
|
+
* const moscow = setTimezone(time, 'Europe/Moscow');
|
|
81
|
+
* console.log(moscow.getTimezone()); // ожидаемый результат: Europe/Moscow
|
|
82
|
+
*/
|
|
83
|
+
export function setTimezone(time, timezone) {
|
|
84
|
+
if (!(time instanceof OzTime)) {
|
|
85
|
+
throw new TypeError('tz: first argument must be OzTime');
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
validateTimezone(timezone);
|
|
89
|
+
|
|
90
|
+
return new OzTime(time.getTimestamp(), timezone, time.getLocale());
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Возвращает смещение часового пояса экземпляра относительно UTC в минутах.
|
|
95
|
+
*
|
|
96
|
+
* @param {OzTime} time - Экземпляр времени.
|
|
97
|
+
* @throws {TypeError} Выбрасывается, если аргумент не является экземпляром OzTime.
|
|
98
|
+
* @returns {number} Смещение в минутах относительно UTC.
|
|
99
|
+
* @example
|
|
100
|
+
* import { getTimezoneOffset, fromISO } from '@alexstukovnikov/oz-time';
|
|
101
|
+
*
|
|
102
|
+
* const time = fromISO('2024-05-25T12:00:00Z', 'Europe/Moscow', 'ru-RU');
|
|
103
|
+
* console.log(getTimezoneOffset(time)); // ожидаемый результат: 180
|
|
104
|
+
*/
|
|
105
|
+
export function getTimezoneOffset(time) {
|
|
106
|
+
if (!(time instanceof OzTime)) {
|
|
107
|
+
throw new TypeError('getTimezoneOffset: argument must be OzTime');
|
|
108
|
+
}
|
|
109
|
+
const timestamp = time.getTimestamp();
|
|
110
|
+
const timeZone = time.getTimezone();
|
|
111
|
+
return getOffsetMinutesFor(timestamp, timeZone);
|
|
112
|
+
}
|