@timestamp-js/core 0.1.0-rc.1 → 0.1.0-rc.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 +17 -1
- package/dist/index.global.js +1550 -0
- package/dist/index.global.min.js +1 -0
- package/package.json +4 -2
|
@@ -0,0 +1,1550 @@
|
|
|
1
|
+
var TimestampJsCore = (function(exports) {
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
4
|
+
|
|
5
|
+
const MILLISECONDS_IN_DAY$1 = 864e5;
|
|
6
|
+
const GREGORIAN_DAYS_IN_MONTH = [
|
|
7
|
+
0,
|
|
8
|
+
31,
|
|
9
|
+
28,
|
|
10
|
+
31,
|
|
11
|
+
30,
|
|
12
|
+
31,
|
|
13
|
+
30,
|
|
14
|
+
31,
|
|
15
|
+
31,
|
|
16
|
+
30,
|
|
17
|
+
31,
|
|
18
|
+
30,
|
|
19
|
+
31
|
|
20
|
+
];
|
|
21
|
+
const GREGORIAN_DAYS_IN_MONTH_LEAP = [
|
|
22
|
+
0,
|
|
23
|
+
31,
|
|
24
|
+
29,
|
|
25
|
+
31,
|
|
26
|
+
30,
|
|
27
|
+
31,
|
|
28
|
+
30,
|
|
29
|
+
31,
|
|
30
|
+
31,
|
|
31
|
+
30,
|
|
32
|
+
31,
|
|
33
|
+
30,
|
|
34
|
+
31
|
|
35
|
+
];
|
|
36
|
+
function padNumber$1(value, length) {
|
|
37
|
+
let padded = String(value);
|
|
38
|
+
while (padded.length < length) padded = "0" + padded;
|
|
39
|
+
return padded;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function formatCalendarDate(date) {
|
|
43
|
+
return `${padNumber$1(date.year, 4)}-${padNumber$1(date.month, 2)}-${padNumber$1(date.day, 2)}`;
|
|
44
|
+
}
|
|
45
|
+
function fromUtcDate(date) {
|
|
46
|
+
return {
|
|
47
|
+
year: date.getUTCFullYear(),
|
|
48
|
+
month: date.getUTCMonth() + 1,
|
|
49
|
+
day: date.getUTCDate()
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
function toGregorianUtcDate(date) {
|
|
53
|
+
return new Date(Date.UTC(date.year, date.month - 1, date.day));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const gregorianCalendar = Object.freeze({
|
|
57
|
+
id: "gregorian",
|
|
58
|
+
intlCalendar: "gregory",
|
|
59
|
+
label: "Gregorian",
|
|
60
|
+
monthsInYear() {
|
|
61
|
+
return 12;
|
|
62
|
+
},
|
|
63
|
+
isLeapYear(year) {
|
|
64
|
+
return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;
|
|
65
|
+
},
|
|
66
|
+
daysInMonth(year, month) {
|
|
67
|
+
return this.isLeapYear(year) ? GREGORIAN_DAYS_IN_MONTH_LEAP[month] : GREGORIAN_DAYS_IN_MONTH[month];
|
|
68
|
+
},
|
|
69
|
+
toEpochDay(date) {
|
|
70
|
+
return Math.floor(Date.UTC(date.year, date.month - 1, date.day) / MILLISECONDS_IN_DAY$1);
|
|
71
|
+
},
|
|
72
|
+
fromEpochDay(epochDay) {
|
|
73
|
+
return fromUtcDate(/* @__PURE__ */ new Date(epochDay * MILLISECONDS_IN_DAY$1));
|
|
74
|
+
},
|
|
75
|
+
addDays(date, amount) {
|
|
76
|
+
return this.fromEpochDay(this.toEpochDay(date) + amount);
|
|
77
|
+
},
|
|
78
|
+
nextDay(date) {
|
|
79
|
+
return this.addDays(date, 1);
|
|
80
|
+
},
|
|
81
|
+
prevDay(date) {
|
|
82
|
+
return this.addDays(date, -1);
|
|
83
|
+
},
|
|
84
|
+
getDayOfYear(date) {
|
|
85
|
+
const yearStart = this.toEpochDay({
|
|
86
|
+
year: date.year,
|
|
87
|
+
month: 1,
|
|
88
|
+
day: 1
|
|
89
|
+
});
|
|
90
|
+
return this.toEpochDay(date) - yearStart + 1;
|
|
91
|
+
},
|
|
92
|
+
getWeekday(date) {
|
|
93
|
+
return toGregorianUtcDate(date).getUTCDay();
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
const PARSE_DATETIME = /^(\d{4})-(\d{1,2})(?:-(\d{1,2}))?(?:[Tt\s]+(\d{1,2})(?::(\d{1,2}))?(?::(\d{1,2})(?:\.(\d{1,3}))?)?)?(?:\s*(Z|[+-]\d{2}:?\d{2}))?$/;
|
|
99
|
+
|
|
100
|
+
const PARSE_DATE = /^(\d{4})-(\d{1,2})(-(\d{1,2}))?/;
|
|
101
|
+
|
|
102
|
+
const PARSE_TIME = /^(\d\d?)(?::(\d\d?))?(?::(\d\d?))?(?:\.(\d{1,3}))?$/;
|
|
103
|
+
|
|
104
|
+
const DAYS_IN_MONTH = [
|
|
105
|
+
0,
|
|
106
|
+
31,
|
|
107
|
+
28,
|
|
108
|
+
31,
|
|
109
|
+
30,
|
|
110
|
+
31,
|
|
111
|
+
30,
|
|
112
|
+
31,
|
|
113
|
+
31,
|
|
114
|
+
30,
|
|
115
|
+
31,
|
|
116
|
+
30,
|
|
117
|
+
31
|
|
118
|
+
];
|
|
119
|
+
|
|
120
|
+
const DAYS_IN_MONTH_LEAP = [
|
|
121
|
+
0,
|
|
122
|
+
31,
|
|
123
|
+
29,
|
|
124
|
+
31,
|
|
125
|
+
30,
|
|
126
|
+
31,
|
|
127
|
+
30,
|
|
128
|
+
31,
|
|
129
|
+
31,
|
|
130
|
+
30,
|
|
131
|
+
31,
|
|
132
|
+
30,
|
|
133
|
+
31
|
|
134
|
+
];
|
|
135
|
+
|
|
136
|
+
const TIME_CONSTANTS = {
|
|
137
|
+
MILLISECONDS_IN: {
|
|
138
|
+
SECOND: 1e3,
|
|
139
|
+
MINUTE: 6e4,
|
|
140
|
+
HOUR: 36e5,
|
|
141
|
+
DAY: 864e5,
|
|
142
|
+
WEEK: 6048e5
|
|
143
|
+
},
|
|
144
|
+
SECONDS_IN: {
|
|
145
|
+
MINUTE: 60,
|
|
146
|
+
HOUR: 3600,
|
|
147
|
+
DAY: 86400,
|
|
148
|
+
WEEK: 604800
|
|
149
|
+
},
|
|
150
|
+
MINUTES_IN: {
|
|
151
|
+
MINUTE: 1,
|
|
152
|
+
HOUR: 60,
|
|
153
|
+
DAY: 1440,
|
|
154
|
+
WEEK: 10080
|
|
155
|
+
},
|
|
156
|
+
HOURS_IN: {
|
|
157
|
+
DAY: 24,
|
|
158
|
+
WEEK: 168
|
|
159
|
+
},
|
|
160
|
+
DAYS_IN: { WEEK: 7 }
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
const DAYS_IN_MONTH_MIN = 28;
|
|
164
|
+
|
|
165
|
+
const DAYS_IN_MONTH_MAX = 31;
|
|
166
|
+
|
|
167
|
+
const MONTH_MAX = 12;
|
|
168
|
+
|
|
169
|
+
const MONTH_MIN = 1;
|
|
170
|
+
|
|
171
|
+
const DAY_MIN = 1;
|
|
172
|
+
|
|
173
|
+
const FIRST_HOUR = 0;
|
|
174
|
+
|
|
175
|
+
const DAYS_IN_WEEK = TIME_CONSTANTS.DAYS_IN.WEEK;
|
|
176
|
+
|
|
177
|
+
const MINUTES_IN_HOUR = TIME_CONSTANTS.MINUTES_IN.HOUR;
|
|
178
|
+
|
|
179
|
+
const HOURS_IN_DAY = TIME_CONSTANTS.HOURS_IN.DAY;
|
|
180
|
+
|
|
181
|
+
const MILLISECONDS_IN_MINUTE = TIME_CONSTANTS.MILLISECONDS_IN.MINUTE;
|
|
182
|
+
|
|
183
|
+
const MILLISECONDS_IN_SECOND = TIME_CONSTANTS.MILLISECONDS_IN.SECOND;
|
|
184
|
+
|
|
185
|
+
const MILLISECONDS_IN_HOUR = TIME_CONSTANTS.MILLISECONDS_IN.HOUR;
|
|
186
|
+
|
|
187
|
+
const MILLISECONDS_IN_DAY = TIME_CONSTANTS.MILLISECONDS_IN.DAY;
|
|
188
|
+
|
|
189
|
+
const MILLISECONDS_IN_WEEK = TIME_CONSTANTS.MILLISECONDS_IN.WEEK;
|
|
190
|
+
|
|
191
|
+
const SECONDS_IN_MINUTE = TIME_CONSTANTS.SECONDS_IN.MINUTE;
|
|
192
|
+
|
|
193
|
+
const SECONDS_IN_HOUR = TIME_CONSTANTS.SECONDS_IN.HOUR;
|
|
194
|
+
|
|
195
|
+
const SECONDS_IN_DAY = TIME_CONSTANTS.SECONDS_IN.DAY;
|
|
196
|
+
|
|
197
|
+
const Timestamp = freezeTimestamp({
|
|
198
|
+
date: "",
|
|
199
|
+
hasDay: false,
|
|
200
|
+
year: 0,
|
|
201
|
+
month: 0,
|
|
202
|
+
day: 0,
|
|
203
|
+
hasTime: false,
|
|
204
|
+
hour: 0,
|
|
205
|
+
minute: 0,
|
|
206
|
+
weekday: 0,
|
|
207
|
+
doy: 0,
|
|
208
|
+
workweek: 0,
|
|
209
|
+
past: false,
|
|
210
|
+
current: false,
|
|
211
|
+
future: false,
|
|
212
|
+
disabled: false
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
const TimeObject = Object.freeze({
|
|
216
|
+
hour: 0,
|
|
217
|
+
minute: 0
|
|
218
|
+
});
|
|
219
|
+
function freezeTimestamp(timestamp) {
|
|
220
|
+
return Object.freeze({ ...timestamp });
|
|
221
|
+
}
|
|
222
|
+
function cloneTimestamp(timestamp) {
|
|
223
|
+
return { ...timestamp };
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function toCalendarDateParts(timestamp) {
|
|
227
|
+
return {
|
|
228
|
+
year: timestamp.year,
|
|
229
|
+
month: timestamp.month,
|
|
230
|
+
day: timestamp.day
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
function getCalendarTimestampOptions(timestamp) {
|
|
234
|
+
return {
|
|
235
|
+
hasTime: timestamp.hasTime,
|
|
236
|
+
hour: timestamp.hour,
|
|
237
|
+
minute: timestamp.minute,
|
|
238
|
+
second: timestamp.second,
|
|
239
|
+
millisecond: timestamp.millisecond,
|
|
240
|
+
timezone: timestamp.timezone
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
function getCalendarWorkWeek(date, calendar) {
|
|
244
|
+
const firstWeekday = calendar.getWeekday({
|
|
245
|
+
year: date.year,
|
|
246
|
+
month: 1,
|
|
247
|
+
day: 1
|
|
248
|
+
});
|
|
249
|
+
return Math.floor((calendar.getDayOfYear(date) + firstWeekday - 1) / 7) + 1;
|
|
250
|
+
}
|
|
251
|
+
function parseMillisecond(value) {
|
|
252
|
+
return value === void 0 ? void 0 : parseInt(value.padEnd(3, "0"), 10);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function validateTimestamp(input) {
|
|
256
|
+
if (typeof input !== "string") return false;
|
|
257
|
+
return PARSE_DATETIME.test(input);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function parsed(input) {
|
|
261
|
+
if (typeof input !== "string") return null;
|
|
262
|
+
const parts = PARSE_DATETIME.exec(input);
|
|
263
|
+
if (!parts || !parts[1] || !parts[2]) return null;
|
|
264
|
+
const year = parseInt(parts[1], 10);
|
|
265
|
+
const month = parseInt(parts[2], 10);
|
|
266
|
+
const day = parseInt(parts[3] || "1", 10);
|
|
267
|
+
const hour = parseInt(parts[4] || "0", 10);
|
|
268
|
+
const minute = parseInt(parts[5] || "0", 10);
|
|
269
|
+
const second = parts[6] === void 0 ? void 0 : parseInt(parts[6], 10);
|
|
270
|
+
const millisecond = parseMillisecond(parts[7]);
|
|
271
|
+
const timestamp = {
|
|
272
|
+
date: input,
|
|
273
|
+
year,
|
|
274
|
+
month,
|
|
275
|
+
day,
|
|
276
|
+
hour,
|
|
277
|
+
minute,
|
|
278
|
+
hasDay: !!parts[3],
|
|
279
|
+
hasTime: true,
|
|
280
|
+
past: false,
|
|
281
|
+
current: false,
|
|
282
|
+
future: false,
|
|
283
|
+
disabled: false,
|
|
284
|
+
weekday: 0,
|
|
285
|
+
doy: 0,
|
|
286
|
+
workweek: 0
|
|
287
|
+
};
|
|
288
|
+
if (second !== void 0) timestamp.second = second;
|
|
289
|
+
if (millisecond !== void 0) timestamp.millisecond = millisecond;
|
|
290
|
+
if (parts[8] !== void 0) timestamp.timezone = parts[8];
|
|
291
|
+
timestamp.time = getTime(timestamp);
|
|
292
|
+
return freezeTimestamp(timestamp);
|
|
293
|
+
}
|
|
294
|
+
function parseDateByMode(date, utc) {
|
|
295
|
+
if (!(date instanceof Date)) return null;
|
|
296
|
+
if (Number.isNaN(date.getTime())) return null;
|
|
297
|
+
const UTC = utc ? "UTC" : "";
|
|
298
|
+
const second = date[`get${UTC}Seconds`]();
|
|
299
|
+
const millisecond = date[`get${UTC}Milliseconds`]();
|
|
300
|
+
const timestamp = {
|
|
301
|
+
date: padNumber(date[`get${UTC}FullYear`](), 4) + "-" + padNumber(date[`get${UTC}Month`]() + 1, 2) + "-" + padNumber(date[`get${UTC}Date`](), 2),
|
|
302
|
+
time: padNumber(date[`get${UTC}Hours`]() || 0, 2) + ":" + padNumber(date[`get${UTC}Minutes`]() || 0, 2),
|
|
303
|
+
year: date[`get${UTC}FullYear`](),
|
|
304
|
+
month: date[`get${UTC}Month`]() + 1,
|
|
305
|
+
day: date[`get${UTC}Date`](),
|
|
306
|
+
hour: date[`get${UTC}Hours`](),
|
|
307
|
+
minute: date[`get${UTC}Minutes`](),
|
|
308
|
+
weekday: 0,
|
|
309
|
+
doy: 0,
|
|
310
|
+
workweek: 0,
|
|
311
|
+
hasDay: true,
|
|
312
|
+
hasTime: true,
|
|
313
|
+
past: false,
|
|
314
|
+
current: false,
|
|
315
|
+
future: false,
|
|
316
|
+
disabled: false
|
|
317
|
+
};
|
|
318
|
+
if (second !== 0) timestamp.second = second;
|
|
319
|
+
if (millisecond !== 0) timestamp.millisecond = millisecond;
|
|
320
|
+
return updateFormatted(timestamp);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
function parseDate(date) {
|
|
324
|
+
return parseDateByMode(date, false);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
function parseDateUTC(date) {
|
|
328
|
+
return parseDateByMode(date, true);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function padNumber(x, length) {
|
|
332
|
+
let padded = String(x);
|
|
333
|
+
while (padded.length < length) padded = "0" + padded;
|
|
334
|
+
return padded;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
function isLeapYear(year) {
|
|
338
|
+
return gregorianCalendar.isLeapYear(year);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
function daysInMonth(year, month) {
|
|
342
|
+
return gregorianCalendar.daysInMonth(year, month);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
function nextDay(timestamp) {
|
|
346
|
+
const date = gregorianCalendar.nextDay(toCalendarDateParts(timestamp));
|
|
347
|
+
return updateFormatted(normalizeTimestamp({
|
|
348
|
+
...timestamp,
|
|
349
|
+
year: date.year,
|
|
350
|
+
month: date.month,
|
|
351
|
+
day: date.day
|
|
352
|
+
}));
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
function prevDay(timestamp) {
|
|
356
|
+
const date = gregorianCalendar.prevDay(toCalendarDateParts(timestamp));
|
|
357
|
+
return updateFormatted(normalizeTimestamp({
|
|
358
|
+
...timestamp,
|
|
359
|
+
year: date.year,
|
|
360
|
+
month: date.month,
|
|
361
|
+
day: date.day
|
|
362
|
+
}));
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
function today() {
|
|
366
|
+
const d = /* @__PURE__ */ new Date(), month = d.getMonth() + 1, day = d.getDate();
|
|
367
|
+
return [
|
|
368
|
+
d.getFullYear(),
|
|
369
|
+
padNumber(month, 2),
|
|
370
|
+
padNumber(day, 2)
|
|
371
|
+
].join("-");
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
function todayUTC(date = /* @__PURE__ */ new Date()) {
|
|
375
|
+
return [
|
|
376
|
+
padNumber(date.getUTCFullYear(), 4),
|
|
377
|
+
padNumber(date.getUTCMonth() + 1, 2),
|
|
378
|
+
padNumber(date.getUTCDate(), 2)
|
|
379
|
+
].join("-");
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
function nowUTC(date = /* @__PURE__ */ new Date()) {
|
|
383
|
+
return parseDateUTC(date);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
function isToday(date) {
|
|
387
|
+
return date === today();
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
function isTodayUTC(date, now = /* @__PURE__ */ new Date()) {
|
|
391
|
+
return date === todayUTC(now);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
function getStartOfWeek(timestamp, weekdays, today) {
|
|
395
|
+
let start = cloneTimestamp(timestamp);
|
|
396
|
+
if (!weekdays) return freezeTimestamp(start);
|
|
397
|
+
if (start.day === 1 || start.weekday === 0) while (!weekdays.includes(Number(start.weekday))) start = nextDay(start);
|
|
398
|
+
start = findWeekday(start, weekdays[0], prevDay);
|
|
399
|
+
start = updateFormatted(start);
|
|
400
|
+
if (today) start = updateRelative(start, today, start.hasTime);
|
|
401
|
+
return start;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
function getEndOfWeek(timestamp, weekdays, today) {
|
|
405
|
+
let end = cloneTimestamp(timestamp);
|
|
406
|
+
if (!weekdays || !Array.isArray(weekdays)) return freezeTimestamp(end);
|
|
407
|
+
if (daysInMonth(end.year, end.month) === end.day || end.weekday === weekdays[weekdays.length - 1]) while (!weekdays.includes(Number(end.weekday))) end = prevDay(end);
|
|
408
|
+
end = findWeekday(end, weekdays[weekdays.length - 1], nextDay);
|
|
409
|
+
end = updateFormatted(end);
|
|
410
|
+
if (today) end = updateRelative(end, today, end.hasTime);
|
|
411
|
+
return end;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
function getStartOfMonth(timestamp) {
|
|
415
|
+
let start = cloneTimestamp(timestamp);
|
|
416
|
+
start.day = 1;
|
|
417
|
+
start = updateFormatted(start);
|
|
418
|
+
return start;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
function getEndOfMonth(timestamp) {
|
|
422
|
+
let end = cloneTimestamp(timestamp);
|
|
423
|
+
end.day = daysInMonth(end.year, end.month);
|
|
424
|
+
end = updateFormatted(end);
|
|
425
|
+
return end;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
function parseTime(input) {
|
|
429
|
+
switch (Object.prototype.toString.call(input)) {
|
|
430
|
+
case "[object Number]": return input;
|
|
431
|
+
case "[object String]": {
|
|
432
|
+
const parts = PARSE_TIME.exec(input);
|
|
433
|
+
if (!parts) return false;
|
|
434
|
+
return parseInt(parts[1], 10) * 60 + parseInt(parts[2] || "0", 10);
|
|
435
|
+
}
|
|
436
|
+
case "[object Object]":
|
|
437
|
+
if (typeof input !== "object" || typeof input.hour !== "number" || typeof input.minute !== "number") return false;
|
|
438
|
+
if (typeof input === "object" && "hour" in input && "minute" in input) return input.hour * 60 + input.minute;
|
|
439
|
+
return false;
|
|
440
|
+
}
|
|
441
|
+
return false;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
function compareTimestamps(ts1, ts2) {
|
|
445
|
+
if (!ts1 || !ts2) return false;
|
|
446
|
+
return ts1.year === ts2.year && ts1.month === ts2.month && ts1.day === ts2.day && ts1.hour === ts2.hour && ts1.minute === ts2.minute && ts1.second === ts2.second && ts1.millisecond === ts2.millisecond && ts1.timezone === ts2.timezone;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
function compareDate(ts1, ts2) {
|
|
450
|
+
return getDate(ts1) === getDate(ts2);
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
function compareTime(ts1, ts2) {
|
|
454
|
+
return getTime(ts1) === getTime(ts2);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
function compareDateTime(ts1, ts2) {
|
|
458
|
+
return getDateTime(ts1) === getDateTime(ts2);
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
function parseTimestamp(input, now = null) {
|
|
462
|
+
let timestamp = parsed(input);
|
|
463
|
+
if (!timestamp) return null;
|
|
464
|
+
timestamp = updateFormatted(timestamp);
|
|
465
|
+
if (now) timestamp = updateRelative(timestamp, now, timestamp.hasTime);
|
|
466
|
+
return timestamp;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
function getDayIdentifier(timestamp) {
|
|
470
|
+
return (timestamp.year ?? 0) * 1e8 + (timestamp.month ?? 0) * 1e6 + (timestamp.day ?? 0) * 1e4;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
function getEpochDay(timestamp, calendar = gregorianCalendar) {
|
|
474
|
+
return calendar.toEpochDay(toCalendarDateParts(timestamp));
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
function getCalendarDayIdentifier(timestamp, calendar = gregorianCalendar) {
|
|
478
|
+
return getEpochDay(timestamp, calendar);
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
function isValidCalendarDate(date, calendar = gregorianCalendar) {
|
|
482
|
+
if (date.year < 1) return false;
|
|
483
|
+
if (date.month < 1 || date.month > calendar.monthsInYear(date.year)) return false;
|
|
484
|
+
return date.day >= 1 && date.day <= calendar.daysInMonth(date.year, date.month);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
function createCalendarTimestamp(date, calendar = gregorianCalendar, options = {}) {
|
|
488
|
+
const timestamp = {
|
|
489
|
+
calendarId: calendar.id,
|
|
490
|
+
date: formatCalendarDate(date),
|
|
491
|
+
hasDay: true,
|
|
492
|
+
year: date.year,
|
|
493
|
+
month: date.month,
|
|
494
|
+
day: date.day,
|
|
495
|
+
hasTime: options.hasTime ?? true,
|
|
496
|
+
hour: options.hour ?? 0,
|
|
497
|
+
minute: options.minute ?? 0,
|
|
498
|
+
past: false,
|
|
499
|
+
current: false,
|
|
500
|
+
future: false,
|
|
501
|
+
disabled: false,
|
|
502
|
+
weekday: calendar.getWeekday(date),
|
|
503
|
+
doy: calendar.getDayOfYear(date),
|
|
504
|
+
workweek: getCalendarWorkWeek(date, calendar)
|
|
505
|
+
};
|
|
506
|
+
if (options.second !== void 0) timestamp.second = options.second;
|
|
507
|
+
if (options.millisecond !== void 0) timestamp.millisecond = options.millisecond;
|
|
508
|
+
if (options.timezone !== void 0) timestamp.timezone = options.timezone;
|
|
509
|
+
timestamp.time = getTime(timestamp);
|
|
510
|
+
const formatted = freezeTimestamp(timestamp);
|
|
511
|
+
return options.now ? updateCalendarRelative(formatted, options.now, calendar, formatted.hasTime) : formatted;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
function parseCalendarTimestamp(input, calendar = gregorianCalendar, now = null) {
|
|
515
|
+
const timestamp = parsed(input);
|
|
516
|
+
if (timestamp === null) return null;
|
|
517
|
+
const date = toCalendarDateParts(timestamp);
|
|
518
|
+
if (isValidCalendarDate(date, calendar) === false) return null;
|
|
519
|
+
return createCalendarTimestamp(date, calendar, {
|
|
520
|
+
...getCalendarTimestampOptions(timestamp),
|
|
521
|
+
now
|
|
522
|
+
});
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
function createCalendarTimestampFromEpochDay(epochDay, calendar = gregorianCalendar, options = {}) {
|
|
526
|
+
return createCalendarTimestamp(calendar.fromEpochDay(epochDay), calendar, options);
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
function updateCalendarFormatted(timestamp, calendar = gregorianCalendar) {
|
|
530
|
+
return createCalendarTimestamp(toCalendarDateParts(timestamp), calendar, getCalendarTimestampOptions(timestamp));
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
function updateCalendarRelative(timestamp, now, calendar = gregorianCalendar, time = false) {
|
|
534
|
+
const ts = cloneTimestamp(timestamp);
|
|
535
|
+
let a = getCalendarDayIdentifier(now, calendar);
|
|
536
|
+
let b = getCalendarDayIdentifier(ts, calendar);
|
|
537
|
+
let current = a === b;
|
|
538
|
+
if (ts.hasTime && time && current) {
|
|
539
|
+
a = getTimeComparisonValue(now);
|
|
540
|
+
b = getTimeComparisonValue(ts);
|
|
541
|
+
current = a === b;
|
|
542
|
+
}
|
|
543
|
+
ts.past = b < a;
|
|
544
|
+
ts.current = current;
|
|
545
|
+
ts.future = b > a;
|
|
546
|
+
ts.currentWeekday = ts.weekday === now.weekday;
|
|
547
|
+
return freezeTimestamp(ts);
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
function nextCalendarDay(timestamp, calendar = gregorianCalendar) {
|
|
551
|
+
return createCalendarTimestamp(calendar.nextDay(toCalendarDateParts(timestamp)), calendar, getCalendarTimestampOptions(timestamp));
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
function prevCalendarDay(timestamp, calendar = gregorianCalendar) {
|
|
555
|
+
return createCalendarTimestamp(calendar.prevDay(toCalendarDateParts(timestamp)), calendar, getCalendarTimestampOptions(timestamp));
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
function addCalendarDays(timestamp, amount, calendar = gregorianCalendar) {
|
|
559
|
+
return createCalendarTimestamp(calendar.addDays(toCalendarDateParts(timestamp), amount), calendar, getCalendarTimestampOptions(timestamp));
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
function addCalendarMonths(timestamp, amount, calendar = gregorianCalendar) {
|
|
563
|
+
let { year, month, day } = toCalendarDateParts(timestamp);
|
|
564
|
+
let remaining = Math.trunc(amount);
|
|
565
|
+
while (remaining > 0) {
|
|
566
|
+
month += 1;
|
|
567
|
+
if (month > calendar.monthsInYear(year)) {
|
|
568
|
+
year += 1;
|
|
569
|
+
month = 1;
|
|
570
|
+
}
|
|
571
|
+
remaining -= 1;
|
|
572
|
+
}
|
|
573
|
+
while (remaining < 0) {
|
|
574
|
+
month -= 1;
|
|
575
|
+
if (month < 1) {
|
|
576
|
+
year -= 1;
|
|
577
|
+
month = calendar.monthsInYear(year);
|
|
578
|
+
}
|
|
579
|
+
remaining += 1;
|
|
580
|
+
}
|
|
581
|
+
day = Math.min(day, calendar.daysInMonth(year, month));
|
|
582
|
+
return createCalendarTimestamp({
|
|
583
|
+
year,
|
|
584
|
+
month,
|
|
585
|
+
day
|
|
586
|
+
}, calendar, getCalendarTimestampOptions(timestamp));
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
function addCalendarYears(timestamp, amount, calendar = gregorianCalendar) {
|
|
590
|
+
let { year, month, day } = toCalendarDateParts(timestamp);
|
|
591
|
+
year += Math.trunc(amount);
|
|
592
|
+
month = Math.min(month, calendar.monthsInYear(year));
|
|
593
|
+
day = Math.min(day, calendar.daysInMonth(year, month));
|
|
594
|
+
return createCalendarTimestamp({
|
|
595
|
+
year,
|
|
596
|
+
month,
|
|
597
|
+
day
|
|
598
|
+
}, calendar, getCalendarTimestampOptions(timestamp));
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
function getCalendarStartOfMonth(timestamp, calendar = gregorianCalendar) {
|
|
602
|
+
return createCalendarTimestamp({
|
|
603
|
+
...toCalendarDateParts(timestamp),
|
|
604
|
+
day: 1
|
|
605
|
+
}, calendar, getCalendarTimestampOptions(timestamp));
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
function getCalendarEndOfMonth(timestamp, calendar = gregorianCalendar) {
|
|
609
|
+
const date = toCalendarDateParts(timestamp);
|
|
610
|
+
return createCalendarTimestamp({
|
|
611
|
+
...date,
|
|
612
|
+
day: calendar.daysInMonth(date.year, date.month)
|
|
613
|
+
}, calendar, getCalendarTimestampOptions(timestamp));
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
function getCalendarStartOfYear(timestamp, calendar = gregorianCalendar) {
|
|
617
|
+
return createCalendarTimestamp({
|
|
618
|
+
year: timestamp.year,
|
|
619
|
+
month: 1,
|
|
620
|
+
day: 1
|
|
621
|
+
}, calendar, getCalendarTimestampOptions(timestamp));
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
function getCalendarEndOfYear(timestamp, calendar = gregorianCalendar) {
|
|
625
|
+
const month = calendar.monthsInYear(timestamp.year);
|
|
626
|
+
return createCalendarTimestamp({
|
|
627
|
+
year: timestamp.year,
|
|
628
|
+
month,
|
|
629
|
+
day: calendar.daysInMonth(timestamp.year, month)
|
|
630
|
+
}, calendar, getCalendarTimestampOptions(timestamp));
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
function findCalendarWeekday(timestamp, weekday, calendar = gregorianCalendar, direction = "next", maxDays = 6) {
|
|
634
|
+
let ts = copyTimestamp(timestamp);
|
|
635
|
+
const mover = direction === "next" ? nextCalendarDay : prevCalendarDay;
|
|
636
|
+
while (ts.weekday !== weekday && --maxDays >= 0) ts = mover(ts, calendar);
|
|
637
|
+
return ts;
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
function getCalendarStartOfWeek(timestamp, weekdays, calendar = gregorianCalendar, now = null) {
|
|
641
|
+
let start = updateCalendarFormatted(timestamp, calendar);
|
|
642
|
+
if (!weekdays || !Array.isArray(weekdays)) return start;
|
|
643
|
+
if (start.day === 1 || start.weekday === 0) while (!weekdays.includes(Number(start.weekday))) start = nextCalendarDay(start, calendar);
|
|
644
|
+
start = findCalendarWeekday(start, weekdays[0], calendar, "prev");
|
|
645
|
+
return now ? updateCalendarRelative(start, now, calendar, start.hasTime) : start;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
function getCalendarEndOfWeek(timestamp, weekdays, calendar = gregorianCalendar, now = null) {
|
|
649
|
+
let end = updateCalendarFormatted(timestamp, calendar);
|
|
650
|
+
if (!weekdays || !Array.isArray(weekdays)) return end;
|
|
651
|
+
if (calendar.daysInMonth(end.year, end.month) === end.day || end.weekday === weekdays[weekdays.length - 1]) while (!weekdays.includes(Number(end.weekday))) end = prevCalendarDay(end, calendar);
|
|
652
|
+
end = findCalendarWeekday(end, weekdays[weekdays.length - 1], calendar, "next");
|
|
653
|
+
return now ? updateCalendarRelative(end, now, calendar, end.hasTime) : end;
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
function createCalendarDayList(start, end, now, calendar = gregorianCalendar, options = {}) {
|
|
657
|
+
const { weekdays = [
|
|
658
|
+
0,
|
|
659
|
+
1,
|
|
660
|
+
2,
|
|
661
|
+
3,
|
|
662
|
+
4,
|
|
663
|
+
5,
|
|
664
|
+
6
|
|
665
|
+
], disabledBefore, disabledAfter, disabledWeekdays = [], disabledDays = [], max = 42, min = 0 } = options;
|
|
666
|
+
const begin = getCalendarDayIdentifier(start, calendar);
|
|
667
|
+
const stop = getCalendarDayIdentifier(end, calendar);
|
|
668
|
+
const days = [];
|
|
669
|
+
let current = updateCalendarFormatted(start, calendar);
|
|
670
|
+
let currentIdentifier = 0;
|
|
671
|
+
let stopped = currentIdentifier === stop;
|
|
672
|
+
if (stop < begin) return days;
|
|
673
|
+
while ((!stopped || days.length < min) && days.length < max) {
|
|
674
|
+
currentIdentifier = getCalendarDayIdentifier(current, calendar);
|
|
675
|
+
stopped = stopped || currentIdentifier > stop && days.length >= min;
|
|
676
|
+
if (stopped) break;
|
|
677
|
+
if (!weekdays.includes(Number(current.weekday))) {
|
|
678
|
+
current = nextCalendarDay(current, calendar);
|
|
679
|
+
continue;
|
|
680
|
+
}
|
|
681
|
+
let day = updateCalendarFormatted(current, calendar);
|
|
682
|
+
day = updateCalendarRelative(day, now, calendar);
|
|
683
|
+
day = updateDisabled(day, disabledBefore, disabledAfter, disabledWeekdays, disabledDays);
|
|
684
|
+
days.push(day);
|
|
685
|
+
current = nextCalendarDay(current, calendar);
|
|
686
|
+
}
|
|
687
|
+
return days;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
function getTimeIdentifier(timestamp) {
|
|
691
|
+
return (timestamp.hour ?? 0) * 100 + (timestamp.minute ?? 0);
|
|
692
|
+
}
|
|
693
|
+
function getTimeComparisonValue(timestamp) {
|
|
694
|
+
return (((timestamp.hour ?? 0) * TIME_CONSTANTS.MINUTES_IN.HOUR + (timestamp.minute ?? 0)) * TIME_CONSTANTS.SECONDS_IN.MINUTE + (timestamp.second ?? 0)) * TIME_CONSTANTS.MILLISECONDS_IN.SECOND + (timestamp.millisecond ?? 0);
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
function getDayTimeIdentifier(timestamp) {
|
|
698
|
+
return getDayIdentifier(timestamp) + getTimeIdentifier(timestamp);
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
function diffTimestamp(ts1, ts2, strict = false) {
|
|
702
|
+
const utc1 = Date.UTC(ts1.year ?? 0, (ts1.month ?? 1) - 1, ts1.day ?? 1, ts1.hour ?? 0, ts1.minute ?? 0, ts1.second ?? 0, ts1.millisecond ?? 0);
|
|
703
|
+
const utc2 = Date.UTC(ts2.year ?? 0, (ts2.month ?? 1) - 1, ts2.day ?? 1, ts2.hour ?? 0, ts2.minute ?? 0, ts2.second ?? 0, ts2.millisecond ?? 0);
|
|
704
|
+
if (strict === true && utc2 < utc1) return 0;
|
|
705
|
+
return utc2 - utc1;
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
function updateRelative(timestamp, now, time = false) {
|
|
709
|
+
const ts = cloneTimestamp(timestamp);
|
|
710
|
+
let a = getDayIdentifier(now);
|
|
711
|
+
let b = getDayIdentifier(ts);
|
|
712
|
+
let current = a === b;
|
|
713
|
+
if (ts.hasTime && time && current) {
|
|
714
|
+
a = getTimeComparisonValue(now);
|
|
715
|
+
b = getTimeComparisonValue(ts);
|
|
716
|
+
current = a === b;
|
|
717
|
+
}
|
|
718
|
+
ts.past = b < a;
|
|
719
|
+
ts.current = current;
|
|
720
|
+
ts.future = b > a;
|
|
721
|
+
ts.currentWeekday = ts.weekday === now.weekday;
|
|
722
|
+
return freezeTimestamp(ts);
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
function updateMinutes(timestamp, minutes, now = null) {
|
|
726
|
+
let ts = cloneTimestamp(timestamp);
|
|
727
|
+
ts.hasTime = true;
|
|
728
|
+
ts.hour = Math.floor(minutes / TIME_CONSTANTS.MINUTES_IN.HOUR);
|
|
729
|
+
ts.minute = minutes % TIME_CONSTANTS.MINUTES_IN.HOUR;
|
|
730
|
+
delete ts.second;
|
|
731
|
+
delete ts.millisecond;
|
|
732
|
+
ts.time = getTime(ts);
|
|
733
|
+
if (now) return updateRelative(ts, now, true);
|
|
734
|
+
return freezeTimestamp(ts);
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
function updateWeekday(timestamp) {
|
|
738
|
+
const ts = cloneTimestamp(timestamp);
|
|
739
|
+
ts.weekday = getWeekday(ts);
|
|
740
|
+
return freezeTimestamp(ts);
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
function updateDayOfYear(timestamp) {
|
|
744
|
+
const ts = cloneTimestamp(timestamp);
|
|
745
|
+
ts.doy = getDayOfYear(ts) || 0;
|
|
746
|
+
return freezeTimestamp(ts);
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
function updateWorkWeek(timestamp) {
|
|
750
|
+
const ts = cloneTimestamp(timestamp);
|
|
751
|
+
ts.workweek = getWorkWeek(ts);
|
|
752
|
+
return freezeTimestamp(ts);
|
|
753
|
+
}
|
|
754
|
+
function isDisabledDayConfig(value) {
|
|
755
|
+
return typeof value === "object" && value !== null && Array.isArray(value) === false;
|
|
756
|
+
}
|
|
757
|
+
function applyDisabledDayConfig(timestamp, config) {
|
|
758
|
+
timestamp.disabled = true;
|
|
759
|
+
if (config !== void 0) {
|
|
760
|
+
timestamp.disabledColor = config.color;
|
|
761
|
+
timestamp.disabledTextColor = config.textColor;
|
|
762
|
+
timestamp.disabledClass = config.class;
|
|
763
|
+
timestamp.disabledStyle = config.style;
|
|
764
|
+
timestamp.disabledLabel = config.label;
|
|
765
|
+
}
|
|
766
|
+
return timestamp;
|
|
767
|
+
}
|
|
768
|
+
function isTimestampInDisabledDay(timestamp, day) {
|
|
769
|
+
const target = getDayIdentifier(timestamp);
|
|
770
|
+
if (Array.isArray(day) === true) {
|
|
771
|
+
if (day.length === 2 && day[0] && day[1]) {
|
|
772
|
+
const start = parsed(day[0]);
|
|
773
|
+
const end = parsed(day[1]);
|
|
774
|
+
return start !== null && end !== null && isBetweenDates(timestamp, start, end);
|
|
775
|
+
}
|
|
776
|
+
return day.some((date) => {
|
|
777
|
+
const disabledDay = parseTimestamp(date);
|
|
778
|
+
return disabledDay !== null && getDayIdentifier(disabledDay) === target;
|
|
779
|
+
});
|
|
780
|
+
}
|
|
781
|
+
if (isDisabledDayConfig(day) === true) {
|
|
782
|
+
const date = day.date;
|
|
783
|
+
const startDate = day.from ?? day.start;
|
|
784
|
+
const endDate = day.to ?? day.end;
|
|
785
|
+
if (date !== void 0) {
|
|
786
|
+
const disabledDay = parseTimestamp(date);
|
|
787
|
+
return disabledDay !== null && getDayIdentifier(disabledDay) === target;
|
|
788
|
+
}
|
|
789
|
+
if (startDate !== void 0 && endDate !== void 0) {
|
|
790
|
+
const start = parsed(startDate);
|
|
791
|
+
const end = parsed(endDate);
|
|
792
|
+
return start !== null && end !== null && isBetweenDates(timestamp, start, end);
|
|
793
|
+
}
|
|
794
|
+
return false;
|
|
795
|
+
}
|
|
796
|
+
const disabledDay = parseTimestamp(day);
|
|
797
|
+
return disabledDay !== null && getDayIdentifier(disabledDay) === target;
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
function updateDisabled(timestamp, disabledBefore, disabledAfter, disabledWeekdays, disabledDays) {
|
|
801
|
+
let ts = cloneTimestamp(timestamp);
|
|
802
|
+
const t = getDayIdentifier(ts);
|
|
803
|
+
if (disabledBefore !== void 0) {
|
|
804
|
+
const disabledDay = parsed(disabledBefore);
|
|
805
|
+
if (disabledDay) {
|
|
806
|
+
if (t <= getDayIdentifier(disabledDay)) ts.disabled = true;
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
if (ts.disabled !== true && disabledAfter !== void 0) {
|
|
810
|
+
const disabledDay = parsed(disabledAfter);
|
|
811
|
+
if (disabledDay) {
|
|
812
|
+
if (t >= getDayIdentifier(disabledDay)) ts.disabled = true;
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
if (ts.disabled !== true && Array.isArray(disabledWeekdays) && disabledWeekdays.length > 0) {
|
|
816
|
+
for (const weekday in disabledWeekdays) if (disabledWeekdays[weekday] === ts.weekday) {
|
|
817
|
+
ts.disabled = true;
|
|
818
|
+
break;
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
if (ts.disabled !== true && Array.isArray(disabledDays) && disabledDays.length > 0) {
|
|
822
|
+
for (const day of disabledDays) if (isTimestampInDisabledDay(ts, day) === true) {
|
|
823
|
+
ts = applyDisabledDayConfig(ts, isDisabledDayConfig(day) === true ? day : void 0);
|
|
824
|
+
break;
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
return freezeTimestamp(ts);
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
function updateFormatted(timestamp) {
|
|
831
|
+
const ts = cloneTimestamp(timestamp);
|
|
832
|
+
ts.hasTime = true;
|
|
833
|
+
ts.time = getTime(ts);
|
|
834
|
+
ts.date = getDate(ts);
|
|
835
|
+
ts.weekday = getWeekday(ts);
|
|
836
|
+
ts.doy = getDayOfYear(ts) || 0;
|
|
837
|
+
ts.workweek = getWorkWeek(ts);
|
|
838
|
+
return freezeTimestamp(ts);
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
function getDayOfYear(timestamp) {
|
|
842
|
+
if (timestamp.year === 0) return;
|
|
843
|
+
return gregorianCalendar.getDayOfYear(toCalendarDateParts(timestamp));
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
function getWorkWeek(timestamp) {
|
|
847
|
+
let ts = timestamp;
|
|
848
|
+
if (ts.year === 0) {
|
|
849
|
+
const parsedToday = parseTimestamp(today());
|
|
850
|
+
if (parsedToday) ts = parsedToday;
|
|
851
|
+
}
|
|
852
|
+
const weekday = new Date(Date.UTC(ts.year, ts.month - 1, ts.day));
|
|
853
|
+
const dayAdjustment = 4;
|
|
854
|
+
weekday.setUTCDate(weekday.getUTCDate() - (weekday.getUTCDay() + 6) % 7 + dayAdjustment);
|
|
855
|
+
weekday.setUTCDate(weekday.getUTCDate() + dayAdjustment - (weekday.getUTCDay() || 7));
|
|
856
|
+
var yearStart = new Date(Date.UTC(weekday.getUTCFullYear(), 0, 1));
|
|
857
|
+
return Math.ceil(((weekday.valueOf() - yearStart.valueOf()) / 864e5 + 1) / 7);
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
function getWeekday(timestamp) {
|
|
861
|
+
let weekday = timestamp.weekday;
|
|
862
|
+
if (timestamp.hasDay) weekday = gregorianCalendar.getWeekday(toCalendarDateParts(timestamp));
|
|
863
|
+
return weekday ?? 0;
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
function copyTimestamp(timestamp) {
|
|
867
|
+
return freezeTimestamp(timestamp);
|
|
868
|
+
}
|
|
869
|
+
function setTimeParts(timestamp, hour, minute, second, millisecond) {
|
|
870
|
+
const ts = cloneTimestamp(timestamp);
|
|
871
|
+
ts.hasTime = true;
|
|
872
|
+
ts.hour = hour;
|
|
873
|
+
ts.minute = minute;
|
|
874
|
+
if (second === void 0) delete ts.second;
|
|
875
|
+
else ts.second = second;
|
|
876
|
+
if (millisecond === void 0) delete ts.millisecond;
|
|
877
|
+
else ts.millisecond = millisecond;
|
|
878
|
+
return updateFormatted(ts);
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
function getStartOfDay(timestamp) {
|
|
882
|
+
return setTimeParts(timestamp, 0, 0);
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
function getEndOfDay(timestamp) {
|
|
886
|
+
return setTimeParts(timestamp, 23, 59, 59, 999);
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
function getStartOfYear(timestamp) {
|
|
890
|
+
const ts = cloneTimestamp(timestamp);
|
|
891
|
+
ts.month = 1;
|
|
892
|
+
ts.day = 1;
|
|
893
|
+
return getStartOfDay(updateFormatted(ts));
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
function getEndOfYear(timestamp) {
|
|
897
|
+
const ts = cloneTimestamp(timestamp);
|
|
898
|
+
ts.month = 12;
|
|
899
|
+
ts.day = daysInMonth(ts.year, 12);
|
|
900
|
+
return getEndOfDay(updateFormatted(ts));
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
function getDate(timestamp) {
|
|
904
|
+
let str = `${padNumber(timestamp.year, 4)}-${padNumber(timestamp.month, 2)}`;
|
|
905
|
+
if (timestamp.hasDay) str += `-${padNumber(timestamp.day, 2)}`;
|
|
906
|
+
return str;
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
function getTime(timestamp) {
|
|
910
|
+
if (!timestamp.hasTime) return "";
|
|
911
|
+
let time = `${padNumber(timestamp.hour, 2)}:${padNumber(timestamp.minute, 2)}`;
|
|
912
|
+
if (timestamp.second !== void 0 || timestamp.millisecond !== void 0) time += `:${padNumber(timestamp.second ?? 0, 2)}`;
|
|
913
|
+
if (timestamp.millisecond !== void 0) time += `.${padNumber(timestamp.millisecond, 3)}`;
|
|
914
|
+
return time;
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
function getDateTime(timestamp) {
|
|
918
|
+
return getDate(timestamp) + " " + (timestamp.hasTime ? getTime(timestamp) : "00:00");
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
function moveRelativeDays(timestamp, mover = nextDay, days = 1, allowedWeekdays = [
|
|
922
|
+
0,
|
|
923
|
+
1,
|
|
924
|
+
2,
|
|
925
|
+
3,
|
|
926
|
+
4,
|
|
927
|
+
5,
|
|
928
|
+
6
|
|
929
|
+
]) {
|
|
930
|
+
return relativeDays(timestamp, mover, days, allowedWeekdays);
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
function relativeDays(timestamp, mover = nextDay, days = 1, allowedWeekdays = [
|
|
934
|
+
0,
|
|
935
|
+
1,
|
|
936
|
+
2,
|
|
937
|
+
3,
|
|
938
|
+
4,
|
|
939
|
+
5,
|
|
940
|
+
6
|
|
941
|
+
]) {
|
|
942
|
+
let ts = copyTimestamp(timestamp);
|
|
943
|
+
if (!allowedWeekdays.includes(Number(ts.weekday)) && ts.weekday === 0 && mover === nextDay) ++days;
|
|
944
|
+
while (--days >= 0) {
|
|
945
|
+
ts = mover(ts);
|
|
946
|
+
if (allowedWeekdays.length < 7 && !allowedWeekdays.includes(Number(ts.weekday))) ++days;
|
|
947
|
+
}
|
|
948
|
+
return ts;
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
function findWeekday(timestamp, weekday, mover = nextDay, maxDays = 6) {
|
|
952
|
+
let ts = copyTimestamp(timestamp);
|
|
953
|
+
while (ts.weekday !== weekday && --maxDays >= 0) ts = mover(ts);
|
|
954
|
+
return ts;
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
function createDayList(start, end, now, weekdays = [
|
|
958
|
+
0,
|
|
959
|
+
1,
|
|
960
|
+
2,
|
|
961
|
+
3,
|
|
962
|
+
4,
|
|
963
|
+
5,
|
|
964
|
+
6
|
|
965
|
+
], disabledBefore = void 0, disabledAfter = void 0, disabledWeekdays = [], disabledDays = [], max = 42, min = 0) {
|
|
966
|
+
const begin = getDayIdentifier(start);
|
|
967
|
+
const stop = getDayIdentifier(end);
|
|
968
|
+
const days = [];
|
|
969
|
+
let current = copyTimestamp(start);
|
|
970
|
+
let currentIdentifier = 0;
|
|
971
|
+
let stopped = currentIdentifier === stop;
|
|
972
|
+
if (stop < begin) return days;
|
|
973
|
+
while ((!stopped || days.length < min) && days.length < max) {
|
|
974
|
+
currentIdentifier = getDayIdentifier(current);
|
|
975
|
+
stopped = stopped || currentIdentifier > stop && days.length >= min;
|
|
976
|
+
if (stopped) break;
|
|
977
|
+
if (!weekdays.includes(Number(current.weekday))) {
|
|
978
|
+
current = relativeDays(current, nextDay);
|
|
979
|
+
continue;
|
|
980
|
+
}
|
|
981
|
+
let day = copyTimestamp(current);
|
|
982
|
+
day = updateFormatted(day);
|
|
983
|
+
day = updateRelative(day, now);
|
|
984
|
+
day = updateDisabled(day, disabledBefore, disabledAfter, disabledWeekdays, disabledDays);
|
|
985
|
+
days.push(day);
|
|
986
|
+
current = relativeDays(current, nextDay);
|
|
987
|
+
}
|
|
988
|
+
return days;
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
function createIntervalList(timestamp, first, minutes, count, now) {
|
|
992
|
+
const intervals = [];
|
|
993
|
+
for (let i = 0; i < count; ++i) {
|
|
994
|
+
const mins = (first + i) * minutes;
|
|
995
|
+
intervals.push(updateMinutes(timestamp, mins, now));
|
|
996
|
+
}
|
|
997
|
+
return intervals;
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
|
|
1001
|
+
function createNativeLocaleFormatterByMode(locale, cb, toDate) {
|
|
1002
|
+
const emptyFormatter = () => "";
|
|
1003
|
+
if (typeof Intl === "undefined" || typeof Intl.DateTimeFormat === "undefined") return emptyFormatter;
|
|
1004
|
+
return (timestamp, short) => {
|
|
1005
|
+
try {
|
|
1006
|
+
return new Intl.DateTimeFormat(locale || void 0, cb(timestamp, short)).format(toDate(timestamp));
|
|
1007
|
+
} catch (e) {
|
|
1008
|
+
console.error(`Intl.DateTimeFormat: ${e.message} -> ${getDateTime(timestamp)}`);
|
|
1009
|
+
return "";
|
|
1010
|
+
}
|
|
1011
|
+
};
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
function createNativeLocaleFormatter(locale, cb) {
|
|
1015
|
+
return createNativeLocaleFormatterByMode(locale, cb, makeDateTime);
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
function createNativeLocaleFormatterUTC(locale, cb) {
|
|
1019
|
+
return createNativeLocaleFormatterByMode(locale, cb, makeDateTimeUTC);
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
function createCalendarLocaleFormatterUTC(calendar, locale, cb) {
|
|
1023
|
+
return createNativeLocaleFormatterByMode(locale, (timestamp, short) => {
|
|
1024
|
+
const options = cb(timestamp, short);
|
|
1025
|
+
const resolvedOptions = options.timeZone === void 0 ? {
|
|
1026
|
+
...options,
|
|
1027
|
+
timeZone: "UTC"
|
|
1028
|
+
} : options;
|
|
1029
|
+
if (calendar.intlCalendar === void 0 || resolvedOptions.calendar !== void 0) return resolvedOptions;
|
|
1030
|
+
return {
|
|
1031
|
+
...resolvedOptions,
|
|
1032
|
+
calendar: calendar.intlCalendar
|
|
1033
|
+
};
|
|
1034
|
+
}, (timestamp) => makeCalendarDateTimeUTC(timestamp, calendar));
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
function makeDate(timestamp) {
|
|
1038
|
+
return new Date(timestamp.year, timestamp.month - 1, timestamp.day, 0, 0);
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
function makeDateUTC(timestamp) {
|
|
1042
|
+
return new Date(Date.UTC(timestamp.year, timestamp.month - 1, timestamp.day, 0, 0));
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
function makeCalendarDateUTC(timestamp, calendar = gregorianCalendar) {
|
|
1046
|
+
const date = gregorianCalendar.fromEpochDay(getCalendarDayIdentifier(timestamp, calendar));
|
|
1047
|
+
return new Date(Date.UTC(date.year, date.month - 1, date.day, 0, 0));
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
function makeDateTime(timestamp) {
|
|
1051
|
+
return new Date(timestamp.year, timestamp.month - 1, timestamp.day, timestamp.hour, timestamp.minute, timestamp.second ?? 0, timestamp.millisecond ?? 0);
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
function makeCalendarDateTimeUTC(timestamp, calendar = gregorianCalendar) {
|
|
1055
|
+
const date = gregorianCalendar.fromEpochDay(getCalendarDayIdentifier(timestamp, calendar));
|
|
1056
|
+
return new Date(Date.UTC(date.year, date.month - 1, date.day, timestamp.hour, timestamp.minute, timestamp.second ?? 0, timestamp.millisecond ?? 0));
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
function makeDateTimeUTC(timestamp) {
|
|
1060
|
+
return new Date(Date.UTC(timestamp.year, timestamp.month - 1, timestamp.day, timestamp.hour, timestamp.minute, timestamp.second ?? 0, timestamp.millisecond ?? 0));
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
function toUnixMilliseconds(timestamp) {
|
|
1064
|
+
return makeDateTimeUTC(timestamp).getTime();
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
function toUnixSeconds(timestamp) {
|
|
1068
|
+
return Math.floor(toUnixMilliseconds(timestamp) / MILLISECONDS_IN_SECOND);
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
function fromUnixMilliseconds(milliseconds) {
|
|
1072
|
+
return parseDateUTC(new Date(milliseconds));
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
function fromUnixSeconds(seconds) {
|
|
1076
|
+
return fromUnixMilliseconds(seconds * MILLISECONDS_IN_SECOND);
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
function getDateObject(timestamp) {
|
|
1080
|
+
return makeDateTime(timestamp);
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
function validateNumber(input) {
|
|
1084
|
+
return isFinite(Number(input));
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
function maxTimestamp(timestamps, useTime = false) {
|
|
1088
|
+
const func = useTime === true ? getDayTimeIdentifier : getDayIdentifier;
|
|
1089
|
+
return timestamps.reduce((prev, cur) => {
|
|
1090
|
+
return Math.max(func(prev), func(cur)) === func(prev) ? prev : cur;
|
|
1091
|
+
});
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
function minTimestamp(timestamps, useTime = false) {
|
|
1095
|
+
const func = useTime === true ? getDayTimeIdentifier : getDayIdentifier;
|
|
1096
|
+
return timestamps.reduce((prev, cur) => {
|
|
1097
|
+
return Math.min(func(prev), func(cur)) === func(prev) ? prev : cur;
|
|
1098
|
+
});
|
|
1099
|
+
}
|
|
1100
|
+
function getTimestampSortValue(timestamp, useTime) {
|
|
1101
|
+
if (useTime === true) return toUnixMilliseconds(timestamp);
|
|
1102
|
+
return getEpochDay(timestamp) * MILLISECONDS_IN_DAY;
|
|
1103
|
+
}
|
|
1104
|
+
function compareTimestampOrder(first, second, useTime) {
|
|
1105
|
+
return getTimestampSortValue(first, useTime) - getTimestampSortValue(second, useTime);
|
|
1106
|
+
}
|
|
1107
|
+
function createFrozenRange(start, end) {
|
|
1108
|
+
return Object.freeze({
|
|
1109
|
+
start: copyTimestamp(start),
|
|
1110
|
+
end: copyTimestamp(end)
|
|
1111
|
+
});
|
|
1112
|
+
}
|
|
1113
|
+
function isRangeTouchingOrOverlapping(first, second, useTime) {
|
|
1114
|
+
const step = useTime ? 1 : MILLISECONDS_IN_DAY;
|
|
1115
|
+
return getTimestampSortValue(second.start, useTime) <= getTimestampSortValue(first.end, useTime) + step;
|
|
1116
|
+
}
|
|
1117
|
+
function moveBoundary(timestamp, amount, useTime) {
|
|
1118
|
+
if (useTime === true) return fromUnixMilliseconds(toUnixMilliseconds(timestamp) + amount);
|
|
1119
|
+
return addToDate(timestamp, { day: amount });
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
function createTimestampRange(start, end, useTime = false) {
|
|
1123
|
+
if (compareTimestampOrder(start, end, useTime) <= 0) return createFrozenRange(start, end);
|
|
1124
|
+
return createFrozenRange(end, start);
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
function isTimestampInRange(timestamp, range, useTime = false) {
|
|
1128
|
+
return isBetweenDates(timestamp, range.start, range.end, useTime);
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
function isRangeOverlapping(first, second, useTime = false) {
|
|
1132
|
+
const firstRange = createTimestampRange(first.start, first.end, useTime);
|
|
1133
|
+
const secondRange = createTimestampRange(second.start, second.end, useTime);
|
|
1134
|
+
return getTimestampSortValue(firstRange.start, useTime) <= getTimestampSortValue(secondRange.end, useTime) && getTimestampSortValue(secondRange.start, useTime) <= getTimestampSortValue(firstRange.end, useTime);
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
function intersectRanges(first, second, useTime = false) {
|
|
1138
|
+
if (isRangeOverlapping(first, second, useTime) === false) return null;
|
|
1139
|
+
return createTimestampRange(compareTimestampOrder(first.start, second.start, useTime) >= 0 ? first.start : second.start, compareTimestampOrder(first.end, second.end, useTime) <= 0 ? first.end : second.end, useTime);
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
function mergeRanges(ranges, useTime = false) {
|
|
1143
|
+
const sorted = ranges.map((range) => createTimestampRange(range.start, range.end, useTime)).sort((a, b) => compareTimestampOrder(a.start, b.start, useTime));
|
|
1144
|
+
const merged = [];
|
|
1145
|
+
for (const range of sorted) {
|
|
1146
|
+
const last = merged[merged.length - 1];
|
|
1147
|
+
if (last === void 0 || isRangeTouchingOrOverlapping(last, range, useTime) === false) {
|
|
1148
|
+
merged.push(range);
|
|
1149
|
+
continue;
|
|
1150
|
+
}
|
|
1151
|
+
const end = compareTimestampOrder(last.end, range.end, useTime) >= 0 ? last.end : range.end;
|
|
1152
|
+
merged[merged.length - 1] = createFrozenRange(last.start, end);
|
|
1153
|
+
}
|
|
1154
|
+
return merged;
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1157
|
+
function subtractRanges(source, blocked, useTime = false) {
|
|
1158
|
+
const normalizedSource = createTimestampRange(source.start, source.end, useTime);
|
|
1159
|
+
const blockers = mergeRanges(blocked, useTime);
|
|
1160
|
+
let available = [normalizedSource];
|
|
1161
|
+
for (const blocker of blockers) {
|
|
1162
|
+
const nextAvailable = [];
|
|
1163
|
+
for (const range of available) {
|
|
1164
|
+
const overlap = intersectRanges(range, blocker, useTime);
|
|
1165
|
+
if (overlap === null) {
|
|
1166
|
+
nextAvailable.push(range);
|
|
1167
|
+
continue;
|
|
1168
|
+
}
|
|
1169
|
+
if (compareTimestampOrder(range.start, overlap.start, useTime) < 0) nextAvailable.push(createTimestampRange(range.start, moveBoundary(overlap.start, -1, useTime), useTime));
|
|
1170
|
+
if (compareTimestampOrder(overlap.end, range.end, useTime) < 0) nextAvailable.push(createTimestampRange(moveBoundary(overlap.end, 1, useTime), range.end, useTime));
|
|
1171
|
+
}
|
|
1172
|
+
available = nextAvailable;
|
|
1173
|
+
}
|
|
1174
|
+
return available;
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
function findRangeGaps(source, occupied, useTime = false) {
|
|
1178
|
+
return subtractRanges(source, occupied, useTime);
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
function isBetweenDates(timestamp, startTimestamp, endTimestamp, useTime = false) {
|
|
1182
|
+
const cd = getDayIdentifier(timestamp) + (useTime === true ? getTimeIdentifier(timestamp) : 0);
|
|
1183
|
+
const sd = getDayIdentifier(startTimestamp) + (useTime === true ? getTimeIdentifier(startTimestamp) : 0);
|
|
1184
|
+
const ed = getDayIdentifier(endTimestamp) + (useTime === true ? getTimeIdentifier(endTimestamp) : 0);
|
|
1185
|
+
return cd >= sd && cd <= ed;
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
function isOverlappingDates(startTimestamp, endTimestamp, firstTimestamp, lastTimestamp) {
|
|
1189
|
+
const start = getDayIdentifier(startTimestamp);
|
|
1190
|
+
const end = getDayIdentifier(endTimestamp);
|
|
1191
|
+
const first = getDayIdentifier(firstTimestamp);
|
|
1192
|
+
const last = getDayIdentifier(lastTimestamp);
|
|
1193
|
+
return start >= first && start <= last || end >= first && end <= last || first >= start && end >= last;
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
function addToDate(timestamp, options) {
|
|
1197
|
+
const ts = cloneTimestamp(timestamp);
|
|
1198
|
+
if (options.year) ts.year += options.year;
|
|
1199
|
+
if (options.month) ts.month += options.month;
|
|
1200
|
+
if (options.day) ts.day += options.day;
|
|
1201
|
+
if (options.hour) ts.hour += options.hour;
|
|
1202
|
+
if (options.minute) ts.minute += options.minute;
|
|
1203
|
+
if (options.second) ts.second = (ts.second ?? 0) + options.second;
|
|
1204
|
+
if (options.millisecond) ts.millisecond = (ts.millisecond ?? 0) + options.millisecond;
|
|
1205
|
+
return updateFormatted(normalizeTimestamp(ts));
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
function addToDateClamped(timestamp, options) {
|
|
1209
|
+
const ts = cloneTimestamp(timestamp);
|
|
1210
|
+
if (options.year || options.month) {
|
|
1211
|
+
const target = normalizeYearMonth(ts.year + (options.year ?? 0), ts.month + (options.month ?? 0));
|
|
1212
|
+
ts.year = target.year;
|
|
1213
|
+
ts.month = target.month;
|
|
1214
|
+
ts.day = Math.min(ts.day, daysInMonth(ts.year, ts.month));
|
|
1215
|
+
}
|
|
1216
|
+
if (options.day) ts.day += options.day;
|
|
1217
|
+
if (options.hour) ts.hour += options.hour;
|
|
1218
|
+
if (options.minute) ts.minute += options.minute;
|
|
1219
|
+
if (options.second) ts.second = (ts.second ?? 0) + options.second;
|
|
1220
|
+
if (options.millisecond) ts.millisecond = (ts.millisecond ?? 0) + options.millisecond;
|
|
1221
|
+
return updateFormatted(normalizeTimestamp(ts));
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1224
|
+
function normalizeYearMonth(year, month) {
|
|
1225
|
+
const date = new Date(year, month - 1, 1);
|
|
1226
|
+
return {
|
|
1227
|
+
year: date.getFullYear(),
|
|
1228
|
+
month: date.getMonth() + 1
|
|
1229
|
+
};
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
function normalizeTimestamp(ts) {
|
|
1233
|
+
const date = new Date(ts.year, ts.month - 1, ts.day, ts.hour, ts.minute, ts.second ?? 0, ts.millisecond ?? 0);
|
|
1234
|
+
const timestamp = {
|
|
1235
|
+
...ts,
|
|
1236
|
+
year: date.getFullYear(),
|
|
1237
|
+
month: date.getMonth() + 1,
|
|
1238
|
+
day: date.getDate(),
|
|
1239
|
+
hour: date.getHours(),
|
|
1240
|
+
minute: date.getMinutes()
|
|
1241
|
+
};
|
|
1242
|
+
if (ts.second !== void 0 || date.getSeconds() !== 0) timestamp.second = date.getSeconds();
|
|
1243
|
+
if (ts.millisecond !== void 0 || date.getMilliseconds() !== 0) timestamp.millisecond = date.getMilliseconds();
|
|
1244
|
+
return freezeTimestamp(timestamp);
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
function daysBetween(ts1, ts2) {
|
|
1248
|
+
const diff = diffTimestamp(ts1, ts2, true);
|
|
1249
|
+
return Math.floor(diff / TIME_CONSTANTS.MILLISECONDS_IN.DAY);
|
|
1250
|
+
}
|
|
1251
|
+
|
|
1252
|
+
function weeksBetween(ts1, ts2) {
|
|
1253
|
+
let t1 = copyTimestamp(ts1);
|
|
1254
|
+
let t2 = copyTimestamp(ts2);
|
|
1255
|
+
t1 = findWeekday(t1, 0);
|
|
1256
|
+
t2 = findWeekday(t2, 6);
|
|
1257
|
+
return Math.ceil(daysBetween(t1, t2) / TIME_CONSTANTS.DAYS_IN.WEEK);
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
function createDuration(milliseconds) {
|
|
1261
|
+
const sign = milliseconds === 0 ? 0 : milliseconds < 0 ? -1 : 1;
|
|
1262
|
+
let remaining = Math.abs(milliseconds);
|
|
1263
|
+
const days = Math.floor(remaining / MILLISECONDS_IN_DAY);
|
|
1264
|
+
remaining -= days * MILLISECONDS_IN_DAY;
|
|
1265
|
+
const hours = Math.floor(remaining / MILLISECONDS_IN_HOUR);
|
|
1266
|
+
remaining -= hours * MILLISECONDS_IN_HOUR;
|
|
1267
|
+
const minutes = Math.floor(remaining / MILLISECONDS_IN_MINUTE);
|
|
1268
|
+
remaining -= minutes * MILLISECONDS_IN_MINUTE;
|
|
1269
|
+
const seconds = Math.floor(remaining / MILLISECONDS_IN_SECOND);
|
|
1270
|
+
remaining -= seconds * MILLISECONDS_IN_SECOND;
|
|
1271
|
+
return Object.freeze({
|
|
1272
|
+
totalMilliseconds: milliseconds,
|
|
1273
|
+
absoluteMilliseconds: Math.abs(milliseconds),
|
|
1274
|
+
sign,
|
|
1275
|
+
days,
|
|
1276
|
+
hours,
|
|
1277
|
+
minutes,
|
|
1278
|
+
seconds,
|
|
1279
|
+
milliseconds: remaining
|
|
1280
|
+
});
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
function durationBetween(start, end) {
|
|
1284
|
+
return createDuration(toUnixMilliseconds(end) - toUnixMilliseconds(start));
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
function addDuration(timestamp, duration) {
|
|
1288
|
+
const milliseconds = typeof duration === "number" ? duration : duration.totalMilliseconds;
|
|
1289
|
+
return fromUnixMilliseconds(toUnixMilliseconds(timestamp) + milliseconds);
|
|
1290
|
+
}
|
|
1291
|
+
|
|
1292
|
+
function subtractDuration(timestamp, duration) {
|
|
1293
|
+
return addDuration(timestamp, -(typeof duration === "number" ? duration : duration.totalMilliseconds));
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1296
|
+
function formatDuration(duration, options = {}) {
|
|
1297
|
+
const value = typeof duration === "number" ? createDuration(duration) : duration;
|
|
1298
|
+
const hours = value.days * HOURS_IN_DAY + value.hours;
|
|
1299
|
+
let formatted = `${options.signed === true && value.sign < 0 ? "-" : ""}${padNumber(hours, 2)}:${padNumber(value.minutes, 2)}:${padNumber(value.seconds, 2)}`;
|
|
1300
|
+
if (options.milliseconds === true) formatted += `.${padNumber(value.milliseconds, 3)}`;
|
|
1301
|
+
return formatted;
|
|
1302
|
+
}
|
|
1303
|
+
function roundTimestampToInterval(timestamp, minutes, rounder) {
|
|
1304
|
+
if (minutes <= 0 || Number.isFinite(minutes) === false) return copyTimestamp(timestamp);
|
|
1305
|
+
const interval = minutes * MILLISECONDS_IN_MINUTE;
|
|
1306
|
+
return fromUnixMilliseconds(rounder(toUnixMilliseconds(timestamp) / interval) * interval);
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1309
|
+
function floorToInterval(timestamp, minutes) {
|
|
1310
|
+
return roundTimestampToInterval(timestamp, minutes, Math.floor);
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
function ceilToInterval(timestamp, minutes) {
|
|
1314
|
+
return roundTimestampToInterval(timestamp, minutes, Math.ceil);
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
function roundToInterval(timestamp, minutes) {
|
|
1318
|
+
return roundTimestampToInterval(timestamp, minutes, Math.round);
|
|
1319
|
+
}
|
|
1320
|
+
const weekdayDateMap = {
|
|
1321
|
+
Sun: /* @__PURE__ */ new Date("2020-01-05T00:00:00.000Z"),
|
|
1322
|
+
Mon: /* @__PURE__ */ new Date("2020-01-06T00:00:00.000Z"),
|
|
1323
|
+
Tue: /* @__PURE__ */ new Date("2020-01-07T00:00:00.000Z"),
|
|
1324
|
+
Wed: /* @__PURE__ */ new Date("2020-01-08T00:00:00.000Z"),
|
|
1325
|
+
Thu: /* @__PURE__ */ new Date("2020-01-09T00:00:00.000Z"),
|
|
1326
|
+
Fri: /* @__PURE__ */ new Date("2020-01-10T00:00:00.000Z"),
|
|
1327
|
+
Sat: /* @__PURE__ */ new Date("2020-01-11T00:00:00.000Z")
|
|
1328
|
+
};
|
|
1329
|
+
function resolveIntlNameFormat(options, type) {
|
|
1330
|
+
if (type === "long" || type === "short" || type === "narrow") return options[type];
|
|
1331
|
+
return options.long;
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1334
|
+
function getWeekdayFormatter() {
|
|
1335
|
+
const emptyFormatter = () => "";
|
|
1336
|
+
const options = {
|
|
1337
|
+
long: {
|
|
1338
|
+
timeZone: "UTC",
|
|
1339
|
+
weekday: "long"
|
|
1340
|
+
},
|
|
1341
|
+
short: {
|
|
1342
|
+
timeZone: "UTC",
|
|
1343
|
+
weekday: "short"
|
|
1344
|
+
},
|
|
1345
|
+
narrow: {
|
|
1346
|
+
timeZone: "UTC",
|
|
1347
|
+
weekday: "narrow"
|
|
1348
|
+
}
|
|
1349
|
+
};
|
|
1350
|
+
if (typeof Intl === "undefined" || typeof Intl.DateTimeFormat === "undefined") return emptyFormatter;
|
|
1351
|
+
|
|
1352
|
+
function weekdayFormatter(weekday, type, locale) {
|
|
1353
|
+
try {
|
|
1354
|
+
return new Intl.DateTimeFormat(locale || void 0, resolveIntlNameFormat(options, type)).format(weekdayDateMap[weekday]);
|
|
1355
|
+
} catch (e) {
|
|
1356
|
+
if (e instanceof Error) console.error(`Intl.DateTimeFormat: ${e.message} -> day of week: ${weekday}`);
|
|
1357
|
+
return "";
|
|
1358
|
+
}
|
|
1359
|
+
}
|
|
1360
|
+
return weekdayFormatter;
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
function getWeekdayNames(type, locale) {
|
|
1364
|
+
const shortWeekdays = Object.keys(weekdayDateMap);
|
|
1365
|
+
const weekdayFormatter = getWeekdayFormatter();
|
|
1366
|
+
return shortWeekdays.map((weekday) => String(weekdayFormatter(weekday, type, locale)));
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
function getMonthFormatter() {
|
|
1370
|
+
const emptyFormatter = () => "";
|
|
1371
|
+
const options = {
|
|
1372
|
+
long: {
|
|
1373
|
+
timeZone: "UTC",
|
|
1374
|
+
month: "long"
|
|
1375
|
+
},
|
|
1376
|
+
short: {
|
|
1377
|
+
timeZone: "UTC",
|
|
1378
|
+
month: "short"
|
|
1379
|
+
},
|
|
1380
|
+
narrow: {
|
|
1381
|
+
timeZone: "UTC",
|
|
1382
|
+
month: "narrow"
|
|
1383
|
+
}
|
|
1384
|
+
};
|
|
1385
|
+
if (typeof Intl === "undefined" || typeof Intl.DateTimeFormat === "undefined") return emptyFormatter;
|
|
1386
|
+
|
|
1387
|
+
function monthFormatter(month, type = "long", locale) {
|
|
1388
|
+
try {
|
|
1389
|
+
const intlFormatter = new Intl.DateTimeFormat(locale || void 0, resolveIntlNameFormat(options, type));
|
|
1390
|
+
const date = /* @__PURE__ */ new Date();
|
|
1391
|
+
date.setDate(1);
|
|
1392
|
+
date.setMonth(month);
|
|
1393
|
+
return intlFormatter.format(date);
|
|
1394
|
+
} catch (e) {
|
|
1395
|
+
if (e instanceof Error) console.error(`Intl.DateTimeFormat: ${e.message} -> month: ${month}`);
|
|
1396
|
+
return "";
|
|
1397
|
+
}
|
|
1398
|
+
}
|
|
1399
|
+
return monthFormatter;
|
|
1400
|
+
}
|
|
1401
|
+
|
|
1402
|
+
function getMonthNames(type, locale) {
|
|
1403
|
+
const monthFormatter = getMonthFormatter();
|
|
1404
|
+
return [...Array(12).keys()].map((month) => monthFormatter(month, type, locale));
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1407
|
+
exports.DAYS_IN_MONTH = DAYS_IN_MONTH;
|
|
1408
|
+
exports.DAYS_IN_MONTH_LEAP = DAYS_IN_MONTH_LEAP;
|
|
1409
|
+
exports.DAYS_IN_MONTH_MAX = DAYS_IN_MONTH_MAX;
|
|
1410
|
+
exports.DAYS_IN_MONTH_MIN = DAYS_IN_MONTH_MIN;
|
|
1411
|
+
exports.DAYS_IN_WEEK = DAYS_IN_WEEK;
|
|
1412
|
+
exports.DAY_MIN = DAY_MIN;
|
|
1413
|
+
exports.FIRST_HOUR = FIRST_HOUR;
|
|
1414
|
+
exports.HOURS_IN_DAY = HOURS_IN_DAY;
|
|
1415
|
+
exports.MILLISECONDS_IN_DAY = MILLISECONDS_IN_DAY;
|
|
1416
|
+
exports.MILLISECONDS_IN_HOUR = MILLISECONDS_IN_HOUR;
|
|
1417
|
+
exports.MILLISECONDS_IN_MINUTE = MILLISECONDS_IN_MINUTE;
|
|
1418
|
+
exports.MILLISECONDS_IN_SECOND = MILLISECONDS_IN_SECOND;
|
|
1419
|
+
exports.MILLISECONDS_IN_WEEK = MILLISECONDS_IN_WEEK;
|
|
1420
|
+
exports.MINUTES_IN_HOUR = MINUTES_IN_HOUR;
|
|
1421
|
+
exports.MONTH_MAX = MONTH_MAX;
|
|
1422
|
+
exports.MONTH_MIN = MONTH_MIN;
|
|
1423
|
+
exports.PARSE_DATE = PARSE_DATE;
|
|
1424
|
+
exports.PARSE_DATETIME = PARSE_DATETIME;
|
|
1425
|
+
exports.PARSE_TIME = PARSE_TIME;
|
|
1426
|
+
exports.SECONDS_IN_DAY = SECONDS_IN_DAY;
|
|
1427
|
+
exports.SECONDS_IN_HOUR = SECONDS_IN_HOUR;
|
|
1428
|
+
exports.SECONDS_IN_MINUTE = SECONDS_IN_MINUTE;
|
|
1429
|
+
exports.TIME_CONSTANTS = TIME_CONSTANTS;
|
|
1430
|
+
exports.TimeObject = TimeObject;
|
|
1431
|
+
exports.Timestamp = Timestamp;
|
|
1432
|
+
exports.addCalendarDays = addCalendarDays;
|
|
1433
|
+
exports.addCalendarMonths = addCalendarMonths;
|
|
1434
|
+
exports.addCalendarYears = addCalendarYears;
|
|
1435
|
+
exports.addDuration = addDuration;
|
|
1436
|
+
exports.addToDate = addToDate;
|
|
1437
|
+
exports.addToDateClamped = addToDateClamped;
|
|
1438
|
+
exports.ceilToInterval = ceilToInterval;
|
|
1439
|
+
exports.compareDate = compareDate;
|
|
1440
|
+
exports.compareDateTime = compareDateTime;
|
|
1441
|
+
exports.compareTime = compareTime;
|
|
1442
|
+
exports.compareTimestamps = compareTimestamps;
|
|
1443
|
+
exports.copyTimestamp = copyTimestamp;
|
|
1444
|
+
exports.createCalendarDayList = createCalendarDayList;
|
|
1445
|
+
exports.createCalendarLocaleFormatterUTC = createCalendarLocaleFormatterUTC;
|
|
1446
|
+
exports.createCalendarTimestamp = createCalendarTimestamp;
|
|
1447
|
+
exports.createCalendarTimestampFromEpochDay = createCalendarTimestampFromEpochDay;
|
|
1448
|
+
exports.createDayList = createDayList;
|
|
1449
|
+
exports.createDuration = createDuration;
|
|
1450
|
+
exports.createIntervalList = createIntervalList;
|
|
1451
|
+
exports.createNativeLocaleFormatter = createNativeLocaleFormatter;
|
|
1452
|
+
exports.createNativeLocaleFormatterUTC = createNativeLocaleFormatterUTC;
|
|
1453
|
+
exports.createTimestampRange = createTimestampRange;
|
|
1454
|
+
exports.daysBetween = daysBetween;
|
|
1455
|
+
exports.daysInMonth = daysInMonth;
|
|
1456
|
+
exports.diffTimestamp = diffTimestamp;
|
|
1457
|
+
exports.durationBetween = durationBetween;
|
|
1458
|
+
exports.findCalendarWeekday = findCalendarWeekday;
|
|
1459
|
+
exports.findRangeGaps = findRangeGaps;
|
|
1460
|
+
exports.findWeekday = findWeekday;
|
|
1461
|
+
exports.floorToInterval = floorToInterval;
|
|
1462
|
+
exports.formatCalendarDate = formatCalendarDate;
|
|
1463
|
+
exports.formatDuration = formatDuration;
|
|
1464
|
+
exports.fromUnixMilliseconds = fromUnixMilliseconds;
|
|
1465
|
+
exports.fromUnixSeconds = fromUnixSeconds;
|
|
1466
|
+
exports.getCalendarDayIdentifier = getCalendarDayIdentifier;
|
|
1467
|
+
exports.getCalendarEndOfMonth = getCalendarEndOfMonth;
|
|
1468
|
+
exports.getCalendarEndOfWeek = getCalendarEndOfWeek;
|
|
1469
|
+
exports.getCalendarEndOfYear = getCalendarEndOfYear;
|
|
1470
|
+
exports.getCalendarStartOfMonth = getCalendarStartOfMonth;
|
|
1471
|
+
exports.getCalendarStartOfWeek = getCalendarStartOfWeek;
|
|
1472
|
+
exports.getCalendarStartOfYear = getCalendarStartOfYear;
|
|
1473
|
+
exports.getDate = getDate;
|
|
1474
|
+
exports.getDateObject = getDateObject;
|
|
1475
|
+
exports.getDateTime = getDateTime;
|
|
1476
|
+
exports.getDayIdentifier = getDayIdentifier;
|
|
1477
|
+
exports.getDayOfYear = getDayOfYear;
|
|
1478
|
+
exports.getDayTimeIdentifier = getDayTimeIdentifier;
|
|
1479
|
+
exports.getEndOfDay = getEndOfDay;
|
|
1480
|
+
exports.getEndOfMonth = getEndOfMonth;
|
|
1481
|
+
exports.getEndOfWeek = getEndOfWeek;
|
|
1482
|
+
exports.getEndOfYear = getEndOfYear;
|
|
1483
|
+
exports.getEpochDay = getEpochDay;
|
|
1484
|
+
exports.getMonthFormatter = getMonthFormatter;
|
|
1485
|
+
exports.getMonthNames = getMonthNames;
|
|
1486
|
+
exports.getStartOfDay = getStartOfDay;
|
|
1487
|
+
exports.getStartOfMonth = getStartOfMonth;
|
|
1488
|
+
exports.getStartOfWeek = getStartOfWeek;
|
|
1489
|
+
exports.getStartOfYear = getStartOfYear;
|
|
1490
|
+
exports.getTime = getTime;
|
|
1491
|
+
exports.getTimeIdentifier = getTimeIdentifier;
|
|
1492
|
+
exports.getWeekday = getWeekday;
|
|
1493
|
+
exports.getWeekdayFormatter = getWeekdayFormatter;
|
|
1494
|
+
exports.getWeekdayNames = getWeekdayNames;
|
|
1495
|
+
exports.getWorkWeek = getWorkWeek;
|
|
1496
|
+
exports.gregorianCalendar = gregorianCalendar;
|
|
1497
|
+
exports.intersectRanges = intersectRanges;
|
|
1498
|
+
exports.isBetweenDates = isBetweenDates;
|
|
1499
|
+
exports.isLeapYear = isLeapYear;
|
|
1500
|
+
exports.isOverlappingDates = isOverlappingDates;
|
|
1501
|
+
exports.isRangeOverlapping = isRangeOverlapping;
|
|
1502
|
+
exports.isTimestampInRange = isTimestampInRange;
|
|
1503
|
+
exports.isToday = isToday;
|
|
1504
|
+
exports.isTodayUTC = isTodayUTC;
|
|
1505
|
+
exports.isValidCalendarDate = isValidCalendarDate;
|
|
1506
|
+
exports.makeCalendarDateTimeUTC = makeCalendarDateTimeUTC;
|
|
1507
|
+
exports.makeCalendarDateUTC = makeCalendarDateUTC;
|
|
1508
|
+
exports.makeDate = makeDate;
|
|
1509
|
+
exports.makeDateTime = makeDateTime;
|
|
1510
|
+
exports.makeDateTimeUTC = makeDateTimeUTC;
|
|
1511
|
+
exports.makeDateUTC = makeDateUTC;
|
|
1512
|
+
exports.maxTimestamp = maxTimestamp;
|
|
1513
|
+
exports.mergeRanges = mergeRanges;
|
|
1514
|
+
exports.minTimestamp = minTimestamp;
|
|
1515
|
+
exports.moveRelativeDays = moveRelativeDays;
|
|
1516
|
+
exports.nextCalendarDay = nextCalendarDay;
|
|
1517
|
+
exports.nextDay = nextDay;
|
|
1518
|
+
exports.nowUTC = nowUTC;
|
|
1519
|
+
exports.padNumber = padNumber;
|
|
1520
|
+
exports.parseCalendarTimestamp = parseCalendarTimestamp;
|
|
1521
|
+
exports.parseDate = parseDate;
|
|
1522
|
+
exports.parseDateUTC = parseDateUTC;
|
|
1523
|
+
exports.parseTime = parseTime;
|
|
1524
|
+
exports.parseTimestamp = parseTimestamp;
|
|
1525
|
+
exports.parsed = parsed;
|
|
1526
|
+
exports.prevCalendarDay = prevCalendarDay;
|
|
1527
|
+
exports.prevDay = prevDay;
|
|
1528
|
+
exports.relativeDays = relativeDays;
|
|
1529
|
+
exports.roundToInterval = roundToInterval;
|
|
1530
|
+
exports.subtractDuration = subtractDuration;
|
|
1531
|
+
exports.subtractRanges = subtractRanges;
|
|
1532
|
+
exports.toCalendarDateParts = toCalendarDateParts;
|
|
1533
|
+
exports.toUnixMilliseconds = toUnixMilliseconds;
|
|
1534
|
+
exports.toUnixSeconds = toUnixSeconds;
|
|
1535
|
+
exports.today = today;
|
|
1536
|
+
exports.todayUTC = todayUTC;
|
|
1537
|
+
exports.updateCalendarFormatted = updateCalendarFormatted;
|
|
1538
|
+
exports.updateCalendarRelative = updateCalendarRelative;
|
|
1539
|
+
exports.updateDayOfYear = updateDayOfYear;
|
|
1540
|
+
exports.updateDisabled = updateDisabled;
|
|
1541
|
+
exports.updateFormatted = updateFormatted;
|
|
1542
|
+
exports.updateMinutes = updateMinutes;
|
|
1543
|
+
exports.updateRelative = updateRelative;
|
|
1544
|
+
exports.updateWeekday = updateWeekday;
|
|
1545
|
+
exports.updateWorkWeek = updateWorkWeek;
|
|
1546
|
+
exports.validateNumber = validateNumber;
|
|
1547
|
+
exports.validateTimestamp = validateTimestamp;
|
|
1548
|
+
exports.weeksBetween = weeksBetween;
|
|
1549
|
+
return exports;
|
|
1550
|
+
})({});
|