ts-time-utils 4.1.0 → 4.4.0
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 +81 -31
- package/dist/{age.js → age.cjs} +14 -6
- package/dist/{calculate.js → calculate.cjs} +30 -18
- package/dist/{calendar.js → calendar.cjs} +80 -39
- package/dist/{calendars.js → calendars.cjs} +48 -23
- package/dist/{chain.js → chain.cjs} +41 -40
- package/dist/{compare.js → compare.cjs} +58 -28
- package/dist/constants.cjs +19 -0
- package/dist/{countdown.js → countdown.cjs} +16 -7
- package/dist/{cron.js → cron.cjs} +20 -9
- package/dist/{dateRange.js → dateRange.cjs} +42 -26
- package/dist/{duration.js → duration.cjs} +56 -44
- package/dist/esm/chain.js +0 -5
- package/dist/esm/naturalLanguage.d.ts +1 -3
- package/dist/esm/naturalLanguage.d.ts.map +1 -1
- package/dist/esm/naturalLanguage.js +9 -2
- package/dist/esm/plugins.d.ts +0 -6
- package/dist/esm/plugins.d.ts.map +1 -1
- package/dist/esm/plugins.js +36 -42
- package/dist/esm/recurrence.d.ts.map +1 -1
- package/dist/esm/recurrence.js +3 -5
- package/dist/esm/timezone.d.ts +6 -1
- package/dist/esm/timezone.d.ts.map +1 -1
- package/dist/esm/timezone.js +106 -66
- package/dist/esm/types.d.ts +0 -4
- package/dist/esm/types.d.ts.map +1 -1
- package/dist/{finance.js → finance.cjs} +39 -22
- package/dist/{fiscal.js → fiscal.cjs} +36 -17
- package/dist/{format.js → format.cjs} +83 -70
- package/dist/{healthcare.js → healthcare.cjs} +37 -22
- package/dist/{holidays.js → holidays.cjs} +52 -25
- package/dist/index.cjs +595 -0
- package/dist/{interval.js → interval.cjs} +24 -11
- package/dist/{iterate.js → iterate.cjs} +84 -41
- package/dist/{locale.js → locale.cjs} +54 -26
- package/dist/{naturalLanguage.js → naturalLanguage.cjs} +36 -23
- package/dist/naturalLanguage.d.ts +1 -3
- package/dist/naturalLanguage.d.ts.map +1 -1
- package/dist/{parse.js → parse.cjs} +24 -11
- package/dist/{performance.js → performance.cjs} +23 -10
- package/dist/{plugins.js → plugins.cjs} +48 -47
- package/dist/plugins.d.ts +0 -6
- package/dist/plugins.d.ts.map +1 -1
- package/dist/{precision.js → precision.cjs} +74 -37
- package/dist/{rangePresets.js → rangePresets.cjs} +40 -19
- package/dist/{recurrence.js → recurrence.cjs} +27 -21
- package/dist/recurrence.d.ts.map +1 -1
- package/dist/{scheduling.js → scheduling.cjs} +46 -31
- package/dist/{serialize.js → serialize.cjs} +36 -17
- package/dist/{temporal.js → temporal.cjs} +28 -13
- package/dist/{timezone.js → timezone.cjs} +140 -82
- package/dist/timezone.d.ts +6 -1
- package/dist/timezone.d.ts.map +1 -1
- package/dist/{types.js → types.cjs} +9 -3
- package/dist/types.d.ts +0 -4
- package/dist/types.d.ts.map +1 -1
- package/dist/{validate.js → validate.cjs} +54 -26
- package/dist/{workingHours.js → workingHours.cjs} +36 -17
- package/package.json +40 -37
- package/dist/constants.js +0 -16
- package/dist/index.js +0 -72
|
@@ -1,13 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
/**
|
|
2
3
|
* @fileoverview Scheduling and booking utilities
|
|
3
4
|
* Provides slot generation, availability checking, and conflict detection
|
|
4
5
|
*/
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.DEFAULT_SCHEDULING_CONFIG = void 0;
|
|
8
|
+
exports.generateSlots = generateSlots;
|
|
9
|
+
exports.generateSlotsForRange = generateSlotsForRange;
|
|
10
|
+
exports.getAvailableSlots = getAvailableSlots;
|
|
11
|
+
exports.findNextAvailable = findNextAvailable;
|
|
12
|
+
exports.isSlotAvailable = isSlotAvailable;
|
|
13
|
+
exports.findConflicts = findConflicts;
|
|
14
|
+
exports.hasConflict = hasConflict;
|
|
15
|
+
exports.addBuffer = addBuffer;
|
|
16
|
+
exports.removeBuffer = removeBuffer;
|
|
17
|
+
exports.expandRecurringAvailability = expandRecurringAvailability;
|
|
18
|
+
exports.mergeBookings = mergeBookings;
|
|
19
|
+
exports.splitSlot = splitSlot;
|
|
20
|
+
const dateRange_js_1 = require("./dateRange.cjs");
|
|
21
|
+
const workingHours_js_1 = require("./workingHours.cjs");
|
|
22
|
+
const recurrence_js_1 = require("./recurrence.cjs");
|
|
8
23
|
/** Default scheduling configuration */
|
|
9
|
-
|
|
10
|
-
workingHours: DEFAULT_WORKING_HOURS,
|
|
24
|
+
exports.DEFAULT_SCHEDULING_CONFIG = {
|
|
25
|
+
workingHours: workingHours_js_1.DEFAULT_WORKING_HOURS,
|
|
11
26
|
bufferMinutes: 0,
|
|
12
27
|
slotDuration: 30,
|
|
13
28
|
holidays: []
|
|
@@ -39,19 +54,19 @@ function isHoliday(date, holidays) {
|
|
|
39
54
|
* // Returns 30-minute slots during working hours
|
|
40
55
|
* ```
|
|
41
56
|
*/
|
|
42
|
-
|
|
57
|
+
function generateSlots(date, config = {}) {
|
|
43
58
|
const d = toDate(date);
|
|
44
|
-
const cfg = { ...DEFAULT_SCHEDULING_CONFIG, ...config };
|
|
45
|
-
const workingHours = cfg.workingHours ?? DEFAULT_WORKING_HOURS;
|
|
59
|
+
const cfg = { ...exports.DEFAULT_SCHEDULING_CONFIG, ...config };
|
|
60
|
+
const workingHours = cfg.workingHours ?? workingHours_js_1.DEFAULT_WORKING_HOURS;
|
|
46
61
|
// Check if it's a working day and not a holiday
|
|
47
|
-
if (!isWorkingDay(d, workingHours))
|
|
62
|
+
if (!(0, workingHours_js_1.isWorkingDay)(d, workingHours))
|
|
48
63
|
return [];
|
|
49
64
|
if (cfg.holidays && isHoliday(d, cfg.holidays))
|
|
50
65
|
return [];
|
|
51
66
|
const slots = [];
|
|
52
67
|
const slotDuration = cfg.slotDuration ?? 30;
|
|
53
|
-
const dayStart = getWorkDayStart(d, workingHours);
|
|
54
|
-
const dayEnd = getWorkDayEnd(d, workingHours);
|
|
68
|
+
const dayStart = (0, workingHours_js_1.getWorkDayStart)(d, workingHours);
|
|
69
|
+
const dayEnd = (0, workingHours_js_1.getWorkDayEnd)(d, workingHours);
|
|
55
70
|
let current = new Date(dayStart);
|
|
56
71
|
while (current < dayEnd) {
|
|
57
72
|
const slotEnd = new Date(current.getTime() + slotDuration * 60 * 1000);
|
|
@@ -59,7 +74,7 @@ export function generateSlots(date, config = {}) {
|
|
|
59
74
|
if (slotEnd <= dayEnd) {
|
|
60
75
|
// Check if slot is during working time (not during breaks)
|
|
61
76
|
const midpoint = new Date(current.getTime() + (slotDuration * 60 * 1000) / 2);
|
|
62
|
-
const available = isWorkingTime(midpoint, workingHours);
|
|
77
|
+
const available = (0, workingHours_js_1.isWorkingTime)(midpoint, workingHours);
|
|
63
78
|
slots.push({
|
|
64
79
|
start: new Date(current),
|
|
65
80
|
end: new Date(slotEnd),
|
|
@@ -82,7 +97,7 @@ export function generateSlots(date, config = {}) {
|
|
|
82
97
|
* const slots = generateSlotsForRange(range, { slotDuration: 60 });
|
|
83
98
|
* ```
|
|
84
99
|
*/
|
|
85
|
-
|
|
100
|
+
function generateSlotsForRange(range, config = {}) {
|
|
86
101
|
const slots = [];
|
|
87
102
|
const current = new Date(range.start);
|
|
88
103
|
current.setHours(0, 0, 0, 0);
|
|
@@ -108,8 +123,8 @@ export function generateSlotsForRange(range, config = {}) {
|
|
|
108
123
|
* const available = getAvailableSlots(new Date('2024-01-15'), bookings);
|
|
109
124
|
* ```
|
|
110
125
|
*/
|
|
111
|
-
|
|
112
|
-
const cfg = { ...DEFAULT_SCHEDULING_CONFIG, ...config };
|
|
126
|
+
function getAvailableSlots(date, bookings, config = {}) {
|
|
127
|
+
const cfg = { ...exports.DEFAULT_SCHEDULING_CONFIG, ...config };
|
|
113
128
|
const slots = generateSlots(date, cfg);
|
|
114
129
|
const bufferMs = (cfg.bufferMinutes ?? 0) * 60 * 1000;
|
|
115
130
|
return slots.map(slot => {
|
|
@@ -118,7 +133,7 @@ export function getAvailableSlots(date, bookings, config = {}) {
|
|
|
118
133
|
start: new Date(slot.start.getTime() - bufferMs),
|
|
119
134
|
end: new Date(slot.end.getTime() + bufferMs)
|
|
120
135
|
};
|
|
121
|
-
const hasConflict = bookings.some(booking => dateRangeOverlap(checkRange, booking));
|
|
136
|
+
const hasConflict = bookings.some(booking => (0, dateRange_js_1.dateRangeOverlap)(checkRange, booking));
|
|
122
137
|
return {
|
|
123
138
|
...slot,
|
|
124
139
|
available: slot.available && !hasConflict
|
|
@@ -139,9 +154,9 @@ export function getAvailableSlots(date, bookings, config = {}) {
|
|
|
139
154
|
* if (nextSlot) console.log(`Next 1-hour slot at ${nextSlot.start}`);
|
|
140
155
|
* ```
|
|
141
156
|
*/
|
|
142
|
-
|
|
157
|
+
function findNextAvailable(after, bookings, duration, config = {}) {
|
|
143
158
|
const startDate = toDate(after);
|
|
144
|
-
const cfg = { ...DEFAULT_SCHEDULING_CONFIG, ...config, slotDuration: duration };
|
|
159
|
+
const cfg = { ...exports.DEFAULT_SCHEDULING_CONFIG, ...config, slotDuration: duration };
|
|
145
160
|
// Search up to 30 days ahead
|
|
146
161
|
for (let dayOffset = 0; dayOffset < 30; dayOffset++) {
|
|
147
162
|
const checkDate = new Date(startDate);
|
|
@@ -169,8 +184,8 @@ export function findNextAvailable(after, bookings, duration, config = {}) {
|
|
|
169
184
|
* }
|
|
170
185
|
* ```
|
|
171
186
|
*/
|
|
172
|
-
|
|
173
|
-
return !bookings.some(booking => dateRangeOverlap(slot, booking));
|
|
187
|
+
function isSlotAvailable(slot, bookings) {
|
|
188
|
+
return !bookings.some(booking => (0, dateRange_js_1.dateRangeOverlap)(slot, booking));
|
|
174
189
|
}
|
|
175
190
|
/**
|
|
176
191
|
* Finds bookings that conflict with a proposed time range
|
|
@@ -186,8 +201,8 @@ export function isSlotAvailable(slot, bookings) {
|
|
|
186
201
|
* }
|
|
187
202
|
* ```
|
|
188
203
|
*/
|
|
189
|
-
|
|
190
|
-
return bookings.filter(booking => dateRangeOverlap(booking, proposed));
|
|
204
|
+
function findConflicts(bookings, proposed) {
|
|
205
|
+
return bookings.filter(booking => (0, dateRange_js_1.dateRangeOverlap)(booking, proposed));
|
|
191
206
|
}
|
|
192
207
|
/**
|
|
193
208
|
* Checks if a proposed time range has any conflicts
|
|
@@ -202,8 +217,8 @@ export function findConflicts(bookings, proposed) {
|
|
|
202
217
|
* }
|
|
203
218
|
* ```
|
|
204
219
|
*/
|
|
205
|
-
|
|
206
|
-
return bookings.some(booking => dateRangeOverlap(booking, proposed));
|
|
220
|
+
function hasConflict(bookings, proposed) {
|
|
221
|
+
return bookings.some(booking => (0, dateRange_js_1.dateRangeOverlap)(booking, proposed));
|
|
207
222
|
}
|
|
208
223
|
/**
|
|
209
224
|
* Adds buffer time around a slot
|
|
@@ -218,7 +233,7 @@ export function hasConflict(bookings, proposed) {
|
|
|
218
233
|
* // buffered.start = 09:45, buffered.end = 11:15
|
|
219
234
|
* ```
|
|
220
235
|
*/
|
|
221
|
-
|
|
236
|
+
function addBuffer(slot, bufferMinutes) {
|
|
222
237
|
const bufferMs = bufferMinutes * 60 * 1000;
|
|
223
238
|
return {
|
|
224
239
|
start: new Date(slot.start.getTime() - bufferMs),
|
|
@@ -238,7 +253,7 @@ export function addBuffer(slot, bufferMinutes) {
|
|
|
238
253
|
* // original.start = 10:00, original.end = 11:00
|
|
239
254
|
* ```
|
|
240
255
|
*/
|
|
241
|
-
|
|
256
|
+
function removeBuffer(slot, bufferMinutes) {
|
|
242
257
|
const bufferMs = bufferMinutes * 60 * 1000;
|
|
243
258
|
return {
|
|
244
259
|
start: new Date(slot.start.getTime() + bufferMs),
|
|
@@ -263,8 +278,8 @@ export function removeBuffer(slot, bufferMinutes) {
|
|
|
263
278
|
* const slots = expandRecurringAvailability(pattern, range);
|
|
264
279
|
* ```
|
|
265
280
|
*/
|
|
266
|
-
|
|
267
|
-
const occurrences = getOccurrencesBetween(pattern, range.start, range.end);
|
|
281
|
+
function expandRecurringAvailability(pattern, range, config = {}) {
|
|
282
|
+
const occurrences = (0, recurrence_js_1.getOccurrencesBetween)(pattern, range.start, range.end);
|
|
268
283
|
const slots = [];
|
|
269
284
|
for (const occurrence of occurrences) {
|
|
270
285
|
const daySlots = generateSlots(occurrence, config);
|
|
@@ -287,10 +302,10 @@ export function expandRecurringAvailability(pattern, range, config = {}) {
|
|
|
287
302
|
* // [{ start: 09:00, end: 11:00 }]
|
|
288
303
|
* ```
|
|
289
304
|
*/
|
|
290
|
-
|
|
305
|
+
function mergeBookings(bookings) {
|
|
291
306
|
if (bookings.length === 0)
|
|
292
307
|
return [];
|
|
293
|
-
const ranges = mergeDateRanges(bookings);
|
|
308
|
+
const ranges = (0, dateRange_js_1.mergeDateRanges)(bookings);
|
|
294
309
|
return ranges.map(range => ({
|
|
295
310
|
start: range.start,
|
|
296
311
|
end: range.end
|
|
@@ -309,7 +324,7 @@ export function mergeBookings(bookings) {
|
|
|
309
324
|
* // before: 09:00-10:00, after: 10:00-11:00
|
|
310
325
|
* ```
|
|
311
326
|
*/
|
|
312
|
-
|
|
327
|
+
function splitSlot(slot, at) {
|
|
313
328
|
const splitTime = toDate(at);
|
|
314
329
|
if (splitTime <= slot.start || splitTime >= slot.end) {
|
|
315
330
|
return null;
|
|
@@ -1,10 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.serializeDate = serializeDate;
|
|
4
|
+
exports.deserializeDate = deserializeDate;
|
|
5
|
+
exports.createDateReviver = createDateReviver;
|
|
6
|
+
exports.createDateReplacer = createDateReplacer;
|
|
7
|
+
exports.parseISOString = parseISOString;
|
|
8
|
+
exports.toEpochTimestamp = toEpochTimestamp;
|
|
9
|
+
exports.fromEpochTimestamp = fromEpochTimestamp;
|
|
10
|
+
exports.createEpochTimestamp = createEpochTimestamp;
|
|
11
|
+
exports.toDateObject = toDateObject;
|
|
12
|
+
exports.fromDateObject = fromDateObject;
|
|
13
|
+
exports.isValidISODateString = isValidISODateString;
|
|
14
|
+
exports.isValidEpochTimestamp = isValidEpochTimestamp;
|
|
15
|
+
exports.cloneDate = cloneDate;
|
|
16
|
+
exports.datesEqual = datesEqual;
|
|
17
|
+
exports.now = now;
|
|
18
|
+
exports.parseJSONWithDates = parseJSONWithDates;
|
|
19
|
+
exports.stringifyWithDates = stringifyWithDates;
|
|
1
20
|
/**
|
|
2
21
|
* Safe JSON date serialization and deserialization utilities
|
|
3
22
|
*/
|
|
4
23
|
/**
|
|
5
24
|
* Safely serialize a date to JSON with various format options
|
|
6
25
|
*/
|
|
7
|
-
|
|
26
|
+
function serializeDate(date, options = {}) {
|
|
8
27
|
const { format = 'iso', includeTimezone = false, useUTC = false, precision = 'milliseconds', customFormat } = options;
|
|
9
28
|
const dateObj = normalizeDate(date);
|
|
10
29
|
if (!dateObj) {
|
|
@@ -30,7 +49,7 @@ export function serializeDate(date, options = {}) {
|
|
|
30
49
|
/**
|
|
31
50
|
* Safely deserialize a date from various formats
|
|
32
51
|
*/
|
|
33
|
-
|
|
52
|
+
function deserializeDate(serializedDate, options = {}) {
|
|
34
53
|
const { useUTC = false } = options;
|
|
35
54
|
try {
|
|
36
55
|
if (typeof serializedDate === 'string') {
|
|
@@ -59,7 +78,7 @@ export function deserializeDate(serializedDate, options = {}) {
|
|
|
59
78
|
/**
|
|
60
79
|
* Create a safe JSON reviver function for automatic date parsing
|
|
61
80
|
*/
|
|
62
|
-
|
|
81
|
+
function createDateReviver(dateKeys = ['createdAt', 'updatedAt', 'date', 'timestamp'], options = {}) {
|
|
63
82
|
return (key, value) => {
|
|
64
83
|
if (dateKeys.includes(key) && (typeof value === 'string' || typeof value === 'number')) {
|
|
65
84
|
const parsed = deserializeDate(value, options);
|
|
@@ -71,7 +90,7 @@ export function createDateReviver(dateKeys = ['createdAt', 'updatedAt', 'date',
|
|
|
71
90
|
/**
|
|
72
91
|
* Create a safe JSON replacer function for automatic date serialization
|
|
73
92
|
*/
|
|
74
|
-
|
|
93
|
+
function createDateReplacer(dateKeys = ['createdAt', 'updatedAt', 'date', 'timestamp'], options = {}) {
|
|
75
94
|
return (key, value) => {
|
|
76
95
|
if (dateKeys.includes(key)) {
|
|
77
96
|
if (value instanceof Date) {
|
|
@@ -91,7 +110,7 @@ export function createDateReplacer(dateKeys = ['createdAt', 'updatedAt', 'date',
|
|
|
91
110
|
/**
|
|
92
111
|
* Parse ISO string with better error handling
|
|
93
112
|
*/
|
|
94
|
-
|
|
113
|
+
function parseISOString(isoString, useUTC = false) {
|
|
95
114
|
if (!isoString || typeof isoString !== 'string') {
|
|
96
115
|
return null;
|
|
97
116
|
}
|
|
@@ -120,7 +139,7 @@ export function parseISOString(isoString, useUTC = false) {
|
|
|
120
139
|
/**
|
|
121
140
|
* Convert date to epoch timestamp with specified precision
|
|
122
141
|
*/
|
|
123
|
-
|
|
142
|
+
function toEpochTimestamp(date, precision = 'milliseconds') {
|
|
124
143
|
const dateObj = normalizeDate(date);
|
|
125
144
|
if (!dateObj) {
|
|
126
145
|
throw new Error('Invalid date provided for epoch conversion');
|
|
@@ -139,7 +158,7 @@ export function toEpochTimestamp(date, precision = 'milliseconds') {
|
|
|
139
158
|
/**
|
|
140
159
|
* Create date from epoch timestamp with specified precision
|
|
141
160
|
*/
|
|
142
|
-
|
|
161
|
+
function fromEpochTimestamp(timestamp, precision = 'milliseconds') {
|
|
143
162
|
let ms;
|
|
144
163
|
switch (precision) {
|
|
145
164
|
case 'seconds':
|
|
@@ -158,7 +177,7 @@ export function fromEpochTimestamp(timestamp, precision = 'milliseconds') {
|
|
|
158
177
|
/**
|
|
159
178
|
* Create epoch timestamp with metadata
|
|
160
179
|
*/
|
|
161
|
-
|
|
180
|
+
function createEpochTimestamp(date, precision = 'milliseconds', timezone) {
|
|
162
181
|
return {
|
|
163
182
|
timestamp: toEpochTimestamp(date, precision),
|
|
164
183
|
precision,
|
|
@@ -168,7 +187,7 @@ export function createEpochTimestamp(date, precision = 'milliseconds', timezone)
|
|
|
168
187
|
/**
|
|
169
188
|
* Convert date to safe object representation
|
|
170
189
|
*/
|
|
171
|
-
|
|
190
|
+
function toDateObject(date, includeTimezone = false) {
|
|
172
191
|
const dateObj = normalizeDate(date);
|
|
173
192
|
if (!dateObj) {
|
|
174
193
|
throw new Error('Invalid date provided for object conversion');
|
|
@@ -195,7 +214,7 @@ export function toDateObject(date, includeTimezone = false) {
|
|
|
195
214
|
/**
|
|
196
215
|
* Create date from object representation
|
|
197
216
|
*/
|
|
198
|
-
|
|
217
|
+
function fromDateObject(dateObj) {
|
|
199
218
|
// Validate required fields
|
|
200
219
|
if (!dateObj || typeof dateObj !== 'object') {
|
|
201
220
|
throw new Error('Invalid date object provided');
|
|
@@ -228,7 +247,7 @@ export function fromDateObject(dateObj) {
|
|
|
228
247
|
/**
|
|
229
248
|
* Check if a string is a valid ISO date string for serialization
|
|
230
249
|
*/
|
|
231
|
-
|
|
250
|
+
function isValidISODateString(dateString) {
|
|
232
251
|
if (!dateString || typeof dateString !== 'string') {
|
|
233
252
|
return false;
|
|
234
253
|
}
|
|
@@ -238,7 +257,7 @@ export function isValidISODateString(dateString) {
|
|
|
238
257
|
/**
|
|
239
258
|
* Check if a number is a valid epoch timestamp
|
|
240
259
|
*/
|
|
241
|
-
|
|
260
|
+
function isValidEpochTimestamp(timestamp, precision = 'milliseconds') {
|
|
242
261
|
if (typeof timestamp !== 'number' || isNaN(timestamp)) {
|
|
243
262
|
return false;
|
|
244
263
|
}
|
|
@@ -265,14 +284,14 @@ export function isValidEpochTimestamp(timestamp, precision = 'milliseconds') {
|
|
|
265
284
|
/**
|
|
266
285
|
* Clone a date safely (avoids reference issues)
|
|
267
286
|
*/
|
|
268
|
-
|
|
287
|
+
function cloneDate(date) {
|
|
269
288
|
const dateObj = normalizeDate(date);
|
|
270
289
|
return dateObj ? new Date(dateObj.getTime()) : null;
|
|
271
290
|
}
|
|
272
291
|
/**
|
|
273
292
|
* Compare two dates for equality (ignoring milliseconds if specified)
|
|
274
293
|
*/
|
|
275
|
-
|
|
294
|
+
function datesEqual(date1, date2, precision = 'milliseconds') {
|
|
276
295
|
const d1 = normalizeDate(date1);
|
|
277
296
|
const d2 = normalizeDate(date2);
|
|
278
297
|
if (!d1 || !d2) {
|
|
@@ -295,7 +314,7 @@ export function datesEqual(date1, date2, precision = 'milliseconds') {
|
|
|
295
314
|
/**
|
|
296
315
|
* Get current timestamp in various formats
|
|
297
316
|
*/
|
|
298
|
-
|
|
317
|
+
function now(format = 'date') {
|
|
299
318
|
const current = new Date();
|
|
300
319
|
switch (format) {
|
|
301
320
|
case 'iso':
|
|
@@ -312,7 +331,7 @@ export function now(format = 'date') {
|
|
|
312
331
|
/**
|
|
313
332
|
* Safely handle JSON parsing with date conversion
|
|
314
333
|
*/
|
|
315
|
-
|
|
334
|
+
function parseJSONWithDates(jsonString, dateKeys, options) {
|
|
316
335
|
try {
|
|
317
336
|
return JSON.parse(jsonString, createDateReviver(dateKeys, options));
|
|
318
337
|
}
|
|
@@ -323,7 +342,7 @@ export function parseJSONWithDates(jsonString, dateKeys, options) {
|
|
|
323
342
|
/**
|
|
324
343
|
* Safely handle JSON stringification with date conversion
|
|
325
344
|
*/
|
|
326
|
-
|
|
345
|
+
function stringifyWithDates(obj, dateKeys, options, space) {
|
|
327
346
|
try {
|
|
328
347
|
return JSON.stringify(obj, createDateReplacer(dateKeys, options), space);
|
|
329
348
|
}
|
|
@@ -1,8 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
/**
|
|
2
3
|
* @fileoverview Temporal API compatibility layer
|
|
3
4
|
* Provides Temporal-like objects that work with native Date
|
|
4
5
|
* When Temporal ships natively, these become thin wrappers
|
|
5
6
|
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.toPlainDate = toPlainDate;
|
|
9
|
+
exports.toPlainTime = toPlainTime;
|
|
10
|
+
exports.toPlainDateTime = toPlainDateTime;
|
|
11
|
+
exports.toZonedDateTime = toZonedDateTime;
|
|
12
|
+
exports.toInstant = toInstant;
|
|
13
|
+
exports.createDuration = createDuration;
|
|
14
|
+
exports.parseDuration = parseDuration;
|
|
15
|
+
exports.nowInstant = nowInstant;
|
|
16
|
+
exports.nowPlainDateTime = nowPlainDateTime;
|
|
17
|
+
exports.nowPlainDate = nowPlainDate;
|
|
18
|
+
exports.nowPlainTime = nowPlainTime;
|
|
19
|
+
exports.nowZonedDateTime = nowZonedDateTime;
|
|
20
|
+
exports.fromTemporal = fromTemporal;
|
|
6
21
|
// Helper functions
|
|
7
22
|
function getWeekNumber(date) {
|
|
8
23
|
const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
|
|
@@ -552,7 +567,7 @@ class InstantImpl {
|
|
|
552
567
|
return new Date(this.epochMilliseconds);
|
|
553
568
|
}
|
|
554
569
|
}
|
|
555
|
-
|
|
570
|
+
function toPlainDate(dateOrYear, month, day) {
|
|
556
571
|
if (dateOrYear instanceof Date) {
|
|
557
572
|
return new PlainDateImpl(dateOrYear.getFullYear(), dateOrYear.getMonth() + 1, dateOrYear.getDate());
|
|
558
573
|
}
|
|
@@ -561,7 +576,7 @@ export function toPlainDate(dateOrYear, month, day) {
|
|
|
561
576
|
}
|
|
562
577
|
return new PlainDateImpl(dateOrYear, month, day);
|
|
563
578
|
}
|
|
564
|
-
|
|
579
|
+
function toPlainTime(dateOrHour, minute, second, millisecond) {
|
|
565
580
|
if (dateOrHour instanceof Date) {
|
|
566
581
|
return new PlainTimeImpl(dateOrHour.getHours(), dateOrHour.getMinutes(), dateOrHour.getSeconds(), dateOrHour.getMilliseconds());
|
|
567
582
|
}
|
|
@@ -570,7 +585,7 @@ export function toPlainTime(dateOrHour, minute, second, millisecond) {
|
|
|
570
585
|
}
|
|
571
586
|
return new PlainTimeImpl(dateOrHour, minute, second, millisecond);
|
|
572
587
|
}
|
|
573
|
-
|
|
588
|
+
function toPlainDateTime(dateOrYear, month, day, hour, minute, second, millisecond) {
|
|
574
589
|
if (dateOrYear instanceof Date) {
|
|
575
590
|
return new PlainDateTimeImpl(dateOrYear.getFullYear(), dateOrYear.getMonth() + 1, dateOrYear.getDate(), dateOrYear.getHours(), dateOrYear.getMinutes(), dateOrYear.getSeconds(), dateOrYear.getMilliseconds());
|
|
576
591
|
}
|
|
@@ -582,10 +597,10 @@ export function toPlainDateTime(dateOrYear, month, day, hour, minute, second, mi
|
|
|
582
597
|
/**
|
|
583
598
|
* Create a ZonedDateTime from a Date object and timezone
|
|
584
599
|
*/
|
|
585
|
-
|
|
600
|
+
function toZonedDateTime(date, timeZone) {
|
|
586
601
|
return new ZonedDateTimeImpl(date.getTime(), timeZone);
|
|
587
602
|
}
|
|
588
|
-
|
|
603
|
+
function toInstant(dateOrEpoch) {
|
|
589
604
|
if (dateOrEpoch instanceof Date) {
|
|
590
605
|
return new InstantImpl(dateOrEpoch.getTime());
|
|
591
606
|
}
|
|
@@ -597,13 +612,13 @@ export function toInstant(dateOrEpoch) {
|
|
|
597
612
|
/**
|
|
598
613
|
* Create a Duration from components
|
|
599
614
|
*/
|
|
600
|
-
|
|
615
|
+
function createDuration(fields = {}) {
|
|
601
616
|
return new DurationImpl(fields);
|
|
602
617
|
}
|
|
603
618
|
/**
|
|
604
619
|
* Parse an ISO 8601 duration string
|
|
605
620
|
*/
|
|
606
|
-
|
|
621
|
+
function parseDuration(str) {
|
|
607
622
|
const match = str.match(/^(-)?P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)W)?(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+(?:\.\d+)?)S)?)?$/);
|
|
608
623
|
if (!match)
|
|
609
624
|
throw new Error(`Invalid duration: ${str}`);
|
|
@@ -625,36 +640,36 @@ export function parseDuration(str) {
|
|
|
625
640
|
/**
|
|
626
641
|
* Get current instant
|
|
627
642
|
*/
|
|
628
|
-
|
|
643
|
+
function nowInstant() {
|
|
629
644
|
return new InstantImpl(Date.now());
|
|
630
645
|
}
|
|
631
646
|
/**
|
|
632
647
|
* Get current PlainDateTime in local timezone
|
|
633
648
|
*/
|
|
634
|
-
|
|
649
|
+
function nowPlainDateTime() {
|
|
635
650
|
return toPlainDateTime(new Date());
|
|
636
651
|
}
|
|
637
652
|
/**
|
|
638
653
|
* Get current PlainDate in local timezone
|
|
639
654
|
*/
|
|
640
|
-
|
|
655
|
+
function nowPlainDate() {
|
|
641
656
|
return toPlainDate(new Date());
|
|
642
657
|
}
|
|
643
658
|
/**
|
|
644
659
|
* Get current PlainTime in local timezone
|
|
645
660
|
*/
|
|
646
|
-
|
|
661
|
+
function nowPlainTime() {
|
|
647
662
|
return toPlainTime(new Date());
|
|
648
663
|
}
|
|
649
664
|
/**
|
|
650
665
|
* Get current ZonedDateTime in specified timezone
|
|
651
666
|
*/
|
|
652
|
-
|
|
667
|
+
function nowZonedDateTime(timeZone) {
|
|
653
668
|
return toZonedDateTime(new Date(), timeZone);
|
|
654
669
|
}
|
|
655
670
|
/**
|
|
656
671
|
* Convert Temporal-like object back to Date
|
|
657
672
|
*/
|
|
658
|
-
|
|
673
|
+
function fromTemporal(temporal) {
|
|
659
674
|
return temporal.toDate();
|
|
660
675
|
}
|