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,3 +1,4 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
/**
|
|
2
3
|
* Fluent chain API for ts-time-utils
|
|
3
4
|
*
|
|
@@ -9,14 +10,18 @@
|
|
|
9
10
|
* .format('YYYY-MM-DD')
|
|
10
11
|
* ```
|
|
11
12
|
*/
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.ChainedDate = void 0;
|
|
15
|
+
exports.chain = chain;
|
|
16
|
+
exports.formatMs = formatMs;
|
|
17
|
+
const calculate_js_1 = require("./calculate.cjs");
|
|
18
|
+
const format_js_1 = require("./format.cjs");
|
|
19
|
+
const validate_js_1 = require("./validate.cjs");
|
|
15
20
|
/**
|
|
16
21
|
* Immutable chainable date wrapper
|
|
17
22
|
* All transformation methods return a new ChainedDate instance
|
|
18
23
|
*/
|
|
19
|
-
|
|
24
|
+
class ChainedDate {
|
|
20
25
|
constructor(date = new Date()) {
|
|
21
26
|
if (date instanceof Date) {
|
|
22
27
|
this._date = new Date(date.getTime());
|
|
@@ -34,28 +39,28 @@ export class ChainedDate {
|
|
|
34
39
|
* @example chain(date).add(1, 'day').add(2, 'hours')
|
|
35
40
|
*/
|
|
36
41
|
add(amount, unit) {
|
|
37
|
-
return new ChainedDate(addTime(this._date, amount, unit));
|
|
42
|
+
return new ChainedDate((0, calculate_js_1.addTime)(this._date, amount, unit));
|
|
38
43
|
}
|
|
39
44
|
/**
|
|
40
45
|
* Subtract time from the date
|
|
41
46
|
* @example chain(date).subtract(1, 'week')
|
|
42
47
|
*/
|
|
43
48
|
subtract(amount, unit) {
|
|
44
|
-
return new ChainedDate(subtractTime(this._date, amount, unit));
|
|
49
|
+
return new ChainedDate((0, calculate_js_1.subtractTime)(this._date, amount, unit));
|
|
45
50
|
}
|
|
46
51
|
/**
|
|
47
52
|
* Get the start of a time period
|
|
48
53
|
* @example chain(date).startOf('month')
|
|
49
54
|
*/
|
|
50
55
|
startOf(unit) {
|
|
51
|
-
return new ChainedDate(startOf(this._date, unit));
|
|
56
|
+
return new ChainedDate((0, calculate_js_1.startOf)(this._date, unit));
|
|
52
57
|
}
|
|
53
58
|
/**
|
|
54
59
|
* Get the end of a time period
|
|
55
60
|
* @example chain(date).endOf('day')
|
|
56
61
|
*/
|
|
57
62
|
endOf(unit) {
|
|
58
|
-
return new ChainedDate(endOf(this._date, unit));
|
|
63
|
+
return new ChainedDate((0, calculate_js_1.endOf)(this._date, unit));
|
|
59
64
|
}
|
|
60
65
|
/**
|
|
61
66
|
* Set specific date/time components
|
|
@@ -91,28 +96,28 @@ export class ChainedDate {
|
|
|
91
96
|
* @example chain(date).format('YYYY-MM-DD') // "2025-01-15"
|
|
92
97
|
*/
|
|
93
98
|
format(pattern) {
|
|
94
|
-
return formatDate(this._date, pattern);
|
|
99
|
+
return (0, format_js_1.formatDate)(this._date, pattern);
|
|
95
100
|
}
|
|
96
101
|
/**
|
|
97
102
|
* Format time in 12h, 24h, or ISO format
|
|
98
103
|
* @example chain(date).formatTime('12h') // "2:30 PM"
|
|
99
104
|
*/
|
|
100
105
|
formatTime(fmt = '24h') {
|
|
101
|
-
return formatTime(this._date, fmt);
|
|
106
|
+
return (0, format_js_1.formatTime)(this._date, fmt);
|
|
102
107
|
}
|
|
103
108
|
/**
|
|
104
109
|
* Format as calendar date (Today, Yesterday, Monday, etc.)
|
|
105
110
|
* @example chain(date).calendar() // "Tomorrow"
|
|
106
111
|
*/
|
|
107
112
|
calendar() {
|
|
108
|
-
return formatCalendarDate(this._date);
|
|
113
|
+
return (0, format_js_1.formatCalendarDate)(this._date);
|
|
109
114
|
}
|
|
110
115
|
/**
|
|
111
116
|
* Get relative time string
|
|
112
117
|
* @example chain(pastDate).ago() // "3 hours ago"
|
|
113
118
|
*/
|
|
114
119
|
ago(options) {
|
|
115
|
-
return timeAgo(this._date, options);
|
|
120
|
+
return (0, format_js_1.timeAgo)(this._date, options);
|
|
116
121
|
}
|
|
117
122
|
/**
|
|
118
123
|
* Get ISO string
|
|
@@ -131,110 +136,110 @@ export class ChainedDate {
|
|
|
131
136
|
* @example chain(date).dayOrdinal() // "15th"
|
|
132
137
|
*/
|
|
133
138
|
dayOrdinal() {
|
|
134
|
-
return formatOrdinal(this._date.getDate());
|
|
139
|
+
return (0, format_js_1.formatOrdinal)(this._date.getDate());
|
|
135
140
|
}
|
|
136
141
|
// ============ Comparisons (return boolean) ============
|
|
137
142
|
/**
|
|
138
143
|
* Check if date is valid
|
|
139
144
|
*/
|
|
140
145
|
isValid() {
|
|
141
|
-
return isValidDate(this._date);
|
|
146
|
+
return (0, validate_js_1.isValidDate)(this._date);
|
|
142
147
|
}
|
|
143
148
|
/**
|
|
144
149
|
* Check if date is today
|
|
145
150
|
*/
|
|
146
151
|
isToday() {
|
|
147
|
-
return isToday(this._date);
|
|
152
|
+
return (0, validate_js_1.isToday)(this._date);
|
|
148
153
|
}
|
|
149
154
|
/**
|
|
150
155
|
* Check if date is yesterday
|
|
151
156
|
*/
|
|
152
157
|
isYesterday() {
|
|
153
|
-
return isYesterday(this._date);
|
|
158
|
+
return (0, validate_js_1.isYesterday)(this._date);
|
|
154
159
|
}
|
|
155
160
|
/**
|
|
156
161
|
* Check if date is tomorrow
|
|
157
162
|
*/
|
|
158
163
|
isTomorrow() {
|
|
159
|
-
return isTomorrow(this._date);
|
|
164
|
+
return (0, validate_js_1.isTomorrow)(this._date);
|
|
160
165
|
}
|
|
161
166
|
/**
|
|
162
167
|
* Check if date is in the past
|
|
163
168
|
*/
|
|
164
169
|
isPast() {
|
|
165
|
-
return isPast(this._date);
|
|
170
|
+
return (0, validate_js_1.isPast)(this._date);
|
|
166
171
|
}
|
|
167
172
|
/**
|
|
168
173
|
* Check if date is in the future
|
|
169
174
|
*/
|
|
170
175
|
isFuture() {
|
|
171
|
-
return isFuture(this._date);
|
|
176
|
+
return (0, validate_js_1.isFuture)(this._date);
|
|
172
177
|
}
|
|
173
178
|
/**
|
|
174
179
|
* Check if date is a weekend
|
|
175
180
|
*/
|
|
176
181
|
isWeekend() {
|
|
177
|
-
return isWeekend(this._date);
|
|
182
|
+
return (0, validate_js_1.isWeekend)(this._date);
|
|
178
183
|
}
|
|
179
184
|
/**
|
|
180
185
|
* Check if date is a weekday
|
|
181
186
|
*/
|
|
182
187
|
isWeekday() {
|
|
183
|
-
return isWeekday(this._date);
|
|
188
|
+
return (0, validate_js_1.isWeekday)(this._date);
|
|
184
189
|
}
|
|
185
190
|
/**
|
|
186
191
|
* Check if date is in this week
|
|
187
192
|
*/
|
|
188
193
|
isThisWeek() {
|
|
189
|
-
return isThisWeek(this._date);
|
|
194
|
+
return (0, validate_js_1.isThisWeek)(this._date);
|
|
190
195
|
}
|
|
191
196
|
/**
|
|
192
197
|
* Check if date is in this month
|
|
193
198
|
*/
|
|
194
199
|
isThisMonth() {
|
|
195
|
-
return isThisMonth(this._date);
|
|
200
|
+
return (0, validate_js_1.isThisMonth)(this._date);
|
|
196
201
|
}
|
|
197
202
|
/**
|
|
198
203
|
* Check if date is in this year
|
|
199
204
|
*/
|
|
200
205
|
isThisYear() {
|
|
201
|
-
return isThisYear(this._date);
|
|
206
|
+
return (0, validate_js_1.isThisYear)(this._date);
|
|
202
207
|
}
|
|
203
208
|
/**
|
|
204
209
|
* Check if year is a leap year
|
|
205
210
|
*/
|
|
206
211
|
isLeapYear() {
|
|
207
|
-
return isLeapYear(this._date.getFullYear());
|
|
212
|
+
return (0, validate_js_1.isLeapYear)(this._date.getFullYear());
|
|
208
213
|
}
|
|
209
214
|
/**
|
|
210
215
|
* Check if date is a business day
|
|
211
216
|
*/
|
|
212
217
|
isBusinessDay(holidays) {
|
|
213
|
-
return isBusinessDay(this._date, holidays);
|
|
218
|
+
return (0, validate_js_1.isBusinessDay)(this._date, holidays);
|
|
214
219
|
}
|
|
215
220
|
/**
|
|
216
221
|
* Check if date is same day as another
|
|
217
222
|
*/
|
|
218
223
|
isSameDay(other) {
|
|
219
|
-
return isSameDay(this._date, toDate(other));
|
|
224
|
+
return (0, validate_js_1.isSameDay)(this._date, toDate(other));
|
|
220
225
|
}
|
|
221
226
|
/**
|
|
222
227
|
* Check if date is same week as another
|
|
223
228
|
*/
|
|
224
229
|
isSameWeek(other) {
|
|
225
|
-
return isSameWeek(this._date, toDate(other));
|
|
230
|
+
return (0, validate_js_1.isSameWeek)(this._date, toDate(other));
|
|
226
231
|
}
|
|
227
232
|
/**
|
|
228
233
|
* Check if date is same month as another
|
|
229
234
|
*/
|
|
230
235
|
isSameMonth(other) {
|
|
231
|
-
return isSameMonth(this._date, toDate(other));
|
|
236
|
+
return (0, validate_js_1.isSameMonth)(this._date, toDate(other));
|
|
232
237
|
}
|
|
233
238
|
/**
|
|
234
239
|
* Check if date is same year as another
|
|
235
240
|
*/
|
|
236
241
|
isSameYear(other) {
|
|
237
|
-
return isSameYear(this._date, toDate(other));
|
|
242
|
+
return (0, validate_js_1.isSameYear)(this._date, toDate(other));
|
|
238
243
|
}
|
|
239
244
|
/**
|
|
240
245
|
* Check if date is before another
|
|
@@ -252,7 +257,7 @@ export class ChainedDate {
|
|
|
252
257
|
* Check if date is between two dates
|
|
253
258
|
*/
|
|
254
259
|
isBetween(start, end, inclusive) {
|
|
255
|
-
return isBetween(this._date, toDate(start), toDate(end), inclusive);
|
|
260
|
+
return (0, calculate_js_1.isBetween)(this._date, toDate(start), toDate(end), inclusive);
|
|
256
261
|
}
|
|
257
262
|
// ============ Getters (return number) ============
|
|
258
263
|
/**
|
|
@@ -260,7 +265,7 @@ export class ChainedDate {
|
|
|
260
265
|
* @example chain(date).diff(other, 'days') // 5
|
|
261
266
|
*/
|
|
262
267
|
diff(other, unit = 'milliseconds', precise = true) {
|
|
263
|
-
return differenceInUnits(this._date, toDate(other), unit, precise);
|
|
268
|
+
return (0, calculate_js_1.differenceInUnits)(this._date, toDate(other), unit, precise);
|
|
264
269
|
}
|
|
265
270
|
/**
|
|
266
271
|
* Get the timestamp (milliseconds since epoch)
|
|
@@ -389,6 +394,7 @@ export class ChainedDate {
|
|
|
389
394
|
};
|
|
390
395
|
}
|
|
391
396
|
}
|
|
397
|
+
exports.ChainedDate = ChainedDate;
|
|
392
398
|
/**
|
|
393
399
|
* Helper to convert DateInput to Date
|
|
394
400
|
*/
|
|
@@ -404,7 +410,7 @@ function toDate(input) {
|
|
|
404
410
|
* chain('2025-01-15').startOf('month').toDate()
|
|
405
411
|
* chain().add(1, 'week').isWeekend()
|
|
406
412
|
*/
|
|
407
|
-
|
|
413
|
+
function chain(date) {
|
|
408
414
|
return new ChainedDate(date);
|
|
409
415
|
}
|
|
410
416
|
/**
|
|
@@ -412,11 +418,6 @@ export function chain(date) {
|
|
|
412
418
|
* Convenience export for use with chain().diff()
|
|
413
419
|
* @example formatMs(chain(a).diff(b)) // "2 days, 3 hours"
|
|
414
420
|
*/
|
|
415
|
-
|
|
416
|
-
return formatDuration(ms, options);
|
|
417
|
-
}
|
|
418
|
-
// Initialize plugin system if it's available
|
|
419
|
-
// This allows plugins to extend ChainedDate
|
|
420
|
-
if (typeof globalThis !== 'undefined') {
|
|
421
|
-
globalThis.__chainedDateClass = ChainedDate;
|
|
421
|
+
function formatMs(ms, options) {
|
|
422
|
+
return (0, format_js_1.formatDuration)(ms, options);
|
|
422
423
|
}
|
|
@@ -1,6 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
/**
|
|
2
3
|
* @fileoverview Date comparison, sorting, and array manipulation utilities
|
|
3
4
|
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.compareDates = compareDates;
|
|
7
|
+
exports.compareDatesDesc = compareDatesDesc;
|
|
8
|
+
exports.sortDates = sortDates;
|
|
9
|
+
exports.minDate = minDate;
|
|
10
|
+
exports.maxDate = maxDate;
|
|
11
|
+
exports.dateExtent = dateExtent;
|
|
12
|
+
exports.uniqueDates = uniqueDates;
|
|
13
|
+
exports.closestDate = closestDate;
|
|
14
|
+
exports.closestFutureDate = closestFutureDate;
|
|
15
|
+
exports.closestPastDate = closestPastDate;
|
|
16
|
+
exports.clampDate = clampDate;
|
|
17
|
+
exports.isDateInRange = isDateInRange;
|
|
18
|
+
exports.filterDatesInRange = filterDatesInRange;
|
|
19
|
+
exports.groupDates = groupDates;
|
|
20
|
+
exports.groupDatesByYear = groupDatesByYear;
|
|
21
|
+
exports.groupDatesByMonth = groupDatesByMonth;
|
|
22
|
+
exports.groupDatesByDay = groupDatesByDay;
|
|
23
|
+
exports.groupDatesByDayOfWeek = groupDatesByDayOfWeek;
|
|
24
|
+
exports.medianDate = medianDate;
|
|
25
|
+
exports.averageDate = averageDate;
|
|
26
|
+
exports.roundDate = roundDate;
|
|
27
|
+
exports.snapDate = snapDate;
|
|
28
|
+
exports.isChronological = isChronological;
|
|
29
|
+
exports.dateSpan = dateSpan;
|
|
30
|
+
exports.partitionDates = partitionDates;
|
|
31
|
+
exports.nthDate = nthDate;
|
|
32
|
+
exports.closestIndexTo = closestIndexTo;
|
|
33
|
+
exports.getOverlappingDaysInIntervals = getOverlappingDaysInIntervals;
|
|
4
34
|
/**
|
|
5
35
|
* Compare two dates for sorting
|
|
6
36
|
* @param a - First date
|
|
@@ -9,7 +39,7 @@
|
|
|
9
39
|
* @example
|
|
10
40
|
* [date3, date1, date2].sort(compareDates) // [date1, date2, date3]
|
|
11
41
|
*/
|
|
12
|
-
|
|
42
|
+
function compareDates(a, b) {
|
|
13
43
|
return a.getTime() - b.getTime();
|
|
14
44
|
}
|
|
15
45
|
/**
|
|
@@ -20,7 +50,7 @@ export function compareDates(a, b) {
|
|
|
20
50
|
* @example
|
|
21
51
|
* [date1, date3, date2].sort(compareDatesDesc) // [date3, date2, date1]
|
|
22
52
|
*/
|
|
23
|
-
|
|
53
|
+
function compareDatesDesc(a, b) {
|
|
24
54
|
return b.getTime() - a.getTime();
|
|
25
55
|
}
|
|
26
56
|
/**
|
|
@@ -32,7 +62,7 @@ export function compareDatesDesc(a, b) {
|
|
|
32
62
|
* sortDates([date3, date1, date2]) // [date1, date2, date3]
|
|
33
63
|
* sortDates([date1, date2, date3], 'desc') // [date3, date2, date1]
|
|
34
64
|
*/
|
|
35
|
-
|
|
65
|
+
function sortDates(dates, direction = 'asc') {
|
|
36
66
|
const sorted = [...dates];
|
|
37
67
|
sorted.sort(direction === 'asc' ? compareDates : compareDatesDesc);
|
|
38
68
|
return sorted;
|
|
@@ -44,7 +74,7 @@ export function sortDates(dates, direction = 'asc') {
|
|
|
44
74
|
* @example
|
|
45
75
|
* minDate([date2, date1, date3]) // date1
|
|
46
76
|
*/
|
|
47
|
-
|
|
77
|
+
function minDate(dates) {
|
|
48
78
|
if (dates.length === 0)
|
|
49
79
|
return undefined;
|
|
50
80
|
return dates.reduce((min, date) => (date < min ? date : min));
|
|
@@ -56,7 +86,7 @@ export function minDate(dates) {
|
|
|
56
86
|
* @example
|
|
57
87
|
* maxDate([date1, date3, date2]) // date3
|
|
58
88
|
*/
|
|
59
|
-
|
|
89
|
+
function maxDate(dates) {
|
|
60
90
|
if (dates.length === 0)
|
|
61
91
|
return undefined;
|
|
62
92
|
return dates.reduce((max, date) => (date > max ? date : max));
|
|
@@ -68,7 +98,7 @@ export function maxDate(dates) {
|
|
|
68
98
|
* @example
|
|
69
99
|
* dateRange([date2, date1, date3]) // { min: date1, max: date3 }
|
|
70
100
|
*/
|
|
71
|
-
|
|
101
|
+
function dateExtent(dates) {
|
|
72
102
|
if (dates.length === 0)
|
|
73
103
|
return undefined;
|
|
74
104
|
let min = dates[0];
|
|
@@ -89,7 +119,7 @@ export function dateExtent(dates) {
|
|
|
89
119
|
* @example
|
|
90
120
|
* uniqueDates([date1, date1Copy, date2]) // [date1, date2]
|
|
91
121
|
*/
|
|
92
|
-
|
|
122
|
+
function uniqueDates(dates, precision = 'ms') {
|
|
93
123
|
const seen = new Set();
|
|
94
124
|
const result = [];
|
|
95
125
|
for (const date of dates) {
|
|
@@ -126,7 +156,7 @@ function getDateKey(date, precision) {
|
|
|
126
156
|
* @example
|
|
127
157
|
* closestDate(targetDate, [date1, date2, date3]) // closest to target
|
|
128
158
|
*/
|
|
129
|
-
|
|
159
|
+
function closestDate(target, candidates) {
|
|
130
160
|
if (candidates.length === 0)
|
|
131
161
|
return undefined;
|
|
132
162
|
const targetTime = target.getTime();
|
|
@@ -147,7 +177,7 @@ export function closestDate(target, candidates) {
|
|
|
147
177
|
* @param candidates - Array of candidate dates
|
|
148
178
|
* @returns The closest future date, or undefined if none found
|
|
149
179
|
*/
|
|
150
|
-
|
|
180
|
+
function closestFutureDate(target, candidates) {
|
|
151
181
|
const targetTime = target.getTime();
|
|
152
182
|
const futureDates = candidates.filter(d => d.getTime() > targetTime);
|
|
153
183
|
return minDate(futureDates);
|
|
@@ -158,7 +188,7 @@ export function closestFutureDate(target, candidates) {
|
|
|
158
188
|
* @param candidates - Array of candidate dates
|
|
159
189
|
* @returns The closest past date, or undefined if none found
|
|
160
190
|
*/
|
|
161
|
-
|
|
191
|
+
function closestPastDate(target, candidates) {
|
|
162
192
|
const targetTime = target.getTime();
|
|
163
193
|
const pastDates = candidates.filter(d => d.getTime() < targetTime);
|
|
164
194
|
return maxDate(pastDates);
|
|
@@ -174,7 +204,7 @@ export function closestPastDate(target, candidates) {
|
|
|
174
204
|
* clampDate(lateDate, minDate, maxDate) // returns maxDate
|
|
175
205
|
* clampDate(middleDate, minDate, maxDate) // returns middleDate
|
|
176
206
|
*/
|
|
177
|
-
|
|
207
|
+
function clampDate(date, min, max) {
|
|
178
208
|
if (date < min)
|
|
179
209
|
return new Date(min);
|
|
180
210
|
if (date > max)
|
|
@@ -188,7 +218,7 @@ export function clampDate(date, min, max) {
|
|
|
188
218
|
* @param max - End of range
|
|
189
219
|
* @returns True if date is within range
|
|
190
220
|
*/
|
|
191
|
-
|
|
221
|
+
function isDateInRange(date, min, max) {
|
|
192
222
|
const time = date.getTime();
|
|
193
223
|
return time >= min.getTime() && time <= max.getTime();
|
|
194
224
|
}
|
|
@@ -199,7 +229,7 @@ export function isDateInRange(date, min, max) {
|
|
|
199
229
|
* @param max - End of range
|
|
200
230
|
* @returns New array with only dates in range
|
|
201
231
|
*/
|
|
202
|
-
|
|
232
|
+
function filterDatesInRange(dates, min, max) {
|
|
203
233
|
return dates.filter(date => isDateInRange(date, min, max));
|
|
204
234
|
}
|
|
205
235
|
/**
|
|
@@ -211,7 +241,7 @@ export function filterDatesInRange(dates, min, max) {
|
|
|
211
241
|
* groupDates(dates, d => d.getFullYear()) // Map { 2023 => [...], 2024 => [...] }
|
|
212
242
|
* groupDates(dates, d => d.toISOString().slice(0, 7)) // Group by month
|
|
213
243
|
*/
|
|
214
|
-
|
|
244
|
+
function groupDates(dates, keyFn) {
|
|
215
245
|
const groups = new Map();
|
|
216
246
|
for (const date of dates) {
|
|
217
247
|
const key = keyFn(date);
|
|
@@ -230,7 +260,7 @@ export function groupDates(dates, keyFn) {
|
|
|
230
260
|
* @param dates - Array of dates
|
|
231
261
|
* @returns Map of year to array of dates
|
|
232
262
|
*/
|
|
233
|
-
|
|
263
|
+
function groupDatesByYear(dates) {
|
|
234
264
|
return groupDates(dates, d => d.getFullYear());
|
|
235
265
|
}
|
|
236
266
|
/**
|
|
@@ -238,7 +268,7 @@ export function groupDatesByYear(dates) {
|
|
|
238
268
|
* @param dates - Array of dates
|
|
239
269
|
* @returns Map of month key to array of dates
|
|
240
270
|
*/
|
|
241
|
-
|
|
271
|
+
function groupDatesByMonth(dates) {
|
|
242
272
|
return groupDates(dates, d => {
|
|
243
273
|
const year = d.getFullYear();
|
|
244
274
|
const month = String(d.getMonth() + 1).padStart(2, '0');
|
|
@@ -250,7 +280,7 @@ export function groupDatesByMonth(dates) {
|
|
|
250
280
|
* @param dates - Array of dates
|
|
251
281
|
* @returns Map of day key to array of dates
|
|
252
282
|
*/
|
|
253
|
-
|
|
283
|
+
function groupDatesByDay(dates) {
|
|
254
284
|
return groupDates(dates, d => d.toISOString().slice(0, 10));
|
|
255
285
|
}
|
|
256
286
|
/**
|
|
@@ -258,7 +288,7 @@ export function groupDatesByDay(dates) {
|
|
|
258
288
|
* @param dates - Array of dates
|
|
259
289
|
* @returns Map of day of week to array of dates
|
|
260
290
|
*/
|
|
261
|
-
|
|
291
|
+
function groupDatesByDayOfWeek(dates) {
|
|
262
292
|
return groupDates(dates, d => d.getDay());
|
|
263
293
|
}
|
|
264
294
|
/**
|
|
@@ -266,7 +296,7 @@ export function groupDatesByDayOfWeek(dates) {
|
|
|
266
296
|
* @param dates - Array of dates
|
|
267
297
|
* @returns The median date, or undefined if array is empty
|
|
268
298
|
*/
|
|
269
|
-
|
|
299
|
+
function medianDate(dates) {
|
|
270
300
|
if (dates.length === 0)
|
|
271
301
|
return undefined;
|
|
272
302
|
const sorted = sortDates(dates);
|
|
@@ -284,7 +314,7 @@ export function medianDate(dates) {
|
|
|
284
314
|
* @param dates - Array of dates
|
|
285
315
|
* @returns The average date, or undefined if array is empty
|
|
286
316
|
*/
|
|
287
|
-
|
|
317
|
+
function averageDate(dates) {
|
|
288
318
|
if (dates.length === 0)
|
|
289
319
|
return undefined;
|
|
290
320
|
const sum = dates.reduce((acc, date) => acc + date.getTime(), 0);
|
|
@@ -299,7 +329,7 @@ export function averageDate(dates) {
|
|
|
299
329
|
* roundDate(new Date('2024-03-15T14:37:00'), 'hour') // 2024-03-15T15:00:00
|
|
300
330
|
* roundDate(new Date('2024-03-15T14:22:00'), 'hour') // 2024-03-15T14:00:00
|
|
301
331
|
*/
|
|
302
|
-
|
|
332
|
+
function roundDate(date, unit) {
|
|
303
333
|
const d = new Date(date);
|
|
304
334
|
switch (unit) {
|
|
305
335
|
case 'minute':
|
|
@@ -333,7 +363,7 @@ export function roundDate(date, unit) {
|
|
|
333
363
|
* snapDate(new Date('2024-03-15T14:37:00'), 15) // 2024-03-15T14:30:00
|
|
334
364
|
* snapDate(new Date('2024-03-15T14:37:00'), 15, 'ceil') // 2024-03-15T14:45:00
|
|
335
365
|
*/
|
|
336
|
-
|
|
366
|
+
function snapDate(date, intervalMinutes, mode = 'round') {
|
|
337
367
|
const ms = date.getTime();
|
|
338
368
|
const intervalMs = intervalMinutes * 60 * 1000;
|
|
339
369
|
let snapped;
|
|
@@ -356,7 +386,7 @@ export function snapDate(date, intervalMinutes, mode = 'round') {
|
|
|
356
386
|
* @param strict - If true, requires strictly increasing (no duplicates)
|
|
357
387
|
* @returns True if dates are in order
|
|
358
388
|
*/
|
|
359
|
-
|
|
389
|
+
function isChronological(dates, strict = false) {
|
|
360
390
|
for (let i = 1; i < dates.length; i++) {
|
|
361
391
|
const prev = dates[i - 1].getTime();
|
|
362
392
|
const curr = dates[i].getTime();
|
|
@@ -371,7 +401,7 @@ export function isChronological(dates, strict = false) {
|
|
|
371
401
|
* @param dates - Array of dates
|
|
372
402
|
* @returns Duration in milliseconds, or 0 if less than 2 dates
|
|
373
403
|
*/
|
|
374
|
-
|
|
404
|
+
function dateSpan(dates) {
|
|
375
405
|
const extent = dateExtent(dates);
|
|
376
406
|
if (!extent)
|
|
377
407
|
return 0;
|
|
@@ -383,7 +413,7 @@ export function dateSpan(dates) {
|
|
|
383
413
|
* @param predicate - Function that returns true for dates in first partition
|
|
384
414
|
* @returns Tuple of [matching, non-matching] date arrays
|
|
385
415
|
*/
|
|
386
|
-
|
|
416
|
+
function partitionDates(dates, predicate) {
|
|
387
417
|
const matching = [];
|
|
388
418
|
const nonMatching = [];
|
|
389
419
|
for (const date of dates) {
|
|
@@ -406,7 +436,7 @@ export function partitionDates(dates, predicate) {
|
|
|
406
436
|
* nthDate(dates, -1) // latest
|
|
407
437
|
* nthDate(dates, 2) // third earliest
|
|
408
438
|
*/
|
|
409
|
-
|
|
439
|
+
function nthDate(dates, n) {
|
|
410
440
|
if (dates.length === 0)
|
|
411
441
|
return undefined;
|
|
412
442
|
const sorted = sortDates(dates);
|
|
@@ -423,7 +453,7 @@ export function nthDate(dates, n) {
|
|
|
423
453
|
* @example
|
|
424
454
|
* closestIndexTo([date1, date2, date3], targetDate) // 1
|
|
425
455
|
*/
|
|
426
|
-
|
|
456
|
+
function closestIndexTo(dates, target) {
|
|
427
457
|
if (dates.length === 0)
|
|
428
458
|
return -1;
|
|
429
459
|
const targetTime = target.getTime();
|
|
@@ -449,7 +479,7 @@ export function closestIndexTo(dates, target) {
|
|
|
449
479
|
* { start: new Date('2024-01-05'), end: new Date('2024-01-15') }
|
|
450
480
|
* ) // 6 (Jan 5-10 inclusive)
|
|
451
481
|
*/
|
|
452
|
-
|
|
482
|
+
function getOverlappingDaysInIntervals(range1, range2) {
|
|
453
483
|
const start1 = new Date(range1.start.getFullYear(), range1.start.getMonth(), range1.start.getDate());
|
|
454
484
|
const end1 = new Date(range1.end.getFullYear(), range1.end.getMonth(), range1.end.getDate());
|
|
455
485
|
const start2 = new Date(range2.start.getFullYear(), range2.start.getMonth(), range2.start.getDate());
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Constants for time conversions and utility types
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.SECONDS_PER_WEEK = exports.SECONDS_PER_DAY = exports.SECONDS_PER_HOUR = exports.SECONDS_PER_MINUTE = exports.MILLISECONDS_PER_YEAR = exports.MILLISECONDS_PER_MONTH = exports.MILLISECONDS_PER_WEEK = exports.MILLISECONDS_PER_DAY = exports.MILLISECONDS_PER_HOUR = exports.MILLISECONDS_PER_MINUTE = exports.MILLISECONDS_PER_SECOND = void 0;
|
|
7
|
+
// Milliseconds per unit
|
|
8
|
+
exports.MILLISECONDS_PER_SECOND = 1000;
|
|
9
|
+
exports.MILLISECONDS_PER_MINUTE = 60 * 1000;
|
|
10
|
+
exports.MILLISECONDS_PER_HOUR = 60 * 60 * 1000;
|
|
11
|
+
exports.MILLISECONDS_PER_DAY = 24 * 60 * 60 * 1000;
|
|
12
|
+
exports.MILLISECONDS_PER_WEEK = 7 * 24 * 60 * 60 * 1000;
|
|
13
|
+
exports.MILLISECONDS_PER_MONTH = 30 * 24 * 60 * 60 * 1000; // Approximate
|
|
14
|
+
exports.MILLISECONDS_PER_YEAR = 365 * 24 * 60 * 60 * 1000; // Approximate
|
|
15
|
+
// Seconds per unit
|
|
16
|
+
exports.SECONDS_PER_MINUTE = 60;
|
|
17
|
+
exports.SECONDS_PER_HOUR = 60 * 60;
|
|
18
|
+
exports.SECONDS_PER_DAY = 24 * 60 * 60;
|
|
19
|
+
exports.SECONDS_PER_WEEK = 7 * 24 * 60 * 60;
|
|
@@ -1,7 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
/**
|
|
2
3
|
* @fileoverview Countdown and timer utilities for tracking time until/since a target date
|
|
3
4
|
* Provides countdown timers, remaining time calculations, and progress tracking
|
|
4
5
|
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.createCountdown = createCountdown;
|
|
8
|
+
exports.getRemainingTime = getRemainingTime;
|
|
9
|
+
exports.formatCountdown = formatCountdown;
|
|
10
|
+
exports.isExpired = isExpired;
|
|
11
|
+
exports.getProgressPercentage = getProgressPercentage;
|
|
12
|
+
exports.getTimeUntil = getTimeUntil;
|
|
13
|
+
exports.createDeadline = createDeadline;
|
|
5
14
|
/**
|
|
6
15
|
* Creates a countdown timer to a target date
|
|
7
16
|
* @param targetDate - The date to count down to
|
|
@@ -27,7 +36,7 @@
|
|
|
27
36
|
* countdown.stop();
|
|
28
37
|
* ```
|
|
29
38
|
*/
|
|
30
|
-
|
|
39
|
+
function createCountdown(targetDate, options = {}) {
|
|
31
40
|
let target = new Date(targetDate);
|
|
32
41
|
let intervalId = null;
|
|
33
42
|
let running = false;
|
|
@@ -106,7 +115,7 @@ export function createCountdown(targetDate, options = {}) {
|
|
|
106
115
|
* }
|
|
107
116
|
* ```
|
|
108
117
|
*/
|
|
109
|
-
|
|
118
|
+
function getRemainingTime(targetDate, fromDate = new Date()) {
|
|
110
119
|
const target = new Date(targetDate);
|
|
111
120
|
const from = new Date(fromDate);
|
|
112
121
|
const totalMilliseconds = target.getTime() - from.getTime();
|
|
@@ -156,7 +165,7 @@ export function getRemainingTime(targetDate, fromDate = new Date()) {
|
|
|
156
165
|
* // "45 days 12 hours 30 minutes 15 seconds"
|
|
157
166
|
* ```
|
|
158
167
|
*/
|
|
159
|
-
|
|
168
|
+
function formatCountdown(targetDate, options = {}) {
|
|
160
169
|
const { from, units = ['days', 'hours', 'minutes', 'seconds'], short = true, maxUnits, showZero = false, separator = ' ' } = options;
|
|
161
170
|
const remaining = getRemainingTime(targetDate, from);
|
|
162
171
|
if (remaining.isExpired) {
|
|
@@ -197,7 +206,7 @@ export function formatCountdown(targetDate, options = {}) {
|
|
|
197
206
|
* isExpired(new Date('2030-01-01')); // false
|
|
198
207
|
* ```
|
|
199
208
|
*/
|
|
200
|
-
|
|
209
|
+
function isExpired(date, fromDate = new Date()) {
|
|
201
210
|
const checkDate = new Date(date);
|
|
202
211
|
const from = new Date(fromDate);
|
|
203
212
|
return checkDate.getTime() < from.getTime();
|
|
@@ -219,7 +228,7 @@ export function isExpired(date, fromDate = new Date()) {
|
|
|
219
228
|
* console.log(`${progress}% complete`); // ~50% complete
|
|
220
229
|
* ```
|
|
221
230
|
*/
|
|
222
|
-
|
|
231
|
+
function getProgressPercentage(startDate, endDate, currentDate = new Date()) {
|
|
223
232
|
const start = new Date(startDate).getTime();
|
|
224
233
|
const end = new Date(endDate).getTime();
|
|
225
234
|
const current = new Date(currentDate).getTime();
|
|
@@ -246,7 +255,7 @@ export function getProgressPercentage(startDate, endDate, currentDate = new Date
|
|
|
246
255
|
* getTimeUntil(new Date('2024-12-31'), 'weeks'); // 6.5
|
|
247
256
|
* ```
|
|
248
257
|
*/
|
|
249
|
-
|
|
258
|
+
function getTimeUntil(targetDate, unit, fromDate = new Date()) {
|
|
250
259
|
const remaining = getRemainingTime(targetDate, fromDate);
|
|
251
260
|
switch (unit) {
|
|
252
261
|
case 'milliseconds':
|
|
@@ -281,7 +290,7 @@ export function getTimeUntil(targetDate, unit, fromDate = new Date()) {
|
|
|
281
290
|
* deadline.progressFrom(new Date('2024-01-01')); // 67.5%
|
|
282
291
|
* ```
|
|
283
292
|
*/
|
|
284
|
-
|
|
293
|
+
function createDeadline(targetDate) {
|
|
285
294
|
const target = new Date(targetDate);
|
|
286
295
|
return {
|
|
287
296
|
target,
|