@dereekb/date 13.2.0 → 13.2.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/index.cjs.js +348 -292
- package/index.esm.js +350 -294
- package/package.json +4 -4
- package/src/lib/date/date.calendar.d.ts +0 -8
- package/src/lib/date/date.cell.d.ts +0 -15
- package/src/lib/date/date.cell.index.d.ts +0 -7
- package/src/lib/date/date.cell.schedule.d.ts +0 -8
- package/src/lib/date/date.cell.validator.d.ts +1 -23
- package/src/lib/date/date.duration.d.ts +0 -7
- package/src/lib/date/date.model.d.ts +151 -0
- package/src/lib/date/date.range.d.ts +0 -15
- package/src/lib/date/index.d.ts +1 -0
- package/src/lib/rrule/date.recurrence.d.ts +0 -10
- package/src/lib/timezone/timezone.validator.d.ts +1 -11
package/index.cjs.js
CHANGED
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
var util = require('@dereekb/util');
|
|
4
4
|
var dateFns = require('date-fns');
|
|
5
|
-
var arktype = require('arktype');
|
|
6
5
|
var dateFnsTz = require('date-fns-tz');
|
|
6
|
+
var arktype = require('arktype');
|
|
7
7
|
var tzdb = require('@vvo/tzdb');
|
|
8
|
+
var model = require('@dereekb/model');
|
|
8
9
|
var rxjs = require('rxjs');
|
|
9
10
|
var rrule = require('rrule');
|
|
10
11
|
|
|
@@ -687,13 +688,6 @@ function isDateRangeStart(value) {
|
|
|
687
688
|
* ```
|
|
688
689
|
*/
|
|
689
690
|
const sortDateRangeStartAscendingCompareFunction = sortByDateFunction((x) => x.start);
|
|
690
|
-
/**
|
|
691
|
-
* ArkType schema for {@link DateRange}.
|
|
692
|
-
*/
|
|
693
|
-
const dateRangeType = arktype.type({
|
|
694
|
-
start: 'Date',
|
|
695
|
-
end: 'Date'
|
|
696
|
-
});
|
|
697
691
|
/**
|
|
698
692
|
* Counts the total number of calendar days spanned by the range, inclusive of both endpoints.
|
|
699
693
|
* Always returns at least 1, even for same-day ranges.
|
|
@@ -869,14 +863,6 @@ exports.DateRangeType = void 0;
|
|
|
869
863
|
*/
|
|
870
864
|
DateRangeType["CALENDAR_MONTH"] = "calendar_month";
|
|
871
865
|
})(exports.DateRangeType || (exports.DateRangeType = {}));
|
|
872
|
-
/**
|
|
873
|
-
* ArkType schema for {@link DateRangeParams}.
|
|
874
|
-
*/
|
|
875
|
-
const dateRangeParamsType = arktype.type({
|
|
876
|
-
type: arktype.type.enumerated(...Object.values(exports.DateRangeType)),
|
|
877
|
-
date: 'Date',
|
|
878
|
-
'distance?': 'number'
|
|
879
|
-
});
|
|
880
866
|
/**
|
|
881
867
|
* Creates a {@link DateRange} from the given type and optional parameters. Supports many range
|
|
882
868
|
* strategies including fixed periods (day, week, month), directional ranges, and radii.
|
|
@@ -1473,75 +1459,6 @@ function getDaysOfWeekInDateRange(dateRange) {
|
|
|
1473
1459
|
return days;
|
|
1474
1460
|
}
|
|
1475
1461
|
|
|
1476
|
-
/**
|
|
1477
|
-
* ArkType schema for {@link DateDurationSpan}.
|
|
1478
|
-
*/
|
|
1479
|
-
const dateDurationSpanType = arktype.type({
|
|
1480
|
-
startsAt: 'Date',
|
|
1481
|
-
duration: 'number >= 0'
|
|
1482
|
-
});
|
|
1483
|
-
/**
|
|
1484
|
-
* Computes the end date for a duration span by adding the duration to the start time.
|
|
1485
|
-
*
|
|
1486
|
-
* @param span - the duration span to compute the end for
|
|
1487
|
-
* @returns the date when the span ends
|
|
1488
|
-
*
|
|
1489
|
-
* @example
|
|
1490
|
-
* ```ts
|
|
1491
|
-
* const span = { startsAt: new Date('2024-01-01T10:00:00Z'), duration: 60 };
|
|
1492
|
-
* dateDurationSpanEndDate(span); // 2024-01-01T11:00:00Z
|
|
1493
|
-
* ```
|
|
1494
|
-
*/
|
|
1495
|
-
function dateDurationSpanEndDate(span) {
|
|
1496
|
-
return dateFns.addMinutes(span.startsAt, span.duration);
|
|
1497
|
-
}
|
|
1498
|
-
/**
|
|
1499
|
-
* Converts a {@link DateDurationSpan} to a {@link DateRange} with start and end dates.
|
|
1500
|
-
*
|
|
1501
|
-
* @param span - the duration span to convert
|
|
1502
|
-
* @returns a date range from startsAt to startsAt + duration
|
|
1503
|
-
*/
|
|
1504
|
-
function durationSpanToDateRange(span) {
|
|
1505
|
-
return {
|
|
1506
|
-
start: span.startsAt,
|
|
1507
|
-
end: dateFns.addMinutes(span.startsAt, span.duration)
|
|
1508
|
-
};
|
|
1509
|
-
}
|
|
1510
|
-
/**
|
|
1511
|
-
* Creates a {@link DateDurationSpan} from a {@link DateRange} by computing the duration in minutes between start and end.
|
|
1512
|
-
*
|
|
1513
|
-
* @param dateRange - the date range to convert
|
|
1514
|
-
* @returns a duration span with the range's start as startsAt
|
|
1515
|
-
*/
|
|
1516
|
-
function durationSpanFromDateRange(dateRange) {
|
|
1517
|
-
return {
|
|
1518
|
-
startsAt: dateRange.start,
|
|
1519
|
-
duration: dateFns.differenceInMinutes(dateRange.end, dateRange.start)
|
|
1520
|
-
};
|
|
1521
|
-
}
|
|
1522
|
-
/**
|
|
1523
|
-
* Determines whether a duration span is in the past, present, or future relative to the given time.
|
|
1524
|
-
*
|
|
1525
|
-
* @param span - the duration span to check
|
|
1526
|
-
* @param now - reference time (defaults to current time)
|
|
1527
|
-
* @returns 'past', 'present', or 'future'
|
|
1528
|
-
*/
|
|
1529
|
-
function durationSpanDateRelativeState(span, now) {
|
|
1530
|
-
return dateRangeRelativeState(durationSpanToDateRange(span), now);
|
|
1531
|
-
}
|
|
1532
|
-
/**
|
|
1533
|
-
* Converts a duration span's duration from minutes to fractional hours.
|
|
1534
|
-
*
|
|
1535
|
-
* @param span - the duration span to measure
|
|
1536
|
-
* @returns the duration expressed as fractional hours (e.g. 90 minutes = 1.5)
|
|
1537
|
-
*/
|
|
1538
|
-
function fractionalHoursInDurationSpan(span) {
|
|
1539
|
-
return util.minutesToFractionalHours(span.duration);
|
|
1540
|
-
}
|
|
1541
|
-
function isSameDurationSpan(a, b) {
|
|
1542
|
-
return util.safeCompareEquality(a, b, (a, b) => a.duration === b.duration && isSameDate(a.startsAt, b.startsAt));
|
|
1543
|
-
}
|
|
1544
|
-
|
|
1545
1462
|
/**
|
|
1546
1463
|
* String code for the start of the current day.
|
|
1547
1464
|
*/
|
|
@@ -2453,158 +2370,6 @@ function copyHoursAndMinutesFromDateWithTimezoneNormal(input, copyFrom, timezone
|
|
|
2453
2370
|
return result;
|
|
2454
2371
|
}
|
|
2455
2372
|
|
|
2456
|
-
/**
|
|
2457
|
-
* Returns all recognized IANA timezone strings, including the explicit UTC entry.
|
|
2458
|
-
*
|
|
2459
|
-
* @example
|
|
2460
|
-
* ```ts
|
|
2461
|
-
* const zones = allTimezoneStrings();
|
|
2462
|
-
* // ['Africa/Abidjan', ..., 'UTC']
|
|
2463
|
-
* ```
|
|
2464
|
-
*/
|
|
2465
|
-
function allTimezoneStrings() {
|
|
2466
|
-
return tzdb.timeZonesNames.concat(util.UTC_TIMEZONE_STRING);
|
|
2467
|
-
}
|
|
2468
|
-
/**
|
|
2469
|
-
* Lazily-computed set of all known timezone strings for O(1) membership checks.
|
|
2470
|
-
*
|
|
2471
|
-
* @example
|
|
2472
|
-
* ```ts
|
|
2473
|
-
* allKnownTimezoneStrings().has('America/New_York'); // true
|
|
2474
|
-
* ```
|
|
2475
|
-
*/
|
|
2476
|
-
const allKnownTimezoneStrings = util.cachedGetter(() => {
|
|
2477
|
-
return new Set(allTimezoneStrings());
|
|
2478
|
-
});
|
|
2479
|
-
/**
|
|
2480
|
-
* Lazily-computed array of {@link TimezoneInfo} for every known timezone.
|
|
2481
|
-
*
|
|
2482
|
-
* Abbreviations are resolved at the time of first access, so results reflect
|
|
2483
|
-
* the DST state at that moment.
|
|
2484
|
-
*/
|
|
2485
|
-
const allTimezoneInfos = util.cachedGetter(() => {
|
|
2486
|
-
const now = new Date();
|
|
2487
|
-
return allTimezoneStrings().map((x) => timezoneStringToTimezoneInfo(x, now));
|
|
2488
|
-
});
|
|
2489
|
-
/**
|
|
2490
|
-
* Returns the {@link TimezoneInfo} for the current system timezone, falling back to UTC.
|
|
2491
|
-
*
|
|
2492
|
-
* @example
|
|
2493
|
-
* ```ts
|
|
2494
|
-
* const info = timezoneInfoForSystem();
|
|
2495
|
-
* console.log(info.abbreviation); // e.g., 'CST'
|
|
2496
|
-
* ```
|
|
2497
|
-
*/
|
|
2498
|
-
function timezoneInfoForSystem() {
|
|
2499
|
-
return timezoneStringToTimezoneInfo(guessCurrentTimezone() ?? util.UTC_TIMEZONE_STRING);
|
|
2500
|
-
}
|
|
2501
|
-
/**
|
|
2502
|
-
* Returns the short abbreviation (e.g., `"EST"`, `"PDT"`) for the given timezone at the specified date.
|
|
2503
|
-
*
|
|
2504
|
-
* The date matters because abbreviations change with DST transitions.
|
|
2505
|
-
* Returns `"UKNOWN"` if no timezone is provided.
|
|
2506
|
-
*
|
|
2507
|
-
* @example
|
|
2508
|
-
* ```ts
|
|
2509
|
-
* getTimezoneAbbreviation('America/New_York'); // 'EST' or 'EDT'
|
|
2510
|
-
* ```
|
|
2511
|
-
*/
|
|
2512
|
-
function getTimezoneAbbreviation(timezone, date = new Date()) {
|
|
2513
|
-
return timezone === util.UTC_TIMEZONE_STRING ? util.UTC_TIMEZONE_STRING : timezone ? dateFnsTz.formatInTimeZone(date, timezone, 'zzz') : 'UKNOWN';
|
|
2514
|
-
}
|
|
2515
|
-
/**
|
|
2516
|
-
* Returns the full display name (e.g., `"Eastern Standard Time"`) for the given timezone.
|
|
2517
|
-
*
|
|
2518
|
-
* Returns `"Unknown Timezone"` if no timezone is provided.
|
|
2519
|
-
*
|
|
2520
|
-
* @example
|
|
2521
|
-
* ```ts
|
|
2522
|
-
* getTimezoneLongName('America/New_York'); // 'Eastern Standard Time'
|
|
2523
|
-
* ```
|
|
2524
|
-
*/
|
|
2525
|
-
function getTimezoneLongName(timezone, date = new Date()) {
|
|
2526
|
-
return timezone ? dateFnsTz.formatInTimeZone(date, timezone, 'zzzz') : 'Unknown Timezone';
|
|
2527
|
-
}
|
|
2528
|
-
/**
|
|
2529
|
-
* Builds a {@link TimezoneInfo} for the given timezone, computing abbreviation and search variants.
|
|
2530
|
-
*
|
|
2531
|
-
* @example
|
|
2532
|
-
* ```ts
|
|
2533
|
-
* const info = timezoneStringToTimezoneInfo('America/Chicago');
|
|
2534
|
-
* // info.abbreviation => 'CST' or 'CDT'
|
|
2535
|
-
* // info.search => 'america chicago'
|
|
2536
|
-
* ```
|
|
2537
|
-
*/
|
|
2538
|
-
function timezoneStringToTimezoneInfo(timezone, date = new Date()) {
|
|
2539
|
-
const abbreviation = getTimezoneAbbreviation(timezone, date);
|
|
2540
|
-
const result = {
|
|
2541
|
-
timezone,
|
|
2542
|
-
search: timezoneStringToSearchableString(timezone),
|
|
2543
|
-
lowercase: timezone.toLowerCase(),
|
|
2544
|
-
abbreviation,
|
|
2545
|
-
lowercaseAbbreviation: abbreviation.toLowerCase()
|
|
2546
|
-
};
|
|
2547
|
-
return result;
|
|
2548
|
-
}
|
|
2549
|
-
/**
|
|
2550
|
-
* Filters timezone infos by a search string, matching against the searchable name,
|
|
2551
|
-
* lowercase identifier, and abbreviation.
|
|
2552
|
-
*
|
|
2553
|
-
* For queries longer than 2 characters, substring matching on the searchable name is also used.
|
|
2554
|
-
*
|
|
2555
|
-
* @example
|
|
2556
|
-
* ```ts
|
|
2557
|
-
* const results = searchTimezoneInfos('eastern', allTimezoneInfos());
|
|
2558
|
-
* ```
|
|
2559
|
-
*/
|
|
2560
|
-
function searchTimezoneInfos(search, infos) {
|
|
2561
|
-
const searchString = search.toLocaleLowerCase();
|
|
2562
|
-
return infos.filter((x) => (search.length > 2 && x.search.includes(searchString)) || x.lowercase.startsWith(searchString) || x.lowercaseAbbreviation.startsWith(searchString) || x.abbreviation.includes(search) || x.search === x.timezone);
|
|
2563
|
-
}
|
|
2564
|
-
const timezoneStringToSearchableStringReplace = util.replaceStringsFunction({
|
|
2565
|
-
replace: ['/', '_'],
|
|
2566
|
-
replaceWith: ' '
|
|
2567
|
-
});
|
|
2568
|
-
/**
|
|
2569
|
-
* Converts a timezone identifier into a lowercase, space-separated string for search indexing.
|
|
2570
|
-
*
|
|
2571
|
-
* Replaces `/` and `_` with spaces (e.g., `"America/New_York"` becomes `"america new york"`).
|
|
2572
|
-
*
|
|
2573
|
-
* @example
|
|
2574
|
-
* ```ts
|
|
2575
|
-
* timezoneStringToSearchableString('America/New_York'); // 'america new york'
|
|
2576
|
-
* ```
|
|
2577
|
-
*/
|
|
2578
|
-
function timezoneStringToSearchableString(timezone) {
|
|
2579
|
-
return timezoneStringToSearchableStringReplace(timezone.toLocaleLowerCase());
|
|
2580
|
-
}
|
|
2581
|
-
/**
|
|
2582
|
-
* Checks whether the input string is a recognized IANA timezone identifier.
|
|
2583
|
-
*
|
|
2584
|
-
* Uses the cached set from {@link allKnownTimezoneStrings} for O(1) lookup.
|
|
2585
|
-
*
|
|
2586
|
-
* @example
|
|
2587
|
-
* ```ts
|
|
2588
|
-
* isKnownTimezone('America/New_York'); // true
|
|
2589
|
-
* isKnownTimezone('Mars/Olympus'); // false
|
|
2590
|
-
* ```
|
|
2591
|
-
*/
|
|
2592
|
-
function isKnownTimezone(input) {
|
|
2593
|
-
return allKnownTimezoneStrings().has(input);
|
|
2594
|
-
}
|
|
2595
|
-
|
|
2596
|
-
/**
|
|
2597
|
-
* ArkType schema that validates a string is a recognized IANA timezone.
|
|
2598
|
-
*
|
|
2599
|
-
* Delegates to {@link isKnownTimezone} for the actual check.
|
|
2600
|
-
*
|
|
2601
|
-
* @example
|
|
2602
|
-
* ```ts
|
|
2603
|
-
* const result = knownTimezoneType('America/Denver');
|
|
2604
|
-
* ```
|
|
2605
|
-
*/
|
|
2606
|
-
const knownTimezoneType = arktype.type('string > 0').narrow((val, ctx) => (val != null && isKnownTimezone(val)) || ctx.mustBe('a known timezone'));
|
|
2607
|
-
|
|
2608
2373
|
/**
|
|
2609
2374
|
* Creates a {@link FitDateRangeToDayPeriodFunction} that collapses a multi-day date range into a single-day period within the given timezone.
|
|
2610
2375
|
*
|
|
@@ -3145,12 +2910,6 @@ function parseISO8601DayStringToDate(dayString) {
|
|
|
3145
2910
|
function isValidDateCellIndex(input) {
|
|
3146
2911
|
return input >= 0 && Number.isInteger(input);
|
|
3147
2912
|
}
|
|
3148
|
-
/**
|
|
3149
|
-
* ArkType schema for {@link DateCell}.
|
|
3150
|
-
*/
|
|
3151
|
-
const dateCellType = arktype.type({
|
|
3152
|
-
i: 'number.integer >= 0'
|
|
3153
|
-
});
|
|
3154
2913
|
/**
|
|
3155
2914
|
* Normalizes a number or {@link DateCell} to a DateCell object.
|
|
3156
2915
|
*
|
|
@@ -3191,13 +2950,6 @@ function dateCellTimingStartsAtForStartOfDay(input = {}) {
|
|
|
3191
2950
|
timezone
|
|
3192
2951
|
};
|
|
3193
2952
|
}
|
|
3194
|
-
/**
|
|
3195
|
-
* ArkType schema for {@link DateCellTiming}.
|
|
3196
|
-
*/
|
|
3197
|
-
const dateCellTimingType = dateDurationSpanType.merge({
|
|
3198
|
-
end: 'Date',
|
|
3199
|
-
timezone: knownTimezoneType
|
|
3200
|
-
});
|
|
3201
2953
|
/**
|
|
3202
2954
|
* Creates a {@link DateTimezoneUtcNormalInstance} from the input, guaranteeing that a timezone string is configured.
|
|
3203
2955
|
*
|
|
@@ -3783,12 +3535,6 @@ function isValidFullDateCellTiming(timing) {
|
|
|
3783
3535
|
return isValid;
|
|
3784
3536
|
}
|
|
3785
3537
|
|
|
3786
|
-
/**
|
|
3787
|
-
* ArkType schema for {@link DateCellRange}.
|
|
3788
|
-
*/
|
|
3789
|
-
const dateCellRangeType = dateCellType.merge({
|
|
3790
|
-
'to?': 'number.integer >= 0'
|
|
3791
|
-
});
|
|
3792
3538
|
/**
|
|
3793
3539
|
* Returns true if the input is a DateCellRange.
|
|
3794
3540
|
*
|
|
@@ -5242,16 +4988,78 @@ function isDateWithinDateCellRangeFunction(config) {
|
|
|
5242
4988
|
}
|
|
5243
4989
|
|
|
5244
4990
|
/**
|
|
5245
|
-
*
|
|
5246
|
-
*
|
|
5247
|
-
* Useful for identifying events or blocks that have already begun relative to a point in time.
|
|
4991
|
+
* Computes the end date for a duration span by adding the duration to the start time.
|
|
5248
4992
|
*
|
|
5249
|
-
* @param
|
|
4993
|
+
* @param span - the duration span to compute the end for
|
|
4994
|
+
* @returns the date when the span ends
|
|
5250
4995
|
*
|
|
5251
4996
|
* @example
|
|
5252
4997
|
* ```ts
|
|
5253
|
-
* const
|
|
5254
|
-
*
|
|
4998
|
+
* const span = { startsAt: new Date('2024-01-01T10:00:00Z'), duration: 60 };
|
|
4999
|
+
* dateDurationSpanEndDate(span); // 2024-01-01T11:00:00Z
|
|
5000
|
+
* ```
|
|
5001
|
+
*/
|
|
5002
|
+
function dateDurationSpanEndDate(span) {
|
|
5003
|
+
return dateFns.addMinutes(span.startsAt, span.duration);
|
|
5004
|
+
}
|
|
5005
|
+
/**
|
|
5006
|
+
* Converts a {@link DateDurationSpan} to a {@link DateRange} with start and end dates.
|
|
5007
|
+
*
|
|
5008
|
+
* @param span - the duration span to convert
|
|
5009
|
+
* @returns a date range from startsAt to startsAt + duration
|
|
5010
|
+
*/
|
|
5011
|
+
function durationSpanToDateRange(span) {
|
|
5012
|
+
return {
|
|
5013
|
+
start: span.startsAt,
|
|
5014
|
+
end: dateFns.addMinutes(span.startsAt, span.duration)
|
|
5015
|
+
};
|
|
5016
|
+
}
|
|
5017
|
+
/**
|
|
5018
|
+
* Creates a {@link DateDurationSpan} from a {@link DateRange} by computing the duration in minutes between start and end.
|
|
5019
|
+
*
|
|
5020
|
+
* @param dateRange - the date range to convert
|
|
5021
|
+
* @returns a duration span with the range's start as startsAt
|
|
5022
|
+
*/
|
|
5023
|
+
function durationSpanFromDateRange(dateRange) {
|
|
5024
|
+
return {
|
|
5025
|
+
startsAt: dateRange.start,
|
|
5026
|
+
duration: dateFns.differenceInMinutes(dateRange.end, dateRange.start)
|
|
5027
|
+
};
|
|
5028
|
+
}
|
|
5029
|
+
/**
|
|
5030
|
+
* Determines whether a duration span is in the past, present, or future relative to the given time.
|
|
5031
|
+
*
|
|
5032
|
+
* @param span - the duration span to check
|
|
5033
|
+
* @param now - reference time (defaults to current time)
|
|
5034
|
+
* @returns 'past', 'present', or 'future'
|
|
5035
|
+
*/
|
|
5036
|
+
function durationSpanDateRelativeState(span, now) {
|
|
5037
|
+
return dateRangeRelativeState(durationSpanToDateRange(span), now);
|
|
5038
|
+
}
|
|
5039
|
+
/**
|
|
5040
|
+
* Converts a duration span's duration from minutes to fractional hours.
|
|
5041
|
+
*
|
|
5042
|
+
* @param span - the duration span to measure
|
|
5043
|
+
* @returns the duration expressed as fractional hours (e.g. 90 minutes = 1.5)
|
|
5044
|
+
*/
|
|
5045
|
+
function fractionalHoursInDurationSpan(span) {
|
|
5046
|
+
return util.minutesToFractionalHours(span.duration);
|
|
5047
|
+
}
|
|
5048
|
+
function isSameDurationSpan(a, b) {
|
|
5049
|
+
return util.safeCompareEquality(a, b, (a, b) => a.duration === b.duration && isSameDate(a.startsAt, b.startsAt));
|
|
5050
|
+
}
|
|
5051
|
+
|
|
5052
|
+
/**
|
|
5053
|
+
* Creates a filter that passes date cell duration spans whose start time is at or before the given reference time.
|
|
5054
|
+
*
|
|
5055
|
+
* Useful for identifying events or blocks that have already begun relative to a point in time.
|
|
5056
|
+
*
|
|
5057
|
+
* @param now - Reference time to compare against. Defaults to the current time.
|
|
5058
|
+
*
|
|
5059
|
+
* @example
|
|
5060
|
+
* ```ts
|
|
5061
|
+
* const hasStarted = dateCellDurationSpanHasStartedFilterFunction(new Date());
|
|
5062
|
+
* const startedSpans = allSpans.filter(hasStarted);
|
|
5255
5063
|
* ```
|
|
5256
5064
|
*/
|
|
5257
5065
|
function dateCellDurationSpanHasStartedFilterFunction(now = new Date()) {
|
|
@@ -6060,14 +5868,6 @@ function isSameDateCellSchedule(a, b) {
|
|
|
6060
5868
|
return a == b;
|
|
6061
5869
|
}
|
|
6062
5870
|
}
|
|
6063
|
-
/**
|
|
6064
|
-
* ArkType schema for {@link DateCellSchedule}.
|
|
6065
|
-
*/
|
|
6066
|
-
const dateCellScheduleType = arktype.type({
|
|
6067
|
-
w: [DATE_CELL_SCHEDULE_ENCODED_WEEK_REGEX, '&', 'string'],
|
|
6068
|
-
'd?': 'number.integer >= 0 []',
|
|
6069
|
-
'ex?': 'number.integer >= 0 []'
|
|
6070
|
-
});
|
|
6071
5871
|
/**
|
|
6072
5872
|
* Returns true if the input is possibly a DateCellScheduleDateRange (has schedule fields and valid start/end dates).
|
|
6073
5873
|
*
|
|
@@ -6577,17 +6377,144 @@ function dateCellIndexsForDateCellScheduleDayCodes(sundayIndex, dayCodes) {
|
|
|
6577
6377
|
}
|
|
6578
6378
|
|
|
6579
6379
|
/**
|
|
6580
|
-
*
|
|
6380
|
+
* Returns all recognized IANA timezone strings, including the explicit UTC entry.
|
|
6381
|
+
*
|
|
6382
|
+
* @example
|
|
6383
|
+
* ```ts
|
|
6384
|
+
* const zones = allTimezoneStrings();
|
|
6385
|
+
* // ['Africa/Abidjan', ..., 'UTC']
|
|
6386
|
+
* ```
|
|
6387
|
+
*/
|
|
6388
|
+
function allTimezoneStrings() {
|
|
6389
|
+
return tzdb.timeZonesNames.concat(util.UTC_TIMEZONE_STRING);
|
|
6390
|
+
}
|
|
6391
|
+
/**
|
|
6392
|
+
* Lazily-computed set of all known timezone strings for O(1) membership checks.
|
|
6393
|
+
*
|
|
6394
|
+
* @example
|
|
6395
|
+
* ```ts
|
|
6396
|
+
* allKnownTimezoneStrings().has('America/New_York'); // true
|
|
6397
|
+
* ```
|
|
6581
6398
|
*/
|
|
6582
|
-
const
|
|
6399
|
+
const allKnownTimezoneStrings = util.cachedGetter(() => {
|
|
6400
|
+
return new Set(allTimezoneStrings());
|
|
6401
|
+
});
|
|
6583
6402
|
/**
|
|
6584
|
-
*
|
|
6403
|
+
* Lazily-computed array of {@link TimezoneInfo} for every known timezone.
|
|
6404
|
+
*
|
|
6405
|
+
* Abbreviations are resolved at the time of first access, so results reflect
|
|
6406
|
+
* the DST state at that moment.
|
|
6585
6407
|
*/
|
|
6586
|
-
const
|
|
6408
|
+
const allTimezoneInfos = util.cachedGetter(() => {
|
|
6409
|
+
const now = new Date();
|
|
6410
|
+
return allTimezoneStrings().map((x) => timezoneStringToTimezoneInfo(x, now));
|
|
6411
|
+
});
|
|
6587
6412
|
/**
|
|
6588
|
-
*
|
|
6413
|
+
* Returns the {@link TimezoneInfo} for the current system timezone, falling back to UTC.
|
|
6414
|
+
*
|
|
6415
|
+
* @example
|
|
6416
|
+
* ```ts
|
|
6417
|
+
* const info = timezoneInfoForSystem();
|
|
6418
|
+
* console.log(info.abbreviation); // e.g., 'CST'
|
|
6419
|
+
* ```
|
|
6589
6420
|
*/
|
|
6590
|
-
|
|
6421
|
+
function timezoneInfoForSystem() {
|
|
6422
|
+
return timezoneStringToTimezoneInfo(guessCurrentTimezone() ?? util.UTC_TIMEZONE_STRING);
|
|
6423
|
+
}
|
|
6424
|
+
/**
|
|
6425
|
+
* Returns the short abbreviation (e.g., `"EST"`, `"PDT"`) for the given timezone at the specified date.
|
|
6426
|
+
*
|
|
6427
|
+
* The date matters because abbreviations change with DST transitions.
|
|
6428
|
+
* Returns `"UKNOWN"` if no timezone is provided.
|
|
6429
|
+
*
|
|
6430
|
+
* @example
|
|
6431
|
+
* ```ts
|
|
6432
|
+
* getTimezoneAbbreviation('America/New_York'); // 'EST' or 'EDT'
|
|
6433
|
+
* ```
|
|
6434
|
+
*/
|
|
6435
|
+
function getTimezoneAbbreviation(timezone, date = new Date()) {
|
|
6436
|
+
return timezone === util.UTC_TIMEZONE_STRING ? util.UTC_TIMEZONE_STRING : timezone ? dateFnsTz.formatInTimeZone(date, timezone, 'zzz') : 'UKNOWN';
|
|
6437
|
+
}
|
|
6438
|
+
/**
|
|
6439
|
+
* Returns the full display name (e.g., `"Eastern Standard Time"`) for the given timezone.
|
|
6440
|
+
*
|
|
6441
|
+
* Returns `"Unknown Timezone"` if no timezone is provided.
|
|
6442
|
+
*
|
|
6443
|
+
* @example
|
|
6444
|
+
* ```ts
|
|
6445
|
+
* getTimezoneLongName('America/New_York'); // 'Eastern Standard Time'
|
|
6446
|
+
* ```
|
|
6447
|
+
*/
|
|
6448
|
+
function getTimezoneLongName(timezone, date = new Date()) {
|
|
6449
|
+
return timezone ? dateFnsTz.formatInTimeZone(date, timezone, 'zzzz') : 'Unknown Timezone';
|
|
6450
|
+
}
|
|
6451
|
+
/**
|
|
6452
|
+
* Builds a {@link TimezoneInfo} for the given timezone, computing abbreviation and search variants.
|
|
6453
|
+
*
|
|
6454
|
+
* @example
|
|
6455
|
+
* ```ts
|
|
6456
|
+
* const info = timezoneStringToTimezoneInfo('America/Chicago');
|
|
6457
|
+
* // info.abbreviation => 'CST' or 'CDT'
|
|
6458
|
+
* // info.search => 'america chicago'
|
|
6459
|
+
* ```
|
|
6460
|
+
*/
|
|
6461
|
+
function timezoneStringToTimezoneInfo(timezone, date = new Date()) {
|
|
6462
|
+
const abbreviation = getTimezoneAbbreviation(timezone, date);
|
|
6463
|
+
const result = {
|
|
6464
|
+
timezone,
|
|
6465
|
+
search: timezoneStringToSearchableString(timezone),
|
|
6466
|
+
lowercase: timezone.toLowerCase(),
|
|
6467
|
+
abbreviation,
|
|
6468
|
+
lowercaseAbbreviation: abbreviation.toLowerCase()
|
|
6469
|
+
};
|
|
6470
|
+
return result;
|
|
6471
|
+
}
|
|
6472
|
+
/**
|
|
6473
|
+
* Filters timezone infos by a search string, matching against the searchable name,
|
|
6474
|
+
* lowercase identifier, and abbreviation.
|
|
6475
|
+
*
|
|
6476
|
+
* For queries longer than 2 characters, substring matching on the searchable name is also used.
|
|
6477
|
+
*
|
|
6478
|
+
* @example
|
|
6479
|
+
* ```ts
|
|
6480
|
+
* const results = searchTimezoneInfos('eastern', allTimezoneInfos());
|
|
6481
|
+
* ```
|
|
6482
|
+
*/
|
|
6483
|
+
function searchTimezoneInfos(search, infos) {
|
|
6484
|
+
const searchString = search.toLocaleLowerCase();
|
|
6485
|
+
return infos.filter((x) => (search.length > 2 && x.search.includes(searchString)) || x.lowercase.startsWith(searchString) || x.lowercaseAbbreviation.startsWith(searchString) || x.abbreviation.includes(search) || x.search === x.timezone);
|
|
6486
|
+
}
|
|
6487
|
+
const timezoneStringToSearchableStringReplace = util.replaceStringsFunction({
|
|
6488
|
+
replace: ['/', '_'],
|
|
6489
|
+
replaceWith: ' '
|
|
6490
|
+
});
|
|
6491
|
+
/**
|
|
6492
|
+
* Converts a timezone identifier into a lowercase, space-separated string for search indexing.
|
|
6493
|
+
*
|
|
6494
|
+
* Replaces `/` and `_` with spaces (e.g., `"America/New_York"` becomes `"america new york"`).
|
|
6495
|
+
*
|
|
6496
|
+
* @example
|
|
6497
|
+
* ```ts
|
|
6498
|
+
* timezoneStringToSearchableString('America/New_York'); // 'america new york'
|
|
6499
|
+
* ```
|
|
6500
|
+
*/
|
|
6501
|
+
function timezoneStringToSearchableString(timezone) {
|
|
6502
|
+
return timezoneStringToSearchableStringReplace(timezone.toLocaleLowerCase());
|
|
6503
|
+
}
|
|
6504
|
+
/**
|
|
6505
|
+
* Checks whether the input string is a recognized IANA timezone identifier.
|
|
6506
|
+
*
|
|
6507
|
+
* Uses the cached set from {@link allKnownTimezoneStrings} for O(1) lookup.
|
|
6508
|
+
*
|
|
6509
|
+
* @example
|
|
6510
|
+
* ```ts
|
|
6511
|
+
* isKnownTimezone('America/New_York'); // true
|
|
6512
|
+
* isKnownTimezone('Mars/Olympus'); // false
|
|
6513
|
+
* ```
|
|
6514
|
+
*/
|
|
6515
|
+
function isKnownTimezone(input) {
|
|
6516
|
+
return allKnownTimezoneStrings().has(input);
|
|
6517
|
+
}
|
|
6591
6518
|
|
|
6592
6519
|
/**
|
|
6593
6520
|
* Distinguishes between time-based calendar events and all-day/multi-day events.
|
|
@@ -6603,12 +6530,6 @@ exports.CalendarDateType = void 0;
|
|
|
6603
6530
|
*/
|
|
6604
6531
|
CalendarDateType["DAYS"] = "days";
|
|
6605
6532
|
})(exports.CalendarDateType || (exports.CalendarDateType = {}));
|
|
6606
|
-
/**
|
|
6607
|
-
* ArkType schema for {@link CalendarDate}.
|
|
6608
|
-
*/
|
|
6609
|
-
const calendarDateType = dateDurationSpanType.merge({
|
|
6610
|
-
type: arktype.type.enumerated(...Object.values(exports.CalendarDateType))
|
|
6611
|
-
});
|
|
6612
6533
|
/**
|
|
6613
6534
|
* Creates a {@link CalendarDateFactory} that produces all-day calendar events with timezone-aware start times.
|
|
6614
6535
|
*
|
|
@@ -6678,6 +6599,151 @@ function calendarDateForDateDurationSpan(dateDurationSpan) {
|
|
|
6678
6599
|
};
|
|
6679
6600
|
}
|
|
6680
6601
|
|
|
6602
|
+
// MARK: Timezone
|
|
6603
|
+
/**
|
|
6604
|
+
* ArkType DTO schema that validates a string is a recognized IANA timezone.
|
|
6605
|
+
*
|
|
6606
|
+
* Delegates to {@link isKnownTimezone} for the actual check.
|
|
6607
|
+
*
|
|
6608
|
+
* Intended for validating and parsing DTO/JSON data where timezones arrive as strings.
|
|
6609
|
+
*
|
|
6610
|
+
* @example
|
|
6611
|
+
* ```ts
|
|
6612
|
+
* const result = knownTimezoneType('America/Denver');
|
|
6613
|
+
* ```
|
|
6614
|
+
*/
|
|
6615
|
+
const knownTimezoneType = arktype.type('string > 0').narrow((val, ctx) => (val != null && isKnownTimezone(val)) || ctx.mustBe('a known timezone'));
|
|
6616
|
+
// MARK: DateDurationSpan
|
|
6617
|
+
/**
|
|
6618
|
+
* ArkType DTO schema for {@link DateDurationSpan}.
|
|
6619
|
+
*
|
|
6620
|
+
* Accepts both Date objects and date strings (parsed via `string.date.parse`).
|
|
6621
|
+
* Use this schema when validating and converting serialized data (e.g., API responses, JSON payloads)
|
|
6622
|
+
* or runtime Date objects into the corresponding runtime types.
|
|
6623
|
+
*/
|
|
6624
|
+
const dateDurationSpanType = arktype.type({
|
|
6625
|
+
startsAt: model.ARKTYPE_DATE_DTO_TYPE,
|
|
6626
|
+
duration: 'number >= 0'
|
|
6627
|
+
});
|
|
6628
|
+
// MARK: DateRange
|
|
6629
|
+
/**
|
|
6630
|
+
* ArkType DTO schema for {@link DateRange}.
|
|
6631
|
+
*
|
|
6632
|
+
* Accepts both Date objects and date strings (parsed via `string.date.parse`).
|
|
6633
|
+
* Use this schema when validating and converting serialized data (e.g., API responses, JSON payloads)
|
|
6634
|
+
* or runtime Date objects into the corresponding runtime types.
|
|
6635
|
+
*/
|
|
6636
|
+
const dateRangeType = arktype.type({
|
|
6637
|
+
start: model.ARKTYPE_DATE_DTO_TYPE,
|
|
6638
|
+
end: model.ARKTYPE_DATE_DTO_TYPE
|
|
6639
|
+
});
|
|
6640
|
+
// MARK: DateRangeParams
|
|
6641
|
+
/**
|
|
6642
|
+
* ArkType DTO schema for {@link DateRangeParams}.
|
|
6643
|
+
*
|
|
6644
|
+
* Accepts both Date objects and date strings (parsed via `string.date.parse`).
|
|
6645
|
+
* Use this schema when validating and converting serialized data (e.g., API responses, JSON payloads)
|
|
6646
|
+
* or runtime Date objects into the corresponding runtime types.
|
|
6647
|
+
*/
|
|
6648
|
+
const dateRangeParamsType = arktype.type({
|
|
6649
|
+
type: arktype.type.enumerated(...Object.values(exports.DateRangeType)),
|
|
6650
|
+
date: model.ARKTYPE_DATE_DTO_TYPE,
|
|
6651
|
+
'distance?': 'number'
|
|
6652
|
+
});
|
|
6653
|
+
// MARK: DateCell
|
|
6654
|
+
/**
|
|
6655
|
+
* ArkType DTO schema for {@link DateCell}.
|
|
6656
|
+
*
|
|
6657
|
+
* Validates a cell index from JSON/DTO input.
|
|
6658
|
+
* Use this schema when validating and converting serialized data (e.g., API responses, JSON payloads)
|
|
6659
|
+
* into the corresponding runtime types.
|
|
6660
|
+
*/
|
|
6661
|
+
const dateCellType = arktype.type({
|
|
6662
|
+
i: 'number.integer >= 0'
|
|
6663
|
+
});
|
|
6664
|
+
// MARK: DateCellRange
|
|
6665
|
+
/**
|
|
6666
|
+
* ArkType DTO schema for {@link DateCellRange}.
|
|
6667
|
+
*
|
|
6668
|
+
* Validates cell range indexes from JSON/DTO input.
|
|
6669
|
+
* Use this schema when validating and converting serialized data (e.g., API responses, JSON payloads)
|
|
6670
|
+
* into the corresponding runtime types.
|
|
6671
|
+
*/
|
|
6672
|
+
const dateCellRangeType = dateCellType.merge({
|
|
6673
|
+
'to?': 'number.integer >= 0'
|
|
6674
|
+
});
|
|
6675
|
+
// MARK: DateCellTiming
|
|
6676
|
+
/**
|
|
6677
|
+
* ArkType DTO schema for {@link DateCellTiming}.
|
|
6678
|
+
*
|
|
6679
|
+
* Accepts both Date objects and date strings (parsed via `string.date.parse`).
|
|
6680
|
+
* Use this schema when validating and converting serialized data (e.g., API responses, JSON payloads)
|
|
6681
|
+
* or runtime Date objects into the corresponding runtime types.
|
|
6682
|
+
*/
|
|
6683
|
+
const dateCellTimingType = dateDurationSpanType.merge({
|
|
6684
|
+
end: model.ARKTYPE_DATE_DTO_TYPE,
|
|
6685
|
+
timezone: knownTimezoneType
|
|
6686
|
+
});
|
|
6687
|
+
// MARK: CalendarDate
|
|
6688
|
+
/**
|
|
6689
|
+
* ArkType DTO schema for {@link CalendarDate}.
|
|
6690
|
+
*
|
|
6691
|
+
* Accepts both Date objects and date strings (parsed via `string.date.parse`).
|
|
6692
|
+
* Use this schema when validating and converting serialized data (e.g., API responses, JSON payloads)
|
|
6693
|
+
* or runtime Date objects into the corresponding runtime types.
|
|
6694
|
+
*/
|
|
6695
|
+
const calendarDateType = dateDurationSpanType.merge({
|
|
6696
|
+
type: arktype.type.enumerated(...Object.values(exports.CalendarDateType))
|
|
6697
|
+
});
|
|
6698
|
+
// MARK: DateCellSchedule
|
|
6699
|
+
/**
|
|
6700
|
+
* ArkType DTO schema for {@link DateCellSchedule}.
|
|
6701
|
+
*
|
|
6702
|
+
* Validates schedule data from JSON/DTO input.
|
|
6703
|
+
* Use this schema when validating and converting serialized data (e.g., API responses, JSON payloads)
|
|
6704
|
+
* into the corresponding runtime types.
|
|
6705
|
+
*/
|
|
6706
|
+
const dateCellScheduleType = arktype.type({
|
|
6707
|
+
w: [DATE_CELL_SCHEDULE_ENCODED_WEEK_REGEX, '&', 'string'],
|
|
6708
|
+
'd?': 'number.integer >= 0 []',
|
|
6709
|
+
'ex?': 'number.integer >= 0 []'
|
|
6710
|
+
});
|
|
6711
|
+
// MARK: ModelRecurrenceInfo
|
|
6712
|
+
/**
|
|
6713
|
+
* ArkType DTO schema for {@link ModelRecurrenceInfo}.
|
|
6714
|
+
*
|
|
6715
|
+
* Accepts both Date objects and date strings (parsed via `string.date.parse`).
|
|
6716
|
+
* Use this schema when validating and converting serialized data (e.g., API responses, JSON payloads)
|
|
6717
|
+
* or runtime Date objects into the corresponding runtime types.
|
|
6718
|
+
*/
|
|
6719
|
+
const modelRecurrenceInfoType = arktype.type({
|
|
6720
|
+
'timezone?': 'string',
|
|
6721
|
+
rrule: 'string',
|
|
6722
|
+
start: model.ARKTYPE_DATE_DTO_TYPE,
|
|
6723
|
+
end: model.ARKTYPE_DATE_DTO_TYPE,
|
|
6724
|
+
'forever?': 'boolean'
|
|
6725
|
+
});
|
|
6726
|
+
// MARK: Validators
|
|
6727
|
+
/**
|
|
6728
|
+
* ArkType DTO schema that validates a value is a valid {@link DateCellTiming}.
|
|
6729
|
+
*
|
|
6730
|
+
* Accepts both Date objects and date strings (parsed via `string.date.parse`), then validates the resulting timing
|
|
6731
|
+
* using {@link isValidDateCellTiming}.
|
|
6732
|
+
*/
|
|
6733
|
+
const validDateCellTimingType = dateCellTimingType.narrow((val, ctx) => (val != null && isValidDateCellTiming(val)) || ctx.mustBe('a valid DateCellTiming'));
|
|
6734
|
+
/**
|
|
6735
|
+
* ArkType DTO schema that validates a value is a valid {@link DateCellRange} (non-negative indexes, `to >= i`).
|
|
6736
|
+
*
|
|
6737
|
+
* Validates cell range data from JSON/DTO input.
|
|
6738
|
+
*/
|
|
6739
|
+
const validDateCellRangeType = dateCellRangeType.narrow((val, ctx) => (val != null && isValidDateCellRange(val)) || ctx.mustBe('a valid DateCellRange'));
|
|
6740
|
+
/**
|
|
6741
|
+
* ArkType DTO schema that validates a value is a sorted array of non-overlapping {@link DateCellRange} values.
|
|
6742
|
+
*
|
|
6743
|
+
* Validates cell range series data from JSON/DTO input.
|
|
6744
|
+
*/
|
|
6745
|
+
const validDateCellRangeSeriesType = arktype.type(dateCellRangeType.array()).narrow((val, ctx) => (val != null && isValidDateCellRangeSeries(val)) || ctx.mustBe('a valid DateCellRange series with items sorted in ascending order and no repeat indexes'));
|
|
6746
|
+
|
|
6681
6747
|
/**
|
|
6682
6748
|
* A {@link HashSet} specialized for Date values, using the millisecond timestamp as the hash key.
|
|
6683
6749
|
*
|
|
@@ -8781,16 +8847,6 @@ class DateRRuleUtility {
|
|
|
8781
8847
|
}
|
|
8782
8848
|
}
|
|
8783
8849
|
|
|
8784
|
-
/**
|
|
8785
|
-
* ArkType schema for {@link ModelRecurrenceInfo}.
|
|
8786
|
-
*/
|
|
8787
|
-
const modelRecurrenceInfoType = arktype.type({
|
|
8788
|
-
'timezone?': 'string',
|
|
8789
|
-
rrule: 'string',
|
|
8790
|
-
start: 'Date',
|
|
8791
|
-
end: 'Date',
|
|
8792
|
-
'forever?': 'boolean'
|
|
8793
|
-
});
|
|
8794
8850
|
/**
|
|
8795
8851
|
* Stateless utility for converting between recurrence input
|
|
8796
8852
|
* ({@link ModelRecurrenceStart}) and the indexed storage form
|