@northguild/gmt 1.18.0 → 1.20.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 +55 -2920
- package/dist/calendar/business/businessDaysBetween.d.ts +2 -2
- package/dist/calendar/business/businessDaysBetween.js +11 -35
- package/dist/calendar/business/mergeCalendars.d.ts +1 -1
- package/dist/calendar/business/mergeCalendars.js +8 -9
- package/dist/calendar/business/nextBusinessDay.d.ts +2 -2
- package/dist/calendar/business/nextBusinessDay.js +2 -2
- package/dist/calendar/business/previousBusinessDay.d.ts +2 -2
- package/dist/calendar/business/previousBusinessDay.js +2 -2
- package/dist/calendar/business/rollDate.d.ts +3 -3
- package/dist/calendar/business/rollDate.js +10 -43
- package/dist/calendar/calculate/bucketRange.d.ts +19 -11
- package/dist/calendar/calculate/bucketRange.js +27 -70
- package/dist/calendar/calculate/floorToZone.d.ts +12 -4
- package/dist/calendar/calculate/floorToZone.js +16 -8
- package/dist/calendar/calculate/getFiscalPeriod.d.ts +50 -40
- package/dist/calendar/calculate/getFiscalPeriod.js +78 -57
- package/dist/calendar/calculate/getQuarter.d.ts +26 -21
- package/dist/calendar/calculate/getQuarter.js +48 -19
- package/dist/calendar/hours/addOperatingTime.d.ts +9 -3
- package/dist/calendar/hours/addOperatingTime.js +10 -4
- package/dist/calendar/hours/isOpenAt.d.ts +9 -3
- package/dist/calendar/hours/isOpenAt.js +9 -3
- package/dist/calendar/hours/nextCloseAt.d.ts +8 -2
- package/dist/calendar/hours/nextCloseAt.js +9 -3
- package/dist/calendar/hours/nextOpenAt.d.ts +9 -3
- package/dist/calendar/hours/nextOpenAt.js +10 -4
- package/dist/calendar/hours/operatingIntervals.d.ts +7 -2
- package/dist/calendar/hours/operatingIntervals.js +9 -6
- package/dist/calendar/hours/operatingTimeBetween.d.ts +8 -3
- package/dist/calendar/hours/operatingTimeBetween.js +11 -8
- package/dist/calendar/hours/recurringWindows.d.ts +13 -6
- package/dist/calendar/hours/recurringWindows.js +21 -14
- package/dist/calendar/index.d.ts +1 -1
- package/dist/calendar/index.js +2 -2
- package/dist/calendar/validate/index.d.ts +3 -0
- package/dist/calendar/validate/index.js +3 -0
- package/dist/calendar/validate/isValidFiscalCalendar.d.ts +23 -0
- package/dist/calendar/validate/isValidFiscalCalendar.js +44 -0
- package/dist/calendar/validate/isValidFiscalExtraWeek.d.ts +19 -0
- package/dist/calendar/validate/isValidFiscalExtraWeek.js +23 -0
- package/dist/calendar/validate/isValidFiscalPattern.d.ts +7 -7
- package/dist/calendar/validate/isValidFiscalPattern.js +7 -7
- package/dist/calendar/validate/isValidFiscalYearLabel.d.ts +20 -0
- package/dist/calendar/validate/isValidFiscalYearLabel.js +24 -0
- package/dist/calendar/validate/isValidRollConvention.js +2 -10
- package/dist/calendar/validate/isValidZoneBucketUnit.d.ts +1 -1
- package/dist/duration/calculate/absDuration.js +1 -1
- package/dist/duration/calculate/addDuration.js +1 -1
- package/dist/duration/calculate/durationFromUnits.d.ts +47 -0
- package/dist/duration/calculate/durationFromUnits.js +67 -0
- package/dist/duration/calculate/getDurationSign.js +1 -1
- package/dist/duration/calculate/getDurationUnit.d.ts +3 -3
- package/dist/duration/calculate/getDurationUnit.js +3 -3
- package/dist/duration/calculate/index.d.ts +3 -1
- package/dist/duration/calculate/index.js +3 -1
- package/dist/duration/calculate/negateDuration.d.ts +1 -1
- package/dist/duration/calculate/negateDuration.js +2 -2
- package/dist/duration/calculate/subtractDuration.js +1 -1
- package/dist/duration/calculate/{durationAs.d.ts → totalDuration.d.ts} +27 -21
- package/dist/duration/calculate/{durationAs.js → totalDuration.js} +27 -21
- package/dist/duration/calculate/totalUnits.d.ts +49 -0
- package/dist/duration/calculate/totalUnits.js +73 -0
- package/dist/duration/compare/compareDurations.d.ts +4 -4
- package/dist/duration/compare/compareDurations.js +4 -4
- package/dist/duration/format/formatDuration.d.ts +9 -9
- package/dist/duration/format/formatDuration.js +14 -13
- package/dist/duration/index.d.ts +1 -1
- package/dist/duration/index.js +2 -2
- package/dist/duration/normalize/normalizeDuration.d.ts +3 -3
- package/dist/duration/normalize/normalizeDuration.js +3 -3
- package/dist/duration/parse/parseDuration.d.ts +1 -1
- package/dist/duration/parse/parseDuration.js +1 -1
- package/dist/duration/validate/isValidDuration.js +2 -11
- package/dist/gnss/convert/gnssToUtc.d.ts +24 -0
- package/dist/gnss/convert/gnssToUtc.js +39 -0
- package/dist/gnss/convert/gnssWeekToUtc.d.ts +53 -0
- package/dist/gnss/convert/gnssWeekToUtc.js +80 -0
- package/dist/gnss/convert/index.d.ts +6 -0
- package/dist/gnss/convert/index.js +6 -0
- package/dist/gnss/convert/rinexWeekToUtc.d.ts +34 -0
- package/dist/gnss/convert/rinexWeekToUtc.js +57 -0
- package/dist/gnss/convert/utcToGnss.d.ts +38 -0
- package/dist/gnss/convert/utcToGnss.js +53 -0
- package/dist/gnss/convert/utcToGnssWeek.d.ts +24 -0
- package/dist/gnss/convert/utcToGnssWeek.js +40 -0
- package/dist/gnss/convert/utcToRinexWeek.d.ts +19 -0
- package/dist/gnss/convert/utcToRinexWeek.js +45 -0
- package/dist/gnss/index.d.ts +2 -0
- package/dist/gnss/index.js +3 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.js +4 -1
- package/dist/instant/convert/classifyLocal.d.ts +9 -5
- package/dist/instant/convert/classifyLocal.js +19 -20
- package/dist/instant/convert/fromOffsetInstant.d.ts +8 -4
- package/dist/instant/convert/fromOffsetInstant.js +11 -6
- package/dist/instant/convert/resolveLocal.d.ts +16 -11
- package/dist/instant/convert/resolveLocal.js +25 -17
- package/dist/instant/convert/toOffsetInstant.d.ts +23 -19
- package/dist/instant/convert/toOffsetInstant.js +29 -38
- package/dist/instant/index.d.ts +2 -1
- package/dist/instant/index.js +3 -2
- package/dist/instant/validate/index.d.ts +1 -0
- package/dist/instant/validate/index.js +1 -0
- package/dist/instant/validate/isValidUtcOffset.d.ts +32 -0
- package/dist/instant/validate/isValidUtcOffset.js +35 -0
- package/dist/intermodal/calculate/billingTimeline.js +1 -1
- package/dist/intermodal/calculate/chargeableDays.d.ts +18 -12
- package/dist/intermodal/calculate/chargeableDays.js +27 -18
- package/dist/intermodal/calculate/demurrageClock.d.ts +1 -1
- package/dist/intermodal/calculate/demurrageClock.js +2 -2
- package/dist/intermodal/calculate/freeTimeExpiry.d.ts +17 -10
- package/dist/intermodal/calculate/freeTimeExpiry.js +32 -17
- package/dist/intermodal/calculate/index.d.ts +1 -0
- package/dist/intermodal/calculate/index.js +1 -0
- package/dist/intermodal/calculate/multimodalETA.d.ts +76 -0
- package/dist/intermodal/calculate/multimodalETA.js +145 -0
- package/dist/intermodal/format/bolTimestamp.d.ts +76 -0
- package/dist/intermodal/format/bolTimestamp.js +78 -0
- package/dist/intermodal/format/formatEdifactDate.d.ts +34 -0
- package/dist/intermodal/format/formatEdifactDate.js +42 -0
- package/dist/intermodal/format/formatEdifactDatePeriod.d.ts +35 -0
- package/dist/intermodal/format/formatEdifactDatePeriod.js +43 -0
- package/dist/intermodal/format/formatEdifactDateTime.d.ts +37 -0
- package/dist/intermodal/format/formatEdifactDateTime.js +45 -0
- package/dist/intermodal/format/formatEdifactDateTimePeriod.d.ts +40 -0
- package/dist/intermodal/format/formatEdifactDateTimePeriod.js +48 -0
- package/dist/intermodal/format/formatEdifactOffsetDateTime.d.ts +62 -0
- package/dist/intermodal/format/formatEdifactOffsetDateTime.js +70 -0
- package/dist/intermodal/format/formatEdifactTime.d.ts +35 -0
- package/dist/intermodal/format/formatEdifactTime.js +43 -0
- package/dist/intermodal/format/formatEpcisEvent.d.ts +47 -0
- package/dist/intermodal/format/formatEpcisEvent.js +79 -0
- package/dist/intermodal/format/formatX12Date.d.ts +35 -0
- package/dist/intermodal/format/formatX12Date.js +43 -0
- package/dist/intermodal/format/formatX12DateRange.d.ts +37 -0
- package/dist/intermodal/format/formatX12DateRange.js +45 -0
- package/dist/intermodal/format/formatX12DateTime.d.ts +39 -0
- package/dist/intermodal/format/formatX12DateTime.js +47 -0
- package/dist/intermodal/format/formatX12DateTimeRange.d.ts +40 -0
- package/dist/intermodal/format/formatX12DateTimeRange.js +48 -0
- package/dist/intermodal/format/formatX12Time.d.ts +42 -0
- package/dist/intermodal/format/formatX12Time.js +50 -0
- package/dist/intermodal/format/formatX12TimeElement.d.ts +46 -0
- package/dist/intermodal/format/formatX12TimeElement.js +54 -0
- package/dist/intermodal/format/index.d.ts +14 -0
- package/dist/intermodal/format/index.js +14 -0
- package/dist/intermodal/index.d.ts +4 -1
- package/dist/intermodal/index.js +5 -2
- package/dist/intermodal/parse/classifyEdifactDtmFormat.d.ts +48 -0
- package/dist/intermodal/parse/classifyEdifactDtmFormat.js +55 -0
- package/dist/intermodal/parse/classifyX12DateTimePeriodFormat.d.ts +50 -0
- package/dist/intermodal/parse/classifyX12DateTimePeriodFormat.js +57 -0
- package/dist/intermodal/parse/classifyX12TimeCode.d.ts +46 -0
- package/dist/intermodal/parse/classifyX12TimeCode.js +57 -0
- package/dist/intermodal/parse/index.d.ts +18 -0
- package/dist/intermodal/parse/index.js +18 -0
- package/dist/intermodal/parse/parseEdifactDate.d.ts +37 -0
- package/dist/intermodal/parse/parseEdifactDate.js +45 -0
- package/dist/intermodal/parse/parseEdifactDatePeriod.d.ts +43 -0
- package/dist/intermodal/parse/parseEdifactDatePeriod.js +51 -0
- package/dist/intermodal/parse/parseEdifactDateTime.d.ts +43 -0
- package/dist/intermodal/parse/parseEdifactDateTime.js +51 -0
- package/dist/intermodal/parse/parseEdifactDateTimePeriod.d.ts +45 -0
- package/dist/intermodal/parse/parseEdifactDateTimePeriod.js +53 -0
- package/dist/intermodal/parse/parseEdifactOffsetDateTime.d.ts +60 -0
- package/dist/intermodal/parse/parseEdifactOffsetDateTime.js +68 -0
- package/dist/intermodal/parse/parseEdifactTime.d.ts +37 -0
- package/dist/intermodal/parse/parseEdifactTime.js +45 -0
- package/dist/intermodal/parse/parseEpcisEvent.d.ts +95 -0
- package/dist/intermodal/parse/parseEpcisEvent.js +102 -0
- package/dist/intermodal/parse/parseX12Date.d.ts +39 -0
- package/dist/intermodal/parse/parseX12Date.js +47 -0
- package/dist/intermodal/parse/parseX12DateAndTime.d.ts +52 -0
- package/dist/intermodal/parse/parseX12DateAndTime.js +61 -0
- package/dist/intermodal/parse/parseX12DateRange.d.ts +44 -0
- package/dist/intermodal/parse/parseX12DateRange.js +52 -0
- package/dist/intermodal/parse/parseX12DateTime.d.ts +45 -0
- package/dist/intermodal/parse/parseX12DateTime.js +53 -0
- package/dist/intermodal/parse/parseX12DateTimeRange.d.ts +46 -0
- package/dist/intermodal/parse/parseX12DateTimeRange.js +54 -0
- package/dist/intermodal/parse/parseX12Time.d.ts +65 -0
- package/dist/intermodal/parse/parseX12Time.js +77 -0
- package/dist/intermodal/parse/x12TimeCodeOffset.d.ts +57 -0
- package/dist/intermodal/parse/x12TimeCodeOffset.js +110 -0
- package/dist/intermodal/parse/x12TimeCodeZone.d.ts +57 -0
- package/dist/intermodal/parse/x12TimeCodeZone.js +105 -0
- package/dist/intermodal/validate/index.d.ts +18 -0
- package/dist/intermodal/validate/index.js +18 -0
- package/dist/intermodal/validate/isValidEdifactDate.d.ts +26 -0
- package/dist/intermodal/validate/isValidEdifactDate.js +28 -0
- package/dist/intermodal/validate/isValidEdifactDatePeriod.d.ts +28 -0
- package/dist/intermodal/validate/isValidEdifactDatePeriod.js +30 -0
- package/dist/intermodal/validate/isValidEdifactDateTime.d.ts +30 -0
- package/dist/intermodal/validate/isValidEdifactDateTime.js +32 -0
- package/dist/intermodal/validate/isValidEdifactDateTimePeriod.d.ts +28 -0
- package/dist/intermodal/validate/isValidEdifactDateTimePeriod.js +30 -0
- package/dist/intermodal/validate/isValidEdifactDtmFormat.d.ts +39 -0
- package/dist/intermodal/validate/isValidEdifactDtmFormat.js +42 -0
- package/dist/intermodal/validate/isValidEdifactOffsetDateTime.d.ts +36 -0
- package/dist/intermodal/validate/isValidEdifactOffsetDateTime.js +38 -0
- package/dist/intermodal/validate/isValidEdifactTime.d.ts +28 -0
- package/dist/intermodal/validate/isValidEdifactTime.js +30 -0
- package/dist/intermodal/validate/isValidEpcisEvent.d.ts +41 -0
- package/dist/intermodal/validate/isValidEpcisEvent.js +58 -0
- package/dist/intermodal/validate/isValidEpcisEventTime.d.ts +33 -0
- package/dist/intermodal/validate/isValidEpcisEventTime.js +48 -0
- package/dist/intermodal/validate/isValidEpcisTimeZoneOffset.d.ts +30 -0
- package/dist/intermodal/validate/isValidEpcisTimeZoneOffset.js +38 -0
- package/dist/intermodal/validate/isValidX12Date.d.ts +28 -0
- package/dist/intermodal/validate/isValidX12Date.js +30 -0
- package/dist/intermodal/validate/isValidX12DateAndTime.d.ts +32 -0
- package/dist/intermodal/validate/isValidX12DateAndTime.js +35 -0
- package/dist/intermodal/validate/isValidX12DateRange.d.ts +29 -0
- package/dist/intermodal/validate/isValidX12DateRange.js +31 -0
- package/dist/intermodal/validate/isValidX12DateTime.d.ts +30 -0
- package/dist/intermodal/validate/isValidX12DateTime.js +32 -0
- package/dist/intermodal/validate/isValidX12DateTimePeriodFormat.d.ts +43 -0
- package/dist/intermodal/validate/isValidX12DateTimePeriodFormat.js +46 -0
- package/dist/intermodal/validate/isValidX12DateTimeRange.d.ts +31 -0
- package/dist/intermodal/validate/isValidX12DateTimeRange.js +33 -0
- package/dist/intermodal/validate/isValidX12Time.d.ts +38 -0
- package/dist/intermodal/validate/isValidX12Time.js +40 -0
- package/dist/intermodal/validate/isValidX12TimeCode.d.ts +38 -0
- package/dist/intermodal/validate/isValidX12TimeCode.js +41 -0
- package/dist/internal/advanceToWeekday.d.ts +1 -1
- package/dist/internal/businessCalendar.d.ts +28 -12
- package/dist/internal/businessCalendar.js +131 -125
- package/dist/internal/businessDayValues.js +1 -1
- package/dist/internal/calendarDatePairPolicy.d.ts +1 -1
- package/dist/internal/calendarDateString.d.ts +1 -1
- package/dist/internal/calendarDateString.js +1 -1
- package/dist/internal/calendarSystemIds.js +1 -1
- package/dist/internal/calendarValueOfDate.js +1 -1
- package/dist/internal/calendarZonedPairPolicy.d.ts +1 -1
- package/dist/internal/calendarZonedString.d.ts +3 -3
- package/dist/internal/calendarZonedString.js +4 -4
- package/dist/internal/compareUnixEpochs.js +1 -1
- package/dist/internal/cutoffAtResolved.d.ts +62 -0
- package/dist/internal/cutoffAtResolved.js +162 -0
- package/dist/internal/cycleFieldValue.d.ts +0 -2
- package/dist/internal/cycleFieldValue.js +0 -2
- package/dist/internal/dateTimeUnitHelpers.d.ts +1 -1
- package/dist/internal/dateUnitHelpers.d.ts +1 -1
- package/dist/internal/daylightTime.d.ts +1 -1
- package/dist/internal/differenceRecord.d.ts +1 -1
- package/dist/internal/durationUntilString.d.ts +1 -1
- package/dist/internal/durationUntilString.js +1 -1
- package/dist/internal/dutyEngine.d.ts +125 -0
- package/dist/internal/dutyEngine.js +1755 -0
- package/dist/internal/dutyLog.d.ts +27 -0
- package/dist/internal/dutyLog.js +47 -0
- package/dist/internal/dutyPeriods.d.ts +135 -0
- package/dist/internal/dutyPeriods.js +375 -0
- package/dist/internal/dutyRules.d.ts +198 -0
- package/dist/internal/dutyRules.js +484 -0
- package/dist/internal/dutyRunIndex.d.ts +150 -0
- package/dist/internal/dutyRunIndex.js +398 -0
- package/dist/internal/earlierOccurrence.d.ts +41 -0
- package/dist/internal/earlierOccurrence.js +57 -0
- package/dist/internal/ediDateTimeFields.d.ts +97 -0
- package/dist/internal/ediDateTimeFields.js +288 -0
- package/dist/internal/ediDateTimeWriter.d.ts +92 -0
- package/dist/internal/ediDateTimeWriter.js +298 -0
- package/dist/internal/ediGrammar.d.ts +158 -0
- package/dist/internal/ediGrammar.js +384 -0
- package/dist/internal/englishCalendarNames.d.ts +4 -2
- package/dist/internal/englishCalendarNames.js +3 -1
- package/dist/internal/epochDay.d.ts +41 -0
- package/dist/internal/epochDay.js +129 -0
- package/dist/internal/exactDuration.js +1 -1
- package/dist/internal/exactMoment.d.ts +4 -4
- package/dist/internal/exactMoment.js +5 -5
- package/dist/internal/fiscalCalendar.d.ts +41 -7
- package/dist/internal/fiscalCalendar.js +77 -9
- package/dist/internal/foreignEpochs.d.ts +5 -0
- package/dist/internal/foreignEpochs.js +5 -0
- package/dist/internal/formatCalendarDays.d.ts +4 -4
- package/dist/internal/formatCalendarDays.js +6 -5
- package/dist/internal/formatDateInCalendar.d.ts +1 -1
- package/dist/internal/formatRelativeDuration.d.ts +7 -7
- package/dist/internal/formatRelativeDuration.js +8 -7
- package/dist/internal/formatterCache.d.ts +40 -0
- package/dist/internal/formatterCache.js +181 -0
- package/dist/internal/freeTimeLedger.d.ts +35 -42
- package/dist/internal/freeTimeLedger.js +332 -31
- package/dist/internal/getLocaleWeekYearBounds.d.ts +1 -1
- package/dist/internal/gnssTimeScales.d.ts +53 -0
- package/dist/internal/gnssTimeScales.js +128 -0
- package/dist/internal/gnssWeek.d.ts +92 -0
- package/dist/internal/gnssWeek.js +212 -0
- package/dist/internal/halfOpenIntervals.d.ts +1 -1
- package/dist/internal/halfOpenIntervals.js +1 -1
- package/dist/internal/hasCalendarAnnotation.d.ts +3 -3
- package/dist/internal/hasCalendarAnnotation.js +3 -3
- package/dist/internal/hourDurationString.js +1 -1
- package/dist/internal/httpDateFields.js +1 -1
- package/dist/internal/index.d.ts +14 -5
- package/dist/internal/index.js +18 -5
- package/dist/internal/inputChecks.d.ts +53 -0
- package/dist/internal/inputChecks.js +132 -0
- package/dist/internal/instantFormatOptions.d.ts +1 -1
- package/dist/internal/instantFormatOptions.js +4 -8
- package/dist/internal/instantIntervalText.js +1 -1
- package/dist/internal/instantNanoseconds.d.ts +2 -2
- package/dist/internal/instantNanoseconds.js +2 -2
- package/dist/internal/intervalCountHelpers.d.ts +1 -1
- package/dist/internal/intervalNanoseconds.js +2 -1
- package/dist/internal/isObject.d.ts +13 -6
- package/dist/internal/isObject.js +14 -7
- package/dist/internal/isoStringBody.d.ts +2 -2
- package/dist/internal/isoStringBody.js +2 -2
- package/dist/internal/isoYearString.d.ts +21 -0
- package/dist/internal/isoYearString.js +27 -0
- package/dist/internal/joinDateTimeConnector.js +3 -2
- package/dist/internal/leapSeconds.d.ts +63 -0
- package/dist/internal/leapSeconds.js +162 -0
- package/dist/internal/localeWeekInfo.d.ts +1 -1
- package/dist/internal/localeWeekInfo.js +1 -1
- package/dist/internal/maxPieces.js +2 -1
- package/dist/internal/monthGridWeekRow.d.ts +1 -1
- package/dist/internal/normalizeDateTime.d.ts +2 -1
- package/dist/internal/normalizeDateTime.js +3 -2
- package/dist/internal/normalizeTimeZone.d.ts +5 -2
- package/dist/internal/normalizeTimeZone.js +5 -2
- package/dist/internal/offsetTimeline.d.ts +56 -0
- package/dist/internal/offsetTimeline.js +166 -0
- package/dist/internal/operatingSchedule.d.ts +39 -34
- package/dist/internal/operatingSchedule.js +672 -222
- package/dist/internal/patternToken.d.ts +10 -3
- package/dist/internal/patternToken.js +41 -19
- package/dist/internal/plainDateAdd.d.ts +1 -1
- package/dist/internal/plainDateAdd.js +1 -1
- package/dist/internal/plainDateUntil.d.ts +1 -1
- package/dist/internal/plainDateUntil.js +1 -1
- package/dist/internal/readDurationUnits.d.ts +34 -0
- package/dist/internal/readDurationUnits.js +78 -0
- package/dist/internal/readSetFields.d.ts +50 -0
- package/dist/internal/readSetFields.js +179 -0
- package/dist/internal/resolveDurationRelativeTo.d.ts +1 -1
- package/dist/internal/resolveDurationRelativeTo.js +1 -1
- package/dist/internal/resolveLocale.d.ts +2 -2
- package/dist/internal/resolveLocale.js +2 -2
- package/dist/internal/resolveManualRoundingOptions.d.ts +1 -1
- package/dist/internal/resolveRelativeUnit.d.ts +1 -1
- package/dist/internal/resolveRelativeUnit.js +1 -1
- package/dist/internal/resolveUnixIntervalPair.d.ts +9 -3
- package/dist/internal/resolveUnixIntervalPair.js +11 -7
- package/dist/internal/rinexWeek.d.ts +22 -0
- package/dist/internal/rinexWeek.js +30 -0
- package/dist/internal/rollBusinessDate.d.ts +15 -0
- package/dist/internal/rollBusinessDate.js +46 -0
- package/dist/internal/splitStep.d.ts +1 -1
- package/dist/internal/splitStep.js +1 -1
- package/dist/internal/startOrEndOfUnix.d.ts +3 -2
- package/dist/internal/startOrEndOfUnix.js +9 -6
- package/dist/internal/startOrEndOfUtc.d.ts +1 -1
- package/dist/internal/startOrEndOfUtc.js +1 -1
- package/dist/internal/startOrEndOfZoned.d.ts +1 -1
- package/dist/internal/temporal.d.ts +5 -0
- package/dist/internal/temporal.js +5 -0
- package/dist/internal/temporalCompat/calendarDateArithmetic.d.ts +1 -1
- package/dist/internal/temporalCompat/calendarDateFromFields.d.ts +1 -1
- package/dist/internal/temporalCompat/calendarDateFromFields.js +1 -1
- package/dist/internal/temporalCompat/calendarFields.d.ts +1 -1
- package/dist/internal/temporalCompat/capabilities.d.ts +27 -5
- package/dist/internal/temporalCompat/capabilities.js +28 -4
- package/dist/internal/temporalCompat/fieldSearch.d.ts +1 -1
- package/dist/internal/temporalCompat/fieldSearch.js +1 -1
- package/dist/internal/temporalCompat/fixedDay.d.ts +1 -1
- package/dist/internal/temporalCompat/fixedDay.js +1 -1
- package/dist/internal/temporalCompat/index.d.ts +1 -1
- package/dist/internal/temporalCompat/index.js +1 -1
- package/dist/internal/temporalCompat/largeMonthSpan.js +1 -1
- package/dist/internal/temporalCompat/nonIsoArithmetic.d.ts +1 -1
- package/dist/internal/temporalCompat/nonIsoArithmetic.js +1 -1
- package/dist/internal/temporalCompat/probeRepros.d.ts +35 -0
- package/dist/internal/temporalCompat/probeRepros.js +571 -0
- package/dist/internal/temporalCompat/readArithmeticModel.js +2 -2
- package/dist/internal/temporalCompat/repros.d.ts +3 -10
- package/dist/internal/temporalCompat/repros.js +13 -520
- package/dist/internal/timeScaleString.d.ts +47 -0
- package/dist/internal/timeScaleString.js +86 -0
- package/dist/internal/toInstantFromUtc.d.ts +1 -1
- package/dist/internal/toInstantFromUtc.js +1 -1
- package/dist/internal/twoDigitYear.d.ts +19 -0
- package/dist/internal/twoDigitYear.js +22 -0
- package/dist/internal/unixEpochValue.d.ts +1 -1
- package/dist/internal/unixEpochValue.js +4 -3
- package/dist/internal/unixFormatReference.d.ts +1 -1
- package/dist/internal/unixFormatReference.js +1 -1
- package/dist/internal/unixWallClock.d.ts +24 -0
- package/dist/internal/unixWallClock.js +35 -0
- package/dist/internal/utcOffsetString.d.ts +16 -0
- package/dist/internal/utcOffsetString.js +31 -1
- package/dist/internal/utcReading.d.ts +59 -0
- package/dist/internal/utcReading.js +113 -0
- package/dist/internal/utcWallClock.d.ts +20 -0
- package/dist/internal/utcWallClock.js +32 -0
- package/dist/internal/validatedZones.d.ts +20 -0
- package/dist/internal/validatedZones.js +33 -0
- package/dist/internal/wallClockAtOffset.d.ts +1 -1
- package/dist/internal/yearWindowStart.d.ts +28 -0
- package/dist/internal/yearWindowStart.js +52 -0
- package/dist/internal/zoneBucketCap.d.ts +18 -0
- package/dist/internal/zoneBucketCap.js +64 -0
- package/dist/internal/zoneFrame.d.ts +180 -0
- package/dist/internal/zoneFrame.js +221 -0
- package/dist/internal/zonedBucket.d.ts +2 -2
- package/dist/internal/zonedBucket.js +92 -21
- package/dist/internal/zonedFormatReference.d.ts +1 -1
- package/dist/internal/zonedFormatReference.js +1 -1
- package/dist/internal/zonedLocalDates.d.ts +1 -1
- package/dist/internal/zonedLocalDates.js +22 -19
- package/dist/internal/zonedNowUnitValue.d.ts +8 -5
- package/dist/internal/zonedNowUnitValue.js +9 -5
- package/dist/internal/zonedTransitionSearch.d.ts +2 -0
- package/dist/internal/zonedTransitionSearch.js +165 -16
- package/dist/internal/zonedWallClock.d.ts +15 -4
- package/dist/internal/zonedWallClock.js +34 -6
- package/dist/internal/zonedWallClockDifference.d.ts +1 -1
- package/dist/internal/zonedWallClockDifference.js +6 -6
- package/dist/internal/zonedWallClockOperations.d.ts +7 -4
- package/dist/internal/zonedWallClockOperations.js +58 -16
- package/dist/internal/zonelessCalendarDate.d.ts +1 -1
- package/dist/internal/zonelessCalendarDate.js +1 -1
- package/dist/interval/index.d.ts +1 -1
- package/dist/interval/index.js +2 -2
- package/dist/plain/calculate/addBusinessDays.d.ts +2 -2
- package/dist/plain/calculate/addBusinessDays.js +2 -2
- package/dist/plain/calculate/addDate.js +4 -7
- package/dist/plain/calculate/addDateTime.js +5 -8
- package/dist/plain/calculate/addTime.js +5 -8
- package/dist/plain/calculate/clampDate.js +1 -1
- package/dist/plain/calculate/closestDateTo.js +1 -1
- package/dist/plain/calculate/cycleDate.js +1 -1
- package/dist/plain/calculate/cycleDateTime.js +1 -1
- package/dist/plain/calculate/cycleTime.js +1 -1
- package/dist/plain/calculate/diffDate.d.ts +1 -1
- package/dist/plain/calculate/diffDateAsDuration.d.ts +1 -1
- package/dist/plain/calculate/diffDateTime.d.ts +1 -1
- package/dist/plain/calculate/diffDateTime.js +1 -1
- package/dist/plain/calculate/diffDateTimeAsDuration.d.ts +1 -1
- package/dist/plain/calculate/diffDateTimeAsDuration.js +1 -1
- package/dist/plain/calculate/diffTime.d.ts +1 -1
- package/dist/plain/calculate/diffTime.js +1 -1
- package/dist/plain/calculate/endOfDate.d.ts +1 -1
- package/dist/plain/calculate/endOfDate.js +1 -1
- package/dist/plain/calculate/endOfDateTime.d.ts +1 -1
- package/dist/plain/calculate/endOfDateTime.js +1 -1
- package/dist/plain/calculate/endOfQuarterForDate.js +1 -1
- package/dist/plain/calculate/endOfQuarterForDateTime.js +1 -1
- package/dist/plain/calculate/endOfTime.d.ts +2 -2
- package/dist/plain/calculate/endOfTime.js +1 -1
- package/dist/plain/calculate/getDayOfYear.js +1 -1
- package/dist/plain/calculate/getDaysInMonth.js +1 -1
- package/dist/plain/calculate/getDaysInYear.js +1 -1
- package/dist/plain/calculate/getLargestDateDurationUnit.d.ts +1 -1
- package/dist/plain/calculate/getLargestDateTimeDurationUnit.d.ts +1 -1
- package/dist/plain/calculate/getLargestTimeDurationUnit.d.ts +1 -1
- package/dist/plain/calculate/getLocaleDayOfWeek.d.ts +6 -6
- package/dist/plain/calculate/getLocaleDayOfWeek.js +7 -7
- package/dist/plain/calculate/getLocaleEndOfWeek.d.ts +4 -4
- package/dist/plain/calculate/getLocaleEndOfWeek.js +5 -5
- package/dist/plain/calculate/getLocaleStartOfWeek.d.ts +5 -5
- package/dist/plain/calculate/getLocaleStartOfWeek.js +6 -6
- package/dist/plain/calculate/getLocaleWeekYear.d.ts +10 -10
- package/dist/plain/calculate/getLocaleWeekYear.js +11 -11
- package/dist/plain/calculate/getQuarterForDate.js +1 -1
- package/dist/plain/calculate/getQuarterForDateTime.js +1 -1
- package/dist/plain/calculate/getWeekNumber.js +1 -1
- package/dist/plain/calculate/getWeekOfMonth.d.ts +10 -14
- package/dist/plain/calculate/getWeekOfMonth.js +11 -15
- package/dist/plain/calculate/getWeekYear.js +1 -1
- package/dist/plain/calculate/getWeeksInLocaleWeekYear.d.ts +7 -7
- package/dist/plain/calculate/getWeeksInLocaleWeekYear.js +8 -8
- package/dist/plain/calculate/getWeeksInMonth.d.ts +8 -11
- package/dist/plain/calculate/getWeeksInMonth.js +9 -12
- package/dist/plain/calculate/getWeeksInYear.js +1 -1
- package/dist/plain/calculate/maxDate.js +1 -1
- package/dist/plain/calculate/maxDateTime.js +1 -1
- package/dist/plain/calculate/maxTime.js +1 -1
- package/dist/plain/calculate/minDate.js +1 -1
- package/dist/plain/calculate/minDateTime.js +1 -1
- package/dist/plain/calculate/minTime.js +1 -1
- package/dist/plain/calculate/nextWeekday.d.ts +14 -12
- package/dist/plain/calculate/nextWeekday.js +15 -13
- package/dist/plain/calculate/previousWeekday.d.ts +14 -12
- package/dist/plain/calculate/previousWeekday.js +15 -13
- package/dist/plain/calculate/roundDate.d.ts +1 -1
- package/dist/plain/calculate/roundDate.js +1 -1
- package/dist/plain/calculate/roundDateTime.d.ts +1 -1
- package/dist/plain/calculate/roundDateTime.js +1 -1
- package/dist/plain/calculate/roundTime.d.ts +1 -1
- package/dist/plain/calculate/roundTime.js +1 -1
- package/dist/plain/calculate/setDate.d.ts +21 -4
- package/dist/plain/calculate/setDate.js +28 -8
- package/dist/plain/calculate/setDateTime.d.ts +16 -4
- package/dist/plain/calculate/setDateTime.js +23 -8
- package/dist/plain/calculate/setTime.d.ts +14 -2
- package/dist/plain/calculate/setTime.js +22 -7
- package/dist/plain/calculate/sortDateTimes.js +1 -1
- package/dist/plain/calculate/sortDates.js +1 -1
- package/dist/plain/calculate/sortTimes.js +1 -1
- package/dist/plain/calculate/startOfDate.d.ts +1 -1
- package/dist/plain/calculate/startOfDate.js +1 -1
- package/dist/plain/calculate/startOfDateTime.d.ts +1 -1
- package/dist/plain/calculate/startOfDateTime.js +1 -1
- package/dist/plain/calculate/startOfQuarterForDate.js +1 -1
- package/dist/plain/calculate/startOfQuarterForDateTime.js +1 -1
- package/dist/plain/calculate/startOfTime.d.ts +2 -2
- package/dist/plain/calculate/startOfTime.js +1 -1
- package/dist/plain/calculate/subtractBusinessDays.d.ts +2 -2
- package/dist/plain/calculate/subtractBusinessDays.js +2 -2
- package/dist/plain/calculate/subtractDate.js +5 -8
- package/dist/plain/calculate/subtractDateTime.js +5 -8
- package/dist/plain/calculate/subtractTime.js +5 -8
- package/dist/plain/calculate/weekOfYearForDate.js +1 -1
- package/dist/plain/calculate/weekOfYearForDateTime.js +1 -1
- package/dist/plain/chop/chopDate.js +1 -1
- package/dist/plain/chop/chopMilliseconds.js +1 -1
- package/dist/plain/chop/chopSeconds.js +1 -1
- package/dist/plain/chop/chopTime.js +1 -1
- package/dist/plain/compare/areDateTimesEqual.js +1 -1
- package/dist/plain/compare/areDateTimesEqualBy.d.ts +2 -4
- package/dist/plain/compare/areDateTimesEqualBy.js +2 -4
- package/dist/plain/compare/areDatesEqual.js +1 -1
- package/dist/plain/compare/areDatesEqualBy.d.ts +5 -5
- package/dist/plain/compare/areDatesEqualBy.js +5 -5
- package/dist/plain/compare/areTimesEqual.js +1 -1
- package/dist/plain/compare/isAfterDate.js +1 -1
- package/dist/plain/compare/isAfterDateTime.js +1 -1
- package/dist/plain/compare/isAfterTime.js +1 -1
- package/dist/plain/compare/isBeforeDate.js +1 -1
- package/dist/plain/compare/isBeforeDateTime.js +1 -1
- package/dist/plain/compare/isBeforeTime.js +1 -1
- package/dist/plain/compare/isBetweenDate.js +1 -1
- package/dist/plain/compare/isBetweenDateTime.js +1 -1
- package/dist/plain/compare/isBetweenTime.js +1 -1
- package/dist/plain/compare/isBusinessDay.d.ts +2 -2
- package/dist/plain/compare/isBusinessDay.js +3 -3
- package/dist/plain/compare/isRelativeDay.d.ts +1 -1
- package/dist/plain/compare/isRelativeDay.js +1 -1
- package/dist/plain/compare/isThisUnit.d.ts +8 -6
- package/dist/plain/compare/isThisUnit.js +7 -5
- package/dist/plain/compare/isWeekend.d.ts +5 -5
- package/dist/plain/compare/isWeekend.js +6 -6
- package/dist/plain/format/formatCalendar.d.ts +3 -5
- package/dist/plain/format/formatCalendar.js +12 -10
- package/dist/plain/format/formatDate.d.ts +4 -4
- package/dist/plain/format/formatDate.js +8 -7
- package/dist/plain/format/formatDateRange.d.ts +4 -4
- package/dist/plain/format/formatDateRange.js +8 -7
- package/dist/plain/format/formatDateTime.d.ts +4 -4
- package/dist/plain/format/formatDateTime.js +8 -7
- package/dist/plain/format/formatDateTimeRange.d.ts +4 -4
- package/dist/plain/format/formatDateTimeRange.js +8 -7
- package/dist/plain/format/formatDateTimeToParts.d.ts +6 -6
- package/dist/plain/format/formatDateTimeToParts.js +10 -9
- package/dist/plain/format/formatDateToParts.d.ts +6 -6
- package/dist/plain/format/formatDateToParts.js +10 -9
- package/dist/plain/format/formatRelativeDate.d.ts +3 -3
- package/dist/plain/format/formatRelativeDate.js +6 -5
- package/dist/plain/format/formatRelativeDateTime.d.ts +3 -3
- package/dist/plain/format/formatRelativeDateTime.js +6 -5
- package/dist/plain/format/formatRelativeTime.d.ts +3 -3
- package/dist/plain/format/formatRelativeTime.js +6 -5
- package/dist/plain/format/{formatSql.d.ts → formatSqlDateTime.d.ts} +7 -7
- package/dist/plain/format/{formatSql.js → formatSqlDateTime.js} +8 -8
- package/dist/plain/format/formatTime.d.ts +4 -4
- package/dist/plain/format/formatTime.js +8 -7
- package/dist/plain/format/index.d.ts +1 -1
- package/dist/plain/format/index.js +1 -1
- package/dist/plain/get/getDay.js +1 -1
- package/dist/plain/get/getDayOfWeek.js +1 -1
- package/dist/plain/get/getHour.js +1 -1
- package/dist/plain/get/getMicrosecond.js +1 -1
- package/dist/plain/get/getMillisecond.js +1 -1
- package/dist/plain/get/getMinute.js +1 -1
- package/dist/plain/get/getMonth.js +1 -1
- package/dist/plain/get/getNanosecond.js +1 -1
- package/dist/plain/get/getNow.js +1 -1
- package/dist/plain/get/getNowUnit.d.ts +2 -0
- package/dist/plain/get/getNowUnit.js +3 -1
- package/dist/plain/get/getSecond.js +1 -1
- package/dist/plain/get/getToday.js +1 -1
- package/dist/plain/get/getWeekOfYear.js +1 -1
- package/dist/plain/get/getYear.d.ts +2 -0
- package/dist/plain/get/getYear.js +5 -4
- package/dist/plain/index.d.ts +1 -1
- package/dist/plain/index.js +2 -2
- package/dist/plain/interval/intervalAbutsDate.d.ts +1 -2
- package/dist/plain/interval/intervalAbutsDate.js +2 -3
- package/dist/plain/interval/intervalAbutsDateTime.js +1 -1
- package/dist/plain/interval/intervalAbutsTime.js +1 -1
- package/dist/plain/interval/intervalContainsDate.d.ts +1 -1
- package/dist/plain/interval/intervalContainsDate.js +2 -2
- package/dist/plain/interval/intervalContainsDateTime.js +1 -1
- package/dist/plain/interval/intervalContainsTime.js +1 -1
- package/dist/plain/interval/intervalCountDate.js +1 -1
- package/dist/plain/interval/intervalCountDateTime.js +1 -1
- package/dist/plain/interval/intervalCountTime.js +1 -1
- package/dist/plain/interval/intervalDifferenceDate.d.ts +1 -1
- package/dist/plain/interval/intervalDifferenceDate.js +2 -2
- package/dist/plain/interval/intervalDifferenceDateTime.js +1 -1
- package/dist/plain/interval/intervalDifferenceTime.js +1 -1
- package/dist/plain/interval/intervalDivideEquallyDate.d.ts +3 -3
- package/dist/plain/interval/intervalDivideEquallyDate.js +3 -3
- package/dist/plain/interval/intervalDivideEquallyDateTime.js +1 -1
- package/dist/plain/interval/intervalDivideEquallyTime.js +1 -1
- package/dist/plain/interval/intervalEngulfsDate.d.ts +1 -1
- package/dist/plain/interval/intervalEngulfsDate.js +2 -2
- package/dist/plain/interval/intervalEngulfsDateTime.js +1 -1
- package/dist/plain/interval/intervalEngulfsTime.js +1 -1
- package/dist/plain/interval/intervalFromDurationDate.js +1 -1
- package/dist/plain/interval/intervalFromDurationDateTime.js +1 -1
- package/dist/plain/interval/intervalFromDurationTime.js +1 -1
- package/dist/plain/interval/intervalIntersectionDate.d.ts +1 -1
- package/dist/plain/interval/intervalIntersectionDate.js +2 -2
- package/dist/plain/interval/intervalIntersectionDateTime.js +1 -1
- package/dist/plain/interval/intervalIntersectionTime.js +1 -1
- package/dist/plain/interval/intervalLengthDateTime.js +1 -1
- package/dist/plain/interval/intervalLengthTime.js +1 -1
- package/dist/plain/interval/intervalOverlappingDaysDate.js +1 -1
- package/dist/plain/interval/intervalOverlappingDaysDateTime.js +1 -1
- package/dist/plain/interval/intervalSplitAtDate.d.ts +1 -1
- package/dist/plain/interval/intervalSplitAtDate.js +2 -2
- package/dist/plain/interval/intervalSplitAtDateTime.js +1 -1
- package/dist/plain/interval/intervalSplitAtTime.js +1 -1
- package/dist/plain/interval/intervalUnionDate.d.ts +2 -2
- package/dist/plain/interval/intervalUnionDate.js +3 -3
- package/dist/plain/interval/intervalUnionDateTime.js +1 -1
- package/dist/plain/interval/intervalUnionTime.js +1 -1
- package/dist/plain/interval/intervalXorAllDate.d.ts +1 -1
- package/dist/plain/interval/intervalXorAllDate.js +4 -4
- package/dist/plain/interval/intervalXorAllDateTime.js +3 -3
- package/dist/plain/interval/intervalXorAllTime.js +3 -3
- package/dist/plain/interval/intervalXorDate.d.ts +1 -1
- package/dist/plain/interval/intervalXorDate.js +2 -2
- package/dist/plain/interval/intervalXorDateTime.js +1 -1
- package/dist/plain/interval/intervalXorTime.js +1 -1
- package/dist/plain/interval/intervalsOverlapDate.d.ts +1 -1
- package/dist/plain/interval/intervalsOverlapDate.js +2 -2
- package/dist/plain/interval/intervalsOverlapDateTime.js +1 -1
- package/dist/plain/interval/intervalsOverlapTime.js +1 -1
- package/dist/plain/interval/mergeIntervalsDate.d.ts +1 -1
- package/dist/plain/interval/mergeIntervalsDate.js +4 -4
- package/dist/plain/interval/mergeIntervalsDateTime.js +3 -3
- package/dist/plain/interval/mergeIntervalsTime.js +3 -3
- package/dist/plain/interval/splitIntervalByUnitDate.d.ts +2 -3
- package/dist/plain/interval/splitIntervalByUnitDate.js +3 -4
- package/dist/plain/interval/splitIntervalByUnitDateTime.d.ts +2 -1
- package/dist/plain/interval/splitIntervalByUnitDateTime.js +3 -2
- package/dist/plain/interval/splitIntervalByUnitTime.js +1 -1
- package/dist/plain/interval/validate/isValidDateInterval.d.ts +1 -1
- package/dist/plain/interval/validate/isValidDateInterval.js +2 -2
- package/dist/plain/interval/validate/isValidDateTimeInterval.js +1 -1
- package/dist/plain/interval/validate/isValidTimeInterval.js +1 -1
- package/dist/plain/locale/getLocaleEraNames.d.ts +6 -6
- package/dist/plain/locale/getLocaleEraNames.js +8 -7
- package/dist/plain/locale/getLocaleMeridiems.d.ts +5 -5
- package/dist/plain/locale/getLocaleMeridiems.js +7 -6
- package/dist/plain/locale/getLocaleMonthNames.d.ts +6 -6
- package/dist/plain/locale/getLocaleMonthNames.js +17 -11
- package/dist/plain/locale/getLocaleWeekdayNames.d.ts +3 -3
- package/dist/plain/locale/getLocaleWeekdayNames.js +12 -5
- package/dist/plain/map/mapDatesInRange.js +1 -1
- package/dist/plain/map/mapDaysInMonth.js +1 -1
- package/dist/plain/parse/index.d.ts +1 -1
- package/dist/plain/parse/index.js +1 -1
- package/dist/plain/parse/parseDateTimeWithPattern.d.ts +28 -14
- package/dist/plain/parse/parseDateTimeWithPattern.js +33 -17
- package/dist/plain/parse/parseDateWithPattern.d.ts +29 -14
- package/dist/plain/parse/parseDateWithPattern.js +34 -17
- package/dist/plain/parse/parseDayFromDate.js +1 -1
- package/dist/plain/parse/parseDayFromDateTime.js +1 -1
- package/dist/plain/parse/parseDayOfWeekFromDate.js +1 -1
- package/dist/plain/parse/parseDayOfWeekFromDateTime.js +1 -1
- package/dist/plain/parse/parseHourFromDateTime.js +1 -1
- package/dist/plain/parse/parseHourFromTime.js +1 -1
- package/dist/plain/parse/parseMicrosecondFromDateTime.js +1 -1
- package/dist/plain/parse/parseMicrosecondFromTime.js +1 -1
- package/dist/plain/parse/parseMillisecondFromDateTime.js +1 -1
- package/dist/plain/parse/parseMillisecondFromTime.js +1 -1
- package/dist/plain/parse/parseMinuteFromDateTime.js +1 -1
- package/dist/plain/parse/parseMinuteFromTime.js +1 -1
- package/dist/plain/parse/parseMonthFromDate.js +1 -1
- package/dist/plain/parse/parseMonthFromDateTime.js +1 -1
- package/dist/plain/parse/parseNanosecondFromDateTime.js +1 -1
- package/dist/plain/parse/parseNanosecondFromTime.js +1 -1
- package/dist/plain/parse/parseSecondFromDateTime.js +1 -1
- package/dist/plain/parse/parseSecondFromTime.js +1 -1
- package/dist/plain/parse/{parseSql.d.ts → parseSqlDateTime.d.ts} +8 -8
- package/dist/plain/parse/{parseSql.js → parseSqlDateTime.js} +9 -9
- package/dist/plain/parse/parseTimeWithPattern.d.ts +6 -4
- package/dist/plain/parse/parseTimeWithPattern.js +8 -5
- package/dist/plain/parse/parseUnitFromDate.d.ts +4 -1
- package/dist/plain/parse/parseUnitFromDate.js +6 -2
- package/dist/plain/parse/parseUnitFromDateTime.d.ts +4 -1
- package/dist/plain/parse/parseUnitFromDateTime.js +6 -2
- package/dist/plain/parse/parseUnitFromTime.d.ts +1 -1
- package/dist/plain/parse/parseUnitFromTime.js +1 -1
- package/dist/plain/parse/parseWeekFromDateTime.js +1 -1
- package/dist/plain/parse/parseYearFromDate.d.ts +5 -2
- package/dist/plain/parse/parseYearFromDate.js +8 -4
- package/dist/plain/parse/parseYearFromDateTime.d.ts +4 -2
- package/dist/plain/parse/parseYearFromDateTime.js +7 -4
- package/dist/plain/validate/{isLeapSecond.d.ts → hasSecond60.d.ts} +16 -14
- package/dist/plain/validate/{isLeapSecond.js → hasSecond60.js} +16 -14
- package/dist/plain/validate/index.d.ts +2 -1
- package/dist/plain/validate/index.js +2 -1
- package/dist/plain/validate/isLeapYear.js +1 -1
- package/dist/plain/validate/isValidDate.js +2 -17
- package/dist/plain/validate/isValidDateRange.js +1 -1
- package/dist/plain/validate/isValidDateTime.d.ts +1 -1
- package/dist/plain/validate/isValidDateTime.js +4 -4
- package/dist/plain/validate/isValidDateTimeRange.js +1 -1
- package/dist/plain/validate/isValidIsoDateLike.js +3 -3
- package/dist/plain/validate/isValidSqlDateTime.d.ts +33 -0
- package/dist/plain/validate/isValidSqlDateTime.js +36 -0
- package/dist/plain/validate/isValidTime.js +2 -18
- package/dist/plain/validate/isValidTimeRange.js +1 -1
- package/dist/precision/convert/fromNanoseconds.d.ts +11 -5
- package/dist/precision/convert/fromNanoseconds.js +12 -6
- package/dist/precision/convert/toNanoseconds.d.ts +2 -2
- package/dist/precision/convert/toNanoseconds.js +2 -2
- package/dist/precision/index.d.ts +1 -1
- package/dist/precision/index.js +2 -2
- package/dist/precision/validate/isValidInstant.d.ts +1 -1
- package/dist/precision/validate/isValidInstant.js +1 -1
- package/dist/regex/calendar-zoned-date-time.d.ts +4 -4
- package/dist/regex/calendar-zoned-date-time.js +4 -4
- package/dist/regex/epcis.d.ts +60 -0
- package/dist/regex/epcis.js +60 -0
- package/dist/regex/http-date.d.ts +6 -4
- package/dist/regex/http-date.js +6 -4
- package/dist/regex/index.d.ts +2 -1
- package/dist/regex/index.js +3 -2
- package/dist/regex/leap-second.d.ts +1 -1
- package/dist/regex/leap-second.js +1 -1
- package/dist/regex/rfc-2822.d.ts +2 -0
- package/dist/regex/rfc-2822.js +2 -0
- package/dist/regex/rfc-3339.d.ts +3 -1
- package/dist/regex/rfc-3339.js +3 -1
- package/dist/regex/sql-date-time.d.ts +2 -1
- package/dist/regex/sql-date-time.js +2 -1
- package/dist/regex/time-zone-like.d.ts +5 -4
- package/dist/regex/time-zone-like.js +5 -4
- package/dist/regex/utc-offset.d.ts +2 -1
- package/dist/regex/utc-offset.js +2 -1
- package/dist/span/calculate/spanMs.d.ts +4 -3
- package/dist/span/calculate/spanMs.js +4 -3
- package/dist/span/calculate/spanNs.d.ts +4 -3
- package/dist/span/calculate/spanNs.js +4 -3
- package/dist/span/calculate/spanWallClock.d.ts +12 -12
- package/dist/span/calculate/spanWallClock.js +13 -13
- package/dist/span/index.d.ts +1 -1
- package/dist/span/index.js +2 -2
- package/dist/span/validate/isValidSpan.d.ts +3 -3
- package/dist/span/validate/isValidSpan.js +3 -3
- package/dist/timescale/calculate/index.d.ts +3 -0
- package/dist/timescale/calculate/index.js +3 -0
- package/dist/timescale/calculate/leapSecondsBetween.d.ts +26 -0
- package/dist/timescale/calculate/leapSecondsBetween.js +62 -0
- package/dist/timescale/calculate/nextLeapSecond.d.ts +18 -0
- package/dist/timescale/calculate/nextLeapSecond.js +33 -0
- package/dist/timescale/calculate/taiMinusUtc.d.ts +21 -0
- package/dist/timescale/calculate/taiMinusUtc.js +38 -0
- package/dist/timescale/convert/fromTAI.d.ts +22 -0
- package/dist/timescale/convert/fromTAI.js +35 -0
- package/dist/timescale/convert/index.d.ts +2 -0
- package/dist/timescale/convert/index.js +2 -0
- package/dist/timescale/convert/toTAI.d.ts +23 -0
- package/dist/timescale/convert/toTAI.js +39 -0
- package/dist/timescale/index.d.ts +4 -0
- package/dist/timescale/index.js +5 -0
- package/dist/timescale/validate/index.d.ts +1 -0
- package/dist/timescale/validate/index.js +1 -0
- package/dist/timescale/validate/isLeapSecond.d.ts +25 -0
- package/dist/timescale/validate/isLeapSecond.js +36 -0
- package/dist/transport/calculate/crossingTime.d.ts +8 -3
- package/dist/transport/calculate/crossingTime.js +9 -4
- package/dist/transport/calculate/cutoffAt.d.ts +10 -5
- package/dist/transport/calculate/cutoffAt.js +26 -133
- package/dist/transport/calculate/cutoffSchedule.d.ts +8 -3
- package/dist/transport/calculate/cutoffSchedule.js +54 -20
- package/dist/transport/calculate/dwellTime.d.ts +9 -4
- package/dist/transport/calculate/dwellTime.js +10 -5
- package/dist/transport/calculate/estimateDrift.d.ts +1 -1
- package/dist/transport/calculate/estimateDrift.js +1 -1
- package/dist/transport/calculate/nextDeparture.d.ts +2 -2
- package/dist/transport/calculate/nextDeparture.js +2 -2
- package/dist/transport/calculate/scheduleDelivery.d.ts +15 -7
- package/dist/transport/calculate/scheduleDelivery.js +9 -4
- package/dist/transport/calculate/transitTime.d.ts +11 -11
- package/dist/transport/calculate/transitTime.js +11 -11
- package/dist/transport/compare/classifyPunctuality.d.ts +1 -1
- package/dist/transport/compare/classifyPunctuality.js +1 -1
- package/dist/transport/compare/isPastCutoff.d.ts +1 -1
- package/dist/transport/compare/isPastCutoff.js +2 -2
- package/dist/transport/compare/scheduleDeviation.d.ts +1 -1
- package/dist/transport/compare/scheduleDeviation.js +1 -1
- package/dist/transport/compare/timeToCutoff.d.ts +1 -1
- package/dist/transport/compare/timeToCutoff.js +1 -1
- package/dist/transport/convert/etaAtZone.d.ts +8 -3
- package/dist/transport/convert/etaAtZone.js +8 -3
- package/dist/transport/index.d.ts +1 -1
- package/dist/transport/index.js +2 -2
- package/dist/types/business-calendar.d.ts +5 -4
- package/dist/types/date-duration-unit.d.ts +1 -1
- package/dist/types/date-time-duration-units.d.ts +1 -1
- package/dist/types/date-time-unit.d.ts +1 -1
- package/dist/types/date-unit.d.ts +1 -1
- package/dist/types/disambiguation.d.ts +1 -1
- package/dist/types/duration-relative-to.d.ts +1 -1
- package/dist/types/duration-string-options.d.ts +1 -1
- package/dist/types/duty.d.ts +777 -0
- package/dist/types/duty.js +0 -0
- package/dist/types/edi.d.ts +407 -0
- package/dist/types/edi.js +0 -0
- package/dist/types/epcis.d.ts +25 -0
- package/dist/types/epcis.js +0 -0
- package/dist/types/exact-duration-unit.d.ts +8 -0
- package/dist/types/exact-duration-unit.js +0 -0
- package/dist/types/fiscal-calendar.d.ts +40 -4
- package/dist/types/free-time-options.d.ts +4 -3
- package/dist/types/gnss.d.ts +51 -0
- package/dist/types/gnss.js +0 -0
- package/dist/types/index.d.ts +7 -0
- package/dist/types/index.js +7 -0
- package/dist/types/now-unit.d.ts +1 -1
- package/dist/types/offset.d.ts +1 -1
- package/dist/types/operating-schedule.d.ts +3 -2
- package/dist/types/overflow.d.ts +1 -1
- package/dist/types/rounding-options.d.ts +1 -1
- package/dist/types/stored-zoned-classification.d.ts +83 -0
- package/dist/types/stored-zoned-classification.js +0 -0
- package/dist/types/time-duration-unit.d.ts +1 -1
- package/dist/types/time-unit.d.ts +1 -1
- package/dist/types/two-digit-year.d.ts +23 -0
- package/dist/types/two-digit-year.js +0 -0
- package/dist/types/utc-now-unit.d.ts +1 -1
- package/dist/types/zone-bucket-unit.d.ts +1 -1
- package/dist/unix/calculate/addUnix.d.ts +11 -2
- package/dist/unix/calculate/addUnix.js +14 -11
- package/dist/unix/calculate/diffUnix.d.ts +11 -3
- package/dist/unix/calculate/diffUnix.js +11 -6
- package/dist/unix/calculate/diffUnixAsDuration.d.ts +11 -3
- package/dist/unix/calculate/diffUnixAsDuration.js +10 -5
- package/dist/unix/calculate/endOfQuarterForUnix.d.ts +10 -2
- package/dist/unix/calculate/endOfQuarterForUnix.js +6 -0
- package/dist/unix/calculate/endOfUnix.d.ts +13 -4
- package/dist/unix/calculate/endOfUnix.js +8 -1
- package/dist/unix/calculate/isBetweenUnix.d.ts +3 -2
- package/dist/unix/calculate/isBetweenUnix.js +4 -4
- package/dist/unix/calculate/roundUnix.d.ts +17 -7
- package/dist/unix/calculate/roundUnix.js +19 -10
- package/dist/unix/calculate/setUnix.d.ts +28 -8
- package/dist/unix/calculate/setUnix.js +35 -14
- package/dist/unix/calculate/startOfQuarterForUnix.d.ts +10 -2
- package/dist/unix/calculate/startOfQuarterForUnix.js +6 -0
- package/dist/unix/calculate/startOfUnix.d.ts +13 -4
- package/dist/unix/calculate/startOfUnix.js +8 -1
- package/dist/unix/calculate/subtractUnix.d.ts +10 -2
- package/dist/unix/calculate/subtractUnix.js +13 -11
- package/dist/unix/compare/areUnixEqualBy.d.ts +13 -4
- package/dist/unix/compare/areUnixEqualBy.js +8 -1
- package/dist/unix/convert/convertUnixToPlainDate.d.ts +5 -2
- package/dist/unix/convert/convertUnixToPlainDate.js +5 -4
- package/dist/unix/convert/convertUnixToPlainDateTime.d.ts +5 -2
- package/dist/unix/convert/convertUnixToPlainDateTime.js +5 -4
- package/dist/unix/convert/convertUnixToPlainTime.d.ts +6 -3
- package/dist/unix/convert/convertUnixToPlainTime.js +6 -5
- package/dist/unix/convert/convertUnixToZoned.d.ts +6 -2
- package/dist/unix/convert/convertUnixToZoned.js +6 -2
- package/dist/unix/format/formatCalendarUnix.d.ts +16 -11
- package/dist/unix/format/formatCalendarUnix.js +12 -7
- package/dist/unix/format/formatRelativeUnix.d.ts +17 -9
- package/dist/unix/format/formatRelativeUnix.js +19 -11
- package/dist/unix/format/formatUnix.d.ts +16 -11
- package/dist/unix/format/formatUnix.js +13 -9
- package/dist/unix/get/getUnixDay.d.ts +1 -3
- package/dist/unix/get/getUnixDay.js +6 -13
- package/dist/unix/get/getUnixHour.d.ts +1 -3
- package/dist/unix/get/getUnixHour.js +6 -13
- package/dist/unix/get/getUnixMicrosecond.d.ts +1 -3
- package/dist/unix/get/getUnixMicrosecond.js +5 -12
- package/dist/unix/get/getUnixMillisecond.d.ts +1 -3
- package/dist/unix/get/getUnixMillisecond.js +6 -13
- package/dist/unix/get/getUnixMinute.d.ts +1 -3
- package/dist/unix/get/getUnixMinute.js +6 -13
- package/dist/unix/get/getUnixMonth.d.ts +1 -3
- package/dist/unix/get/getUnixMonth.js +6 -13
- package/dist/unix/get/getUnixNanosecond.d.ts +1 -3
- package/dist/unix/get/getUnixNanosecond.js +5 -12
- package/dist/unix/get/getUnixNow.js +1 -1
- package/dist/unix/get/getUnixNowUnit.d.ts +3 -1
- package/dist/unix/get/getUnixNowUnit.js +3 -1
- package/dist/unix/get/getUnixSecond.d.ts +1 -3
- package/dist/unix/get/getUnixSecond.js +6 -13
- package/dist/unix/get/getUnixYear.d.ts +3 -3
- package/dist/unix/get/getUnixYear.js +6 -13
- package/dist/unix/index.d.ts +1 -1
- package/dist/unix/index.js +2 -2
- package/dist/unix/interval/intervalCountUnix.d.ts +11 -2
- package/dist/unix/interval/intervalCountUnix.js +7 -0
- package/dist/unix/interval/intervalFromDurationUnix.d.ts +10 -2
- package/dist/unix/interval/intervalFromDurationUnix.js +13 -8
- package/dist/unix/interval/intervalLengthUnix.d.ts +12 -4
- package/dist/unix/interval/intervalLengthUnix.js +8 -2
- package/dist/unix/interval/intervalOverlappingDaysUnix.d.ts +10 -2
- package/dist/unix/interval/intervalOverlappingDaysUnix.js +10 -5
- package/dist/unix/interval/splitIntervalByUnitUnix.d.ts +13 -4
- package/dist/unix/interval/splitIntervalByUnitUnix.js +16 -9
- package/dist/unix/parse/parseDateFromUnix.d.ts +4 -2
- package/dist/unix/parse/parseDateFromUnix.js +3 -3
- package/dist/unix/parse/parseDayFromUnix.d.ts +4 -2
- package/dist/unix/parse/parseDayOfWeekFromUnix.d.ts +4 -2
- package/dist/unix/parse/parseDayOfWeekFromUnix.js +2 -2
- package/dist/unix/parse/parseHourFromUnix.d.ts +4 -2
- package/dist/unix/parse/parseMicrosecondFromUnix.d.ts +4 -2
- package/dist/unix/parse/parseMillisecondFromUnix.d.ts +4 -2
- package/dist/unix/parse/parseMinuteFromUnix.d.ts +4 -2
- package/dist/unix/parse/parseMonthFromUnix.d.ts +4 -2
- package/dist/unix/parse/parseNanosecondFromUnix.d.ts +4 -2
- package/dist/unix/parse/parseSecondFromUnix.d.ts +4 -2
- package/dist/unix/parse/parseTimeFromUnix.d.ts +5 -2
- package/dist/unix/parse/parseTimeFromUnix.js +4 -3
- package/dist/unix/parse/parseUnitFromUnix.d.ts +10 -4
- package/dist/unix/parse/parseUnitFromUnix.js +21 -14
- package/dist/unix/parse/parseWeekFromUnix.d.ts +3 -2
- package/dist/unix/parse/parseWeekFromUnix.js +4 -4
- package/dist/unix/parse/parseYearFromUnix.d.ts +8 -3
- package/dist/unix/parse/parseYearFromUnix.js +4 -1
- package/dist/unix/validate/isValidUnixUnit.d.ts +1 -1
- package/dist/utc/calculate/addUtc.js +5 -8
- package/dist/utc/calculate/diffUtc.d.ts +1 -1
- package/dist/utc/calculate/diffUtc.js +1 -1
- package/dist/utc/calculate/diffUtcAsDuration.d.ts +1 -1
- package/dist/utc/calculate/diffUtcAsDuration.js +1 -1
- package/dist/utc/calculate/endOfQuarterForUtc.js +1 -1
- package/dist/utc/calculate/endOfUtc.d.ts +1 -1
- package/dist/utc/calculate/isBetweenUtc.js +1 -1
- package/dist/utc/calculate/maxUtc.js +1 -1
- package/dist/utc/calculate/minUtc.js +1 -1
- package/dist/utc/calculate/roundUtc.d.ts +1 -1
- package/dist/utc/calculate/roundUtc.js +1 -1
- package/dist/utc/calculate/setUtc.d.ts +17 -4
- package/dist/utc/calculate/setUtc.js +23 -9
- package/dist/utc/calculate/sortUtc.js +1 -1
- package/dist/utc/calculate/startOfQuarterForUtc.js +1 -1
- package/dist/utc/calculate/startOfUtc.d.ts +1 -1
- package/dist/utc/calculate/subtractUtc.js +5 -8
- package/dist/utc/compare/areUtcEqual.js +1 -1
- package/dist/utc/compare/areUtcEqualBy.d.ts +2 -2
- package/dist/utc/compare/areUtcEqualBy.js +2 -2
- package/dist/utc/compare/isAfterUtc.js +1 -1
- package/dist/utc/compare/isBeforeUtc.js +1 -1
- package/dist/utc/convert/convertUtcToPlainDate.d.ts +9 -3
- package/dist/utc/convert/convertUtcToPlainDate.js +12 -9
- package/dist/utc/convert/convertUtcToPlainDateTime.d.ts +10 -3
- package/dist/utc/convert/convertUtcToPlainDateTime.js +14 -15
- package/dist/utc/convert/convertUtcToPlainTime.d.ts +6 -3
- package/dist/utc/convert/convertUtcToPlainTime.js +9 -8
- package/dist/utc/convert/convertUtcToUnix.js +1 -1
- package/dist/utc/convert/convertUtcToZoned.d.ts +6 -2
- package/dist/utc/convert/convertUtcToZoned.js +7 -3
- package/dist/utc/format/formatCalendarUtc.d.ts +12 -7
- package/dist/utc/format/formatCalendarUtc.js +9 -4
- package/dist/utc/format/{formatHttp.d.ts → formatHttpDate.d.ts} +7 -7
- package/dist/utc/format/{formatHttp.js → formatHttpDate.js} +8 -8
- package/dist/utc/format/formatRelativeUtc.d.ts +15 -7
- package/dist/utc/format/formatRelativeUtc.js +17 -9
- package/dist/utc/format/formatUtc.d.ts +15 -10
- package/dist/utc/format/formatUtc.js +12 -8
- package/dist/utc/format/index.d.ts +1 -1
- package/dist/utc/format/index.js +1 -1
- package/dist/utc/get/getUtcDay.d.ts +1 -3
- package/dist/utc/get/getUtcDay.js +6 -13
- package/dist/utc/get/getUtcHour.d.ts +1 -3
- package/dist/utc/get/getUtcHour.js +6 -13
- package/dist/utc/get/getUtcMicrosecond.d.ts +1 -3
- package/dist/utc/get/getUtcMicrosecond.js +5 -12
- package/dist/utc/get/getUtcMillisecond.d.ts +1 -3
- package/dist/utc/get/getUtcMillisecond.js +6 -13
- package/dist/utc/get/getUtcMinute.d.ts +1 -3
- package/dist/utc/get/getUtcMinute.js +6 -13
- package/dist/utc/get/getUtcMonth.d.ts +1 -3
- package/dist/utc/get/getUtcMonth.js +6 -13
- package/dist/utc/get/getUtcNanosecond.d.ts +1 -3
- package/dist/utc/get/getUtcNanosecond.js +5 -12
- package/dist/utc/get/getUtcNow.d.ts +1 -3
- package/dist/utc/get/getUtcNow.js +3 -10
- package/dist/utc/get/getUtcNowUnit.d.ts +2 -0
- package/dist/utc/get/getUtcNowUnit.js +3 -1
- package/dist/utc/get/getUtcSecond.d.ts +1 -3
- package/dist/utc/get/getUtcSecond.js +6 -13
- package/dist/utc/get/getUtcYear.d.ts +3 -3
- package/dist/utc/get/getUtcYear.js +6 -13
- package/dist/utc/index.d.ts +1 -1
- package/dist/utc/index.js +2 -2
- package/dist/utc/interval/intervalAbutsUtc.js +1 -1
- package/dist/utc/interval/intervalContainsUtc.js +1 -1
- package/dist/utc/interval/intervalCountUtc.js +1 -1
- package/dist/utc/interval/intervalDivideEquallyUtc.js +1 -1
- package/dist/utc/interval/intervalEngulfsUtc.js +1 -1
- package/dist/utc/interval/intervalFromDurationUtc.js +1 -1
- package/dist/utc/interval/intervalLengthUtc.js +1 -1
- package/dist/utc/interval/intervalOverlappingDaysUtc.js +1 -1
- package/dist/utc/interval/intervalSplitAtUtc.js +1 -1
- package/dist/utc/interval/intervalXorAllUtc.js +3 -3
- package/dist/utc/interval/intervalXorUtc.js +1 -1
- package/dist/utc/interval/mergeIntervalsUtc.js +2 -2
- package/dist/utc/interval/splitIntervalByUnitUtc.d.ts +2 -1
- package/dist/utc/interval/splitIntervalByUnitUtc.js +3 -2
- package/dist/utc/interval/validate/isValidUtcInterval.js +1 -1
- package/dist/utc/parse/index.d.ts +1 -1
- package/dist/utc/parse/index.js +1 -1
- package/dist/utc/parse/parseDateFromUtc.d.ts +5 -3
- package/dist/utc/parse/parseDateFromUtc.js +3 -3
- package/dist/utc/parse/parseDayFromUtc.d.ts +5 -3
- package/dist/utc/parse/parseDayFromUtc.js +3 -3
- package/dist/utc/parse/parseDayOfWeekFromUtc.d.ts +5 -3
- package/dist/utc/parse/parseDayOfWeekFromUtc.js +6 -6
- package/dist/utc/parse/parseHourFromUtc.d.ts +5 -3
- package/dist/utc/parse/parseHourFromUtc.js +3 -3
- package/dist/utc/parse/{parseHttp.d.ts → parseHttpDate.d.ts} +12 -12
- package/dist/utc/parse/{parseHttp.js → parseHttpDate.js} +13 -13
- package/dist/utc/parse/parseMicrosecondFromUtc.d.ts +5 -3
- package/dist/utc/parse/parseMicrosecondFromUtc.js +3 -3
- package/dist/utc/parse/parseMillisecondFromUtc.d.ts +5 -3
- package/dist/utc/parse/parseMillisecondFromUtc.js +3 -3
- package/dist/utc/parse/parseMinuteFromUtc.d.ts +4 -2
- package/dist/utc/parse/parseMinuteFromUtc.js +2 -2
- package/dist/utc/parse/parseMonthFromUtc.d.ts +5 -3
- package/dist/utc/parse/parseMonthFromUtc.js +3 -3
- package/dist/utc/parse/parseNanosecondFromUtc.d.ts +5 -3
- package/dist/utc/parse/parseNanosecondFromUtc.js +3 -3
- package/dist/utc/parse/parseSecondFromUtc.d.ts +5 -3
- package/dist/utc/parse/parseSecondFromUtc.js +3 -3
- package/dist/utc/parse/parseTimeFromUtc.d.ts +6 -3
- package/dist/utc/parse/parseTimeFromUtc.js +7 -6
- package/dist/utc/parse/parseUnitFromUtc.d.ts +12 -5
- package/dist/utc/parse/parseUnitFromUtc.js +13 -7
- package/dist/utc/parse/parseWeekFromUtc.d.ts +5 -3
- package/dist/utc/parse/parseWeekFromUtc.js +6 -6
- package/dist/utc/parse/parseYearFromUtc.d.ts +9 -5
- package/dist/utc/parse/parseYearFromUtc.js +9 -6
- package/dist/utc/validate/index.d.ts +2 -0
- package/dist/utc/validate/index.js +2 -0
- package/dist/utc/validate/isValidHttpDate.d.ts +35 -0
- package/dist/utc/validate/isValidHttpDate.js +38 -0
- package/dist/utc/validate/isValidUtc.d.ts +4 -0
- package/dist/utc/validate/isValidUtc.js +7 -3
- package/dist/utc/validate/isValidUtcRange.js +1 -1
- package/dist/utc/validate/isValidUtcTimestamp.d.ts +43 -0
- package/dist/utc/validate/isValidUtcTimestamp.js +48 -0
- package/dist/workforce/calculate/dutyDayFor.d.ts +38 -0
- package/dist/workforce/calculate/dutyDayFor.js +71 -0
- package/dist/workforce/calculate/dutyTotals.d.ts +24 -0
- package/dist/workforce/calculate/dutyTotals.js +41 -0
- package/dist/workforce/calculate/dutyViolations.d.ts +74 -0
- package/dist/workforce/calculate/dutyViolations.js +65 -0
- package/dist/workforce/calculate/evaluateDutyLog.d.ts +77 -0
- package/dist/workforce/calculate/evaluateDutyLog.js +75 -0
- package/dist/workforce/calculate/index.d.ts +7 -0
- package/dist/workforce/calculate/index.js +7 -0
- package/dist/workforce/calculate/longestRun.d.ts +28 -0
- package/dist/workforce/calculate/longestRun.js +54 -0
- package/dist/workforce/calculate/qualifyingRestPairs.d.ts +37 -0
- package/dist/workforce/calculate/qualifyingRestPairs.js +58 -0
- package/dist/workforce/calculate/qualifyingRests.d.ts +27 -0
- package/dist/workforce/calculate/qualifyingRests.js +49 -0
- package/dist/workforce/index.d.ts +3 -0
- package/dist/workforce/index.js +4 -0
- package/dist/workforce/validate/index.d.ts +1 -0
- package/dist/workforce/validate/index.js +1 -0
- package/dist/workforce/validate/isValidDutyLog.d.ts +24 -0
- package/dist/workforce/validate/isValidDutyLog.js +34 -0
- package/dist/zoned/calculate/addZoned.d.ts +15 -15
- package/dist/zoned/calculate/addZoned.js +19 -22
- package/dist/zoned/calculate/addZonedBusinessDays.d.ts +5 -4
- package/dist/zoned/calculate/addZonedBusinessDays.js +5 -4
- package/dist/zoned/calculate/clampZoned.js +1 -1
- package/dist/zoned/calculate/diffZoned.d.ts +8 -8
- package/dist/zoned/calculate/diffZoned.js +7 -7
- package/dist/zoned/calculate/diffZonedAsDuration.d.ts +5 -5
- package/dist/zoned/calculate/diffZonedAsDuration.js +4 -4
- package/dist/zoned/calculate/endOfZoned.d.ts +3 -3
- package/dist/zoned/calculate/endOfZoned.js +2 -2
- package/dist/zoned/calculate/getHoursInZonedDay.d.ts +2 -2
- package/dist/zoned/calculate/getHoursInZonedDay.js +2 -2
- package/dist/zoned/calculate/getLocaleZonedDayOfWeek.d.ts +6 -5
- package/dist/zoned/calculate/getLocaleZonedDayOfWeek.js +6 -5
- package/dist/zoned/calculate/getLocaleZonedEndOfWeek.d.ts +5 -5
- package/dist/zoned/calculate/getLocaleZonedEndOfWeek.js +5 -5
- package/dist/zoned/calculate/getLocaleZonedStartOfWeek.d.ts +6 -6
- package/dist/zoned/calculate/getLocaleZonedStartOfWeek.js +6 -6
- package/dist/zoned/calculate/maxZoned.d.ts +2 -2
- package/dist/zoned/calculate/maxZoned.js +3 -3
- package/dist/zoned/calculate/minZoned.d.ts +2 -2
- package/dist/zoned/calculate/minZoned.js +3 -3
- package/dist/zoned/calculate/roundZoned.d.ts +11 -9
- package/dist/zoned/calculate/roundZoned.js +11 -9
- package/dist/zoned/calculate/setZoned.d.ts +26 -12
- package/dist/zoned/calculate/setZoned.js +33 -16
- package/dist/zoned/calculate/sortZoned.d.ts +3 -3
- package/dist/zoned/calculate/sortZoned.js +4 -4
- package/dist/zoned/calculate/startOfZoned.d.ts +3 -3
- package/dist/zoned/calculate/startOfZoned.js +2 -2
- package/dist/zoned/calculate/subtractZoned.d.ts +14 -14
- package/dist/zoned/calculate/subtractZoned.js +18 -21
- package/dist/zoned/calculate/subtractZonedBusinessDays.d.ts +5 -4
- package/dist/zoned/calculate/subtractZonedBusinessDays.js +5 -4
- package/dist/zoned/chop/chopZonedDate.d.ts +1 -1
- package/dist/zoned/chop/chopZonedDate.js +1 -1
- package/dist/zoned/chop/chopZonedMilliseconds.d.ts +1 -1
- package/dist/zoned/chop/chopZonedMilliseconds.js +1 -1
- package/dist/zoned/chop/chopZonedSeconds.d.ts +1 -1
- package/dist/zoned/chop/chopZonedSeconds.js +1 -1
- package/dist/zoned/chop/chopZonedTime.d.ts +1 -1
- package/dist/zoned/chop/chopZonedTime.js +1 -1
- package/dist/zoned/chop/chopZonedTimezone.d.ts +1 -1
- package/dist/zoned/chop/chopZonedTimezone.js +1 -1
- package/dist/zoned/classify/classifyStoredZoned.d.ts +46 -0
- package/dist/zoned/classify/classifyStoredZoned.js +177 -0
- package/dist/zoned/classify/index.d.ts +1 -0
- package/dist/zoned/classify/index.js +1 -0
- package/dist/zoned/compare/areZonedEqual.js +1 -1
- package/dist/zoned/compare/areZonedEqualBy.d.ts +8 -10
- package/dist/zoned/compare/areZonedEqualBy.js +8 -10
- package/dist/zoned/compare/isAfterZoned.js +1 -1
- package/dist/zoned/compare/isBeforeZoned.d.ts +2 -2
- package/dist/zoned/compare/isBeforeZoned.js +3 -3
- package/dist/zoned/compare/isBetweenZoned.js +1 -1
- package/dist/zoned/compare/isInDaylightSaving.d.ts +2 -2
- package/dist/zoned/compare/isInDaylightSaving.js +2 -2
- package/dist/zoned/compare/isZonedBusinessDay.d.ts +7 -6
- package/dist/zoned/compare/isZonedBusinessDay.js +7 -6
- package/dist/zoned/compare/isZonedFuture.js +1 -1
- package/dist/zoned/compare/isZonedPast.js +1 -1
- package/dist/zoned/compare/isZonedRelativeDay.d.ts +2 -2
- package/dist/zoned/compare/isZonedRelativeDay.js +3 -3
- package/dist/zoned/compare/isZonedThisUnit.d.ts +7 -7
- package/dist/zoned/compare/isZonedThisUnit.js +7 -7
- package/dist/zoned/compare/isZonedWeekend.d.ts +5 -5
- package/dist/zoned/compare/isZonedWeekend.js +5 -5
- package/dist/zoned/convert/convertPlainDateTimeToZoned.d.ts +10 -7
- package/dist/zoned/convert/convertPlainDateTimeToZoned.js +10 -7
- package/dist/zoned/convert/convertZonedToCalendar.d.ts +5 -5
- package/dist/zoned/convert/convertZonedToCalendar.js +5 -5
- package/dist/zoned/convert/convertZonedToPlainDateTime.d.ts +3 -3
- package/dist/zoned/convert/convertZonedToPlainDateTime.js +3 -3
- package/dist/zoned/convert/convertZonedToZoned.d.ts +7 -3
- package/dist/zoned/convert/convertZonedToZoned.js +7 -3
- package/dist/zoned/format/formatCalendarZoned.d.ts +7 -6
- package/dist/zoned/format/formatCalendarZoned.js +7 -6
- package/dist/zoned/format/formatRelativeZoned.d.ts +3 -3
- package/dist/zoned/format/formatRelativeZoned.js +6 -5
- package/dist/zoned/format/formatRfc2822.d.ts +3 -3
- package/dist/zoned/format/formatRfc2822.js +3 -3
- package/dist/zoned/format/formatRfc3339.d.ts +2 -2
- package/dist/zoned/format/formatRfc3339.js +2 -2
- package/dist/zoned/format/formatTimeZoneName.d.ts +22 -18
- package/dist/zoned/format/formatTimeZoneName.js +18 -13
- package/dist/zoned/format/formatZonedDateTime.d.ts +10 -10
- package/dist/zoned/format/formatZonedDateTime.js +12 -11
- package/dist/zoned/format/formatZonedRange.d.ts +7 -7
- package/dist/zoned/format/formatZonedRange.js +9 -8
- package/dist/zoned/format/formatZonedToParts.d.ts +11 -11
- package/dist/zoned/format/formatZonedToParts.js +13 -12
- package/dist/zoned/get/getDstTransitions.d.ts +14 -12
- package/dist/zoned/get/getDstTransitions.js +15 -10
- package/dist/zoned/get/getSystemTimeZone.d.ts +5 -3
- package/dist/zoned/get/getSystemTimeZone.js +7 -4
- package/dist/zoned/get/getTimeZoneOffset.d.ts +15 -7
- package/dist/zoned/get/getTimeZoneOffset.js +23 -10
- package/dist/zoned/get/getTimeZones.d.ts +1 -1
- package/dist/zoned/get/getTimeZones.js +1 -1
- package/dist/zoned/get/getZonedDay.d.ts +3 -2
- package/dist/zoned/get/getZonedDay.js +7 -8
- package/dist/zoned/get/getZonedDayOfWeek.d.ts +3 -2
- package/dist/zoned/get/getZonedDayOfWeek.js +7 -6
- package/dist/zoned/get/getZonedHour.d.ts +3 -2
- package/dist/zoned/get/getZonedHour.js +7 -8
- package/dist/zoned/get/getZonedMicrosecond.d.ts +3 -2
- package/dist/zoned/get/getZonedMicrosecond.js +7 -6
- package/dist/zoned/get/getZonedMillisecond.d.ts +3 -2
- package/dist/zoned/get/getZonedMillisecond.js +7 -8
- package/dist/zoned/get/getZonedMinute.d.ts +3 -2
- package/dist/zoned/get/getZonedMinute.js +7 -8
- package/dist/zoned/get/getZonedMonth.d.ts +3 -2
- package/dist/zoned/get/getZonedMonth.js +7 -8
- package/dist/zoned/get/getZonedNanosecond.d.ts +3 -2
- package/dist/zoned/get/getZonedNanosecond.js +7 -6
- package/dist/zoned/get/getZonedNow.d.ts +9 -5
- package/dist/zoned/get/getZonedNow.js +9 -5
- package/dist/zoned/get/getZonedNowUnit.d.ts +7 -4
- package/dist/zoned/get/getZonedNowUnit.js +11 -8
- package/dist/zoned/get/getZonedSecond.d.ts +3 -2
- package/dist/zoned/get/getZonedSecond.js +7 -8
- package/dist/zoned/get/getZonedToday.d.ts +3 -2
- package/dist/zoned/get/getZonedToday.js +7 -6
- package/dist/zoned/get/getZonedWeekOfYear.d.ts +3 -2
- package/dist/zoned/get/getZonedWeekOfYear.js +7 -6
- package/dist/zoned/get/getZonedYear.d.ts +5 -2
- package/dist/zoned/get/getZonedYear.js +10 -8
- package/dist/zoned/index.d.ts +2 -1
- package/dist/zoned/index.js +3 -2
- package/dist/zoned/interval/intervalAbutsZoned.d.ts +2 -2
- package/dist/zoned/interval/intervalAbutsZoned.js +3 -3
- package/dist/zoned/interval/intervalContainsZoned.d.ts +1 -1
- package/dist/zoned/interval/intervalContainsZoned.js +2 -2
- package/dist/zoned/interval/intervalCountZoned.d.ts +4 -4
- package/dist/zoned/interval/intervalCountZoned.js +5 -5
- package/dist/zoned/interval/intervalDifferenceZoned.js +1 -1
- package/dist/zoned/interval/intervalDivideEquallyZoned.d.ts +1 -1
- package/dist/zoned/interval/intervalDivideEquallyZoned.js +2 -2
- package/dist/zoned/interval/intervalEngulfsZoned.d.ts +1 -1
- package/dist/zoned/interval/intervalEngulfsZoned.js +2 -2
- package/dist/zoned/interval/intervalFromDurationZoned.d.ts +6 -6
- package/dist/zoned/interval/intervalFromDurationZoned.js +7 -7
- package/dist/zoned/interval/intervalIntersectionZoned.js +1 -1
- package/dist/zoned/interval/intervalLengthZoned.d.ts +5 -5
- package/dist/zoned/interval/intervalLengthZoned.js +5 -5
- package/dist/zoned/interval/intervalOverlappingDaysZoned.d.ts +2 -2
- package/dist/zoned/interval/intervalOverlappingDaysZoned.js +3 -3
- package/dist/zoned/interval/intervalSplitAtZoned.js +14 -16
- package/dist/zoned/interval/intervalUnionZoned.js +1 -1
- package/dist/zoned/interval/intervalXorAllZoned.js +3 -3
- package/dist/zoned/interval/intervalXorZoned.js +1 -1
- package/dist/zoned/interval/intervalsOverlapZoned.d.ts +2 -2
- package/dist/zoned/interval/intervalsOverlapZoned.js +3 -3
- package/dist/zoned/interval/mergeIntervalsZoned.js +3 -3
- package/dist/zoned/interval/splitIntervalByUnitZoned.d.ts +2 -1
- package/dist/zoned/interval/splitIntervalByUnitZoned.js +3 -2
- package/dist/zoned/interval/validate/isValidCalendarZonedInterval.d.ts +2 -2
- package/dist/zoned/interval/validate/isValidCalendarZonedInterval.js +3 -3
- package/dist/zoned/interval/validate/isValidZonedInterval.d.ts +1 -1
- package/dist/zoned/interval/validate/isValidZonedInterval.js +2 -2
- package/dist/zoned/map/mapZonedDatesInRange.js +1 -1
- package/dist/zoned/map/mapZonedHoursInDay.d.ts +1 -1
- package/dist/zoned/map/mapZonedHoursInDay.js +2 -2
- package/dist/zoned/parse/getZonedOffset.d.ts +1 -1
- package/dist/zoned/parse/getZonedOffset.js +1 -1
- package/dist/zoned/parse/getZonedOffsetAs.d.ts +6 -6
- package/dist/zoned/parse/getZonedOffsetAs.js +3 -3
- package/dist/zoned/parse/parseDateTimeFromZoned.js +2 -2
- package/dist/zoned/parse/parseRfc2822.js +1 -1
- package/dist/zoned/parse/parseRfc3339.js +1 -1
- package/dist/zoned/parse/parseUnitFromZoned.d.ts +5 -2
- package/dist/zoned/parse/parseUnitFromZoned.js +5 -1
- package/dist/zoned/parse/parseYearFromZoned.d.ts +4 -2
- package/dist/zoned/parse/parseYearFromZoned.js +6 -3
- package/dist/zoned/validate/hasDaylightSaving.d.ts +6 -4
- package/dist/zoned/validate/hasDaylightSaving.js +16 -10
- package/dist/zoned/validate/index.d.ts +2 -0
- package/dist/zoned/validate/index.js +2 -0
- package/dist/zoned/validate/isValidCalendarZonedDateTime.d.ts +8 -8
- package/dist/zoned/validate/isValidCalendarZonedDateTime.js +8 -8
- package/dist/zoned/validate/isValidRfc2822DateTime.d.ts +32 -0
- package/dist/zoned/validate/isValidRfc2822DateTime.js +35 -0
- package/dist/zoned/validate/isValidRfc3339DateTime.d.ts +31 -0
- package/dist/zoned/validate/isValidRfc3339DateTime.js +34 -0
- package/dist/zoned/validate/isValidTimeZone.d.ts +6 -2
- package/dist/zoned/validate/isValidTimeZone.js +8 -19
- package/dist/zoned/validate/isValidZonedDateTime.d.ts +7 -7
- package/dist/zoned/validate/isValidZonedDateTime.js +9 -9
- package/dist/zoned/validate/isValidZonedRange.d.ts +1 -1
- package/dist/zoned/validate/isValidZonedRange.js +5 -5
- package/package.json +103 -4
- package/skills/gmt-arithmetic/SKILL.md +63 -17
- package/skills/gmt-basics/SKILL.md +83 -21
- package/skills/gmt-gnss/SKILL.md +92 -0
- package/skills/gmt-integration/SKILL.md +58 -10
- package/skills/gmt-intermodal/SKILL.md +189 -0
- package/skills/gmt-timezone/SKILL.md +51 -169
- package/skills/gmt-transport/SKILL.md +133 -0
- package/skills/gmt-workforce/SKILL.md +84 -0
- package/dist/internal/unixZonedDateTime.d.ts +0 -22
- package/dist/internal/unixZonedDateTime.js +0 -32
- package/dist/internal/utcZonedDateTime.d.ts +0 -19
- package/dist/internal/utcZonedDateTime.js +0 -31
|
@@ -0,0 +1,1755 @@
|
|
|
1
|
+
import { Temporal } from "./temporal.js";
|
|
2
|
+
import { parseDutyLog } from "./dutyLog.js";
|
|
3
|
+
import { calendarScale, datePlusDays, localDateOf, operatorDayScale, periodAfter, periodsEndingAt, resolveWallClock, WallClockRejected, } from "./dutyPeriods.js";
|
|
4
|
+
import { MAX_PERIOD_COUNT, parseDutyRules, usesOperatorDays, } from "./dutyRules.js";
|
|
5
|
+
import { countEvents, countInRange, latestPairFrom, createRunStore, endingAtOrBefore, entryHolding, firstEndingAfter, firstEntryIn, firstStartingAtOrAfter, firstWhere, interruptionResetAt, lastAtLeastUntil, lastEntryBefore, latestAtLeast, logStartBefore, runEndingAt, runIndex, runsMatching, runsUntil, timeInBefore, viewRun, } from "./dutyRunIndex.js";
|
|
6
|
+
import { MIN_EPOCH_NANOSECONDS } from "./epochNanoseconds.js";
|
|
7
|
+
import { isObject } from "./isObject.js";
|
|
8
|
+
import { parseScheduleDisambiguation } from "./operatingSchedule.js";
|
|
9
|
+
import { formatHourDuration } from "./hourDurationString.js";
|
|
10
|
+
import { zoneFrame } from "./zoneFrame.js";
|
|
11
|
+
import { parseDayStartTime } from "./dutyPeriods.js";
|
|
12
|
+
/** A window a call cannot place in Temporal's range. Caught by the public function. */
|
|
13
|
+
export class Unrepresentable extends RangeError {
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* A count as a number, exactly. Past `Number.MAX_SAFE_INTEGER` a number would round it, so the
|
|
17
|
+
* call is refused instead.
|
|
18
|
+
*/
|
|
19
|
+
function exactCount(value) {
|
|
20
|
+
if (value > BigInt(Number.MAX_SAFE_INTEGER)) {
|
|
21
|
+
throw new Unrepresentable("a count past the safe integers");
|
|
22
|
+
}
|
|
23
|
+
return Number(value);
|
|
24
|
+
}
|
|
25
|
+
const duration = (nanoseconds) => ({
|
|
26
|
+
duration: nanoseconds > 0n ? nanoseconds : 0n,
|
|
27
|
+
});
|
|
28
|
+
const tally = (value) => ({ count: value > 0 ? value : 0 });
|
|
29
|
+
const max = (a, b) => (a > b ? a : b);
|
|
30
|
+
const min = (a, b) => (a < b ? a : b);
|
|
31
|
+
const length = (run) => run.end - run.start;
|
|
32
|
+
/**
|
|
33
|
+
* Read the log, rules and options `evaluateDutyLog` and `dutyViolations` take, all-or-nothing.
|
|
34
|
+
*
|
|
35
|
+
* - `options` must be an object with a valid `timeZone`; `dayStartTime` is optional, but a rule
|
|
36
|
+
* that counts operator days needs it; `disambiguation` is `"compatible"` when absent. Each
|
|
37
|
+
* member is read once.
|
|
38
|
+
*
|
|
39
|
+
* @param log candidate duty log
|
|
40
|
+
* @param rules candidate rules
|
|
41
|
+
* @param options candidate `{ timeZone, dayStartTime?, disambiguation? }`
|
|
42
|
+
* @returns the context and resolved rules, or null on invalid input
|
|
43
|
+
*/
|
|
44
|
+
export function prepareDutyCall(log, rules, options) {
|
|
45
|
+
const entries = parseDutyLog(log);
|
|
46
|
+
const resolved = parseDutyRules(rules);
|
|
47
|
+
if (entries === null || resolved === null || !isObject(options)) {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
const { timeZone, dayStartTime } = options;
|
|
51
|
+
const disambiguation = parseScheduleDisambiguation(options);
|
|
52
|
+
const frame = zoneFrame(timeZone);
|
|
53
|
+
const time = dayStartTime === undefined ? null : parseDayStartTime(dayStartTime);
|
|
54
|
+
if (frame === null ||
|
|
55
|
+
disambiguation === null ||
|
|
56
|
+
(dayStartTime !== undefined && time === null) ||
|
|
57
|
+
(time === null && resolved.some(usesOperatorDays))) {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
context: {
|
|
62
|
+
entries,
|
|
63
|
+
frame,
|
|
64
|
+
dayStartTime: time,
|
|
65
|
+
disambiguation,
|
|
66
|
+
scales: new Map(),
|
|
67
|
+
wallClocks: new Map(),
|
|
68
|
+
windowInstances: new Map(),
|
|
69
|
+
store: createRunStore(entries),
|
|
70
|
+
},
|
|
71
|
+
rules: resolved,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
function scaleFor(context, unit) {
|
|
75
|
+
const known = context.scales.get(unit);
|
|
76
|
+
if (known !== undefined) {
|
|
77
|
+
return known;
|
|
78
|
+
}
|
|
79
|
+
let scale;
|
|
80
|
+
if (unit === "operatorDay") {
|
|
81
|
+
if (context.dayStartTime === null) {
|
|
82
|
+
throw new Unrepresentable("operator days need dayStartTime");
|
|
83
|
+
}
|
|
84
|
+
scale = operatorDayScale(context.frame, context.dayStartTime, context.disambiguation);
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
scale = calendarScale(context.frame, unit);
|
|
88
|
+
}
|
|
89
|
+
context.scales.set(unit, scale);
|
|
90
|
+
return scale;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Read a status list a helper takes: an array of strings, `[]` allowed. Each element is read once.
|
|
94
|
+
*
|
|
95
|
+
* @param value candidate status list
|
|
96
|
+
* @returns the statuses, or null when `value` is not an array of strings
|
|
97
|
+
*/
|
|
98
|
+
export function readStatusList(value) {
|
|
99
|
+
if (!Array.isArray(value)) {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
const statuses = new Set();
|
|
103
|
+
const count = value.length;
|
|
104
|
+
for (let index = 0; index < count; index++) {
|
|
105
|
+
const status = value[index];
|
|
106
|
+
if (typeof status !== "string") {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
statuses.add(status);
|
|
110
|
+
}
|
|
111
|
+
return statuses;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Maximal runs of touching entries whose status passes `test`, merged as `mergeIntervals` merges
|
|
115
|
+
* them (CORE-6): touching entries join, and a gap or another status ends a run.
|
|
116
|
+
*/
|
|
117
|
+
export function runsOf(log, test) {
|
|
118
|
+
return runsMatching(log, (status) => test.has(status));
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* The parts of ordered, separate runs inside `[from, to)`, empty parts dropped: `clipRuns`, with
|
|
122
|
+
* the runs before `from` skipped by a binary search instead of read one by one.
|
|
123
|
+
*/
|
|
124
|
+
function runsBetween(runs, from, to) {
|
|
125
|
+
let low = 0;
|
|
126
|
+
let high = runs.length;
|
|
127
|
+
// A binary search over at most 2^32 runs.
|
|
128
|
+
for (let step = 0; step < 33 && low < high; step++) {
|
|
129
|
+
const middle = (low + high) >> 1;
|
|
130
|
+
if (runs[middle].end <= from) {
|
|
131
|
+
low = middle + 1;
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
high = middle;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
const inside = [];
|
|
138
|
+
for (let index = low; index < runs.length; index++) {
|
|
139
|
+
const run = runs[index];
|
|
140
|
+
if (run.start >= to) {
|
|
141
|
+
break;
|
|
142
|
+
}
|
|
143
|
+
inside.push({ start: max(run.start, from), end: min(run.end, to) });
|
|
144
|
+
}
|
|
145
|
+
return inside;
|
|
146
|
+
}
|
|
147
|
+
/** The parts of runs inside `[from, to)`, empty parts dropped. */
|
|
148
|
+
export function clipRuns(runs, from, to) {
|
|
149
|
+
const clipped = [];
|
|
150
|
+
for (const run of runs) {
|
|
151
|
+
const start = max(run.start, from);
|
|
152
|
+
const end = min(run.end, to);
|
|
153
|
+
if (start < end) {
|
|
154
|
+
clipped.push({ start, end });
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return clipped;
|
|
158
|
+
}
|
|
159
|
+
/** Time in `statuses` inside `[from, to)`. */
|
|
160
|
+
export function timeIn(log, statuses, from, to) {
|
|
161
|
+
let total = 0n;
|
|
162
|
+
for (const entry of log) {
|
|
163
|
+
if (statuses.has(entry.status)) {
|
|
164
|
+
const start = max(entry.start, from);
|
|
165
|
+
const end = min(entry.end, to);
|
|
166
|
+
total += end > start ? end - start : 0n;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return total;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* The paired rests among runs of rest: two runs in a row, each shorter than `fullRest` and at
|
|
173
|
+
* least `pair.each`, the longer at least `pair.one` and both together at least `pair.combined`.
|
|
174
|
+
*
|
|
175
|
+
* - A run of `fullRest` or more is a rest on its own: it pairs with nothing, and no pair spans it.
|
|
176
|
+
* - A run shorter than `pair.each` is neither half of a pair nor a break between two runs.
|
|
177
|
+
* - Pairs may chain: of runs a, b and c, both (a, b) and (b, c) are returned when both qualify.
|
|
178
|
+
*
|
|
179
|
+
* @param runs runs of rest, in order
|
|
180
|
+
* @param fullRest the length at which a run is a full rest
|
|
181
|
+
* @param pair the three floors
|
|
182
|
+
* @returns the qualifying pairs, in order
|
|
183
|
+
*/
|
|
184
|
+
export function restPairs(runs, fullRest, pair) {
|
|
185
|
+
const pairs = [];
|
|
186
|
+
let previous;
|
|
187
|
+
for (const run of runs) {
|
|
188
|
+
const taken = length(run);
|
|
189
|
+
if (taken >= fullRest) {
|
|
190
|
+
previous = undefined;
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
if (taken < pair.each) {
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
if (previous !== undefined) {
|
|
197
|
+
const before = length(previous);
|
|
198
|
+
if (max(before, taken) >= pair.one && before + taken >= pair.combined) {
|
|
199
|
+
pairs.push({ first: previous, second: run });
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
previous = run;
|
|
203
|
+
}
|
|
204
|
+
return pairs;
|
|
205
|
+
}
|
|
206
|
+
/** A period repeated `times` over: `times` × its length, or `times` × its count. */
|
|
207
|
+
function repeated(period, times) {
|
|
208
|
+
return period.kind === "elapsed"
|
|
209
|
+
? { kind: "elapsed", length: period.length * BigInt(times) }
|
|
210
|
+
: { ...period, count: period.count * times };
|
|
211
|
+
}
|
|
212
|
+
/** The window a period names at `at`: sliding for elapsed time, whole periods otherwise. */
|
|
213
|
+
function windowOf(context, period, at, anchor) {
|
|
214
|
+
if (period.kind === "elapsed") {
|
|
215
|
+
return {
|
|
216
|
+
span: {
|
|
217
|
+
start: max(at - period.length, MIN_EPOCH_NANOSECONDS),
|
|
218
|
+
end: at,
|
|
219
|
+
},
|
|
220
|
+
basis: "elapsed",
|
|
221
|
+
rolling: true,
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
const scale = scaleFor(context, period.unit);
|
|
225
|
+
const span = periodsEndingAt(scale, period.count, anchor);
|
|
226
|
+
if (span === null) {
|
|
227
|
+
throw new Unrepresentable("period outside the instant range");
|
|
228
|
+
}
|
|
229
|
+
return { span, basis: scale.basis, rolling: period.count > 1 };
|
|
230
|
+
}
|
|
231
|
+
/** The end of the `periods`-th period, the one `from` falls in counting as the first. */
|
|
232
|
+
function boundaryAfter(context, period, periods, from) {
|
|
233
|
+
if (period.kind === "elapsed") {
|
|
234
|
+
return from + period.length * BigInt(periods);
|
|
235
|
+
}
|
|
236
|
+
const scale = scaleFor(context, period.unit);
|
|
237
|
+
const first = scale.containing(from);
|
|
238
|
+
const last = first === null
|
|
239
|
+
? null
|
|
240
|
+
: periodAfter(scale, first, period.count * periods - 1);
|
|
241
|
+
if (last === null) {
|
|
242
|
+
throw new Unrepresentable("period outside the instant range");
|
|
243
|
+
}
|
|
244
|
+
return last.end;
|
|
245
|
+
}
|
|
246
|
+
const basisOf = (window) => window.basis;
|
|
247
|
+
const groupingOf = (window) => window.rolling ? "slide" : "period";
|
|
248
|
+
/** A cap: holds while `used` is at most `limit`. */
|
|
249
|
+
function capped(used, limit, rest) {
|
|
250
|
+
const usedValue = "duration" in used ? used.duration : BigInt(used.count);
|
|
251
|
+
const limitValue = "duration" in limit ? limit.duration : BigInt(limit.count);
|
|
252
|
+
const remaining = limitValue - usedValue;
|
|
253
|
+
return {
|
|
254
|
+
satisfied: usedValue <= limitValue,
|
|
255
|
+
used,
|
|
256
|
+
limit,
|
|
257
|
+
remaining: "duration" in limit ? duration(remaining) : tally(Number(remaining)),
|
|
258
|
+
excess: usedValue - limitValue,
|
|
259
|
+
...rest,
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
/** A floor: holds while `used` is at least `limit`, or `met` says otherwise. */
|
|
263
|
+
function floored(used, limit, met, rest) {
|
|
264
|
+
return {
|
|
265
|
+
satisfied: met,
|
|
266
|
+
used: duration(used),
|
|
267
|
+
limit: duration(limit),
|
|
268
|
+
remaining: duration(limit - used),
|
|
269
|
+
excess: limit - used,
|
|
270
|
+
...rest,
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
/** How a list of rest runs measures against a `restRequirement`'s floors. */
|
|
274
|
+
function restChecks(rule, lengths) {
|
|
275
|
+
const sorted = [...lengths].sort((a, b) => (a > b ? -1 : a < b ? 1 : 0));
|
|
276
|
+
const longest = sorted[0] ?? 0n;
|
|
277
|
+
const checks = [];
|
|
278
|
+
let counted = sorted.reduce((sum, value) => sum + value, 0n);
|
|
279
|
+
if (rule.composition !== null) {
|
|
280
|
+
const { maxPeriods, longestAtLeast, othersAtLeast } = rule.composition;
|
|
281
|
+
const others = sorted
|
|
282
|
+
.slice(1)
|
|
283
|
+
.filter((value) => value >= othersAtLeast)
|
|
284
|
+
.slice(0, maxPeriods - 1);
|
|
285
|
+
counted = min(counted, others.reduce((sum, value) => sum + value, longest));
|
|
286
|
+
checks.push({ used: longest, limit: longestAtLeast });
|
|
287
|
+
}
|
|
288
|
+
if (rule.composite !== null) {
|
|
289
|
+
const { consecutive, additional, blockMinimum } = rule.composite;
|
|
290
|
+
const blocks = sorted
|
|
291
|
+
.slice(1)
|
|
292
|
+
.filter((value) => value >= blockMinimum)
|
|
293
|
+
.reduce((sum, value) => sum + value, 0n);
|
|
294
|
+
checks.push({ used: longest, limit: consecutive });
|
|
295
|
+
checks.push({
|
|
296
|
+
used: max(longest - consecutive, 0n) + blocks,
|
|
297
|
+
limit: additional,
|
|
298
|
+
});
|
|
299
|
+
counted = min(counted, longest + blocks);
|
|
300
|
+
}
|
|
301
|
+
checks.push({ used: counted, limit: rule.minimum });
|
|
302
|
+
const failing = checks.find((check) => check.used < check.limit);
|
|
303
|
+
return {
|
|
304
|
+
met: failing === undefined,
|
|
305
|
+
failing,
|
|
306
|
+
// The last check is always the minimum: rest counted against `minimum`.
|
|
307
|
+
total: checks[checks.length - 1],
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
/** Rest runs with rest added from `at` to `end`, joined to a run that reaches `at`. */
|
|
311
|
+
function withRestUntil(runs, at, end) {
|
|
312
|
+
const last = runs[runs.length - 1];
|
|
313
|
+
return last !== undefined && last.end === at
|
|
314
|
+
? [...runs.slice(0, -1), { start: last.start, end }]
|
|
315
|
+
: [...runs, { start: at, end }];
|
|
316
|
+
}
|
|
317
|
+
/** `resolveWallClock` under the call's policy, each local date-time resolved once per call. */
|
|
318
|
+
function wallClockOf(context, date, time) {
|
|
319
|
+
const key = `${date.toString()}T${time.toString()}`;
|
|
320
|
+
const known = context.wallClocks.get(key);
|
|
321
|
+
if (known !== undefined) {
|
|
322
|
+
return known;
|
|
323
|
+
}
|
|
324
|
+
const resolved = resolveWallClock(context.frame, date, time, context.disambiguation);
|
|
325
|
+
context.wallClocks.set(key, resolved);
|
|
326
|
+
return resolved;
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* The whole local windows inside `[from, to)` in the reference zone, their edges resolved under
|
|
330
|
+
* the call's `disambiguation`.
|
|
331
|
+
*
|
|
332
|
+
* - `strict`: under `"reject"`, a window with a repeated or skipped edge that reaches `[from, to)`
|
|
333
|
+
* throws `WallClockRejected`. Without it, such an edge is read `"compatible"`: for rest that is
|
|
334
|
+
* only supposed (the best case of a window not yet over), or for finding candidate instants.
|
|
335
|
+
*/
|
|
336
|
+
function localWindowsIn(context, window, from, to, strict) {
|
|
337
|
+
const found = [];
|
|
338
|
+
const instances = windowInstances(context, window, from, to);
|
|
339
|
+
// Every policy maps wall times to instants without reversing them, so the instances are in
|
|
340
|
+
// order by start and by end: skip to the first that ends after `from`.
|
|
341
|
+
let low = 0;
|
|
342
|
+
let high = instances.length;
|
|
343
|
+
// A binary search over at most 2^32 instances.
|
|
344
|
+
for (let step = 0; step < 33 && low < high; step++) {
|
|
345
|
+
const middle = (low + high) >> 1;
|
|
346
|
+
if (instances[middle].end <= from) {
|
|
347
|
+
low = middle + 1;
|
|
348
|
+
}
|
|
349
|
+
else {
|
|
350
|
+
high = middle;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
for (let index = low; index < instances.length; index++) {
|
|
354
|
+
const instance = instances[index];
|
|
355
|
+
if (instance.start >= to) {
|
|
356
|
+
break;
|
|
357
|
+
}
|
|
358
|
+
// Under "reject", a window with a repeated or skipped edge that reaches the run is refused.
|
|
359
|
+
if (strict && instance.rejected && instance.end > from) {
|
|
360
|
+
throw new WallClockRejected("a local window the zone repeats or skips");
|
|
361
|
+
}
|
|
362
|
+
if (instance.start < instance.end &&
|
|
363
|
+
instance.start >= from &&
|
|
364
|
+
instance.end <= to) {
|
|
365
|
+
found.push({ start: instance.start, end: instance.end });
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
return found;
|
|
369
|
+
}
|
|
370
|
+
/** Two days: how far either side of a request the window instances are resolved and kept. */
|
|
371
|
+
const WINDOW_MARGIN = 172800000000000n;
|
|
372
|
+
/** The instances of a local window on the dates `first` to `last`, in date order. */
|
|
373
|
+
function instancesOn(context, window, first, last) {
|
|
374
|
+
const instances = [];
|
|
375
|
+
let date = first;
|
|
376
|
+
for (let step = 0; date !== null && Temporal.PlainDate.compare(date, last) <= 0; step++) {
|
|
377
|
+
if (step > 2 * MAX_PERIOD_COUNT) {
|
|
378
|
+
throw new Unrepresentable("too many local windows");
|
|
379
|
+
}
|
|
380
|
+
const next = datePlusDays(date, 1);
|
|
381
|
+
const start = wallClockOf(context, date, window.from);
|
|
382
|
+
const end = window.wraps && next === null
|
|
383
|
+
? null
|
|
384
|
+
: wallClockOf(context, window.wraps ? next : date, window.to);
|
|
385
|
+
if (start !== null && end !== null) {
|
|
386
|
+
instances.push({
|
|
387
|
+
start: start.at,
|
|
388
|
+
end: end.at,
|
|
389
|
+
rejected: start.rejected || end.rejected,
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
date = next;
|
|
393
|
+
}
|
|
394
|
+
return instances;
|
|
395
|
+
}
|
|
396
|
+
/** How close a request must be to a stretch already resolved to extend it: thirty days. */
|
|
397
|
+
const WINDOW_JOIN = 2592000000000000n;
|
|
398
|
+
/**
|
|
399
|
+
* Every instance of a local window on the local dates around `[from, to)`, resolved once per call
|
|
400
|
+
* and kept, so each later evaluation only filters them.
|
|
401
|
+
*
|
|
402
|
+
* - A request near a stretch of dates already kept resolves only the dates it adds, so a scan
|
|
403
|
+
* that moves along the log resolves each date once. A request far from every stretch starts a
|
|
404
|
+
* stretch of its own: the dates between two far-apart rests are never resolved.
|
|
405
|
+
* - One request may need at most `2 × MAX_PERIOD_COUNT` dates; past that it throws
|
|
406
|
+
* `Unrepresentable`. What is kept from earlier requests does not count against it.
|
|
407
|
+
*/
|
|
408
|
+
function windowInstances(context, window, from, to) {
|
|
409
|
+
const key = `${window.from.toString()}-${window.to.toString()}`;
|
|
410
|
+
const stretches = context.windowInstances.get(key) ?? [];
|
|
411
|
+
const covering = stretches.find((stretch) => stretch.from <= from && stretch.to >= to);
|
|
412
|
+
if (covering !== undefined) {
|
|
413
|
+
return covering.instances;
|
|
414
|
+
}
|
|
415
|
+
const wantedFrom = from - WINDOW_MARGIN;
|
|
416
|
+
const wantedTo = to + WINDOW_MARGIN;
|
|
417
|
+
const wanted = datePlusDays(localDateOf(context.frame, wantedFrom), -1);
|
|
418
|
+
const until = localDateOf(context.frame, wantedTo - 1n);
|
|
419
|
+
if (wanted === null ||
|
|
420
|
+
wanted.until(until, { largestUnit: "day" }).days > 2 * MAX_PERIOD_COUNT) {
|
|
421
|
+
throw new Unrepresentable("too many local windows");
|
|
422
|
+
}
|
|
423
|
+
const known = stretches.find((stretch) => stretch.from - WINDOW_JOIN <= wantedTo &&
|
|
424
|
+
stretch.to + WINDOW_JOIN >= wantedFrom);
|
|
425
|
+
const spanFrom = known === undefined ? wantedFrom : min(known.from, wantedFrom);
|
|
426
|
+
const spanTo = known === undefined ? wantedTo : max(known.to, wantedTo);
|
|
427
|
+
// A fall-back can put an earlier instant on a later local date, so the dates kept stay a
|
|
428
|
+
// superset of the dates wanted.
|
|
429
|
+
const first = known !== undefined && Temporal.PlainDate.compare(known.first, wanted) < 0
|
|
430
|
+
? known.first
|
|
431
|
+
: wanted;
|
|
432
|
+
const last = known !== undefined && Temporal.PlainDate.compare(known.last, until) > 0
|
|
433
|
+
? known.last
|
|
434
|
+
: until;
|
|
435
|
+
let instances;
|
|
436
|
+
if (known === undefined) {
|
|
437
|
+
instances = instancesOn(context, window, first, last);
|
|
438
|
+
}
|
|
439
|
+
else {
|
|
440
|
+
const before = datePlusDays(known.first, -1);
|
|
441
|
+
const after = datePlusDays(known.last, 1);
|
|
442
|
+
instances = [
|
|
443
|
+
...(before !== null && Temporal.PlainDate.compare(first, before) <= 0
|
|
444
|
+
? instancesOn(context, window, first, before)
|
|
445
|
+
: []),
|
|
446
|
+
...known.instances,
|
|
447
|
+
...(after !== null && Temporal.PlainDate.compare(after, last) <= 0
|
|
448
|
+
? instancesOn(context, window, after, last)
|
|
449
|
+
: []),
|
|
450
|
+
];
|
|
451
|
+
}
|
|
452
|
+
const stretch = { from: spanFrom, to: spanTo, first, last, instances };
|
|
453
|
+
context.windowInstances.set(key, [
|
|
454
|
+
...stretches.filter((other) => other !== known),
|
|
455
|
+
stretch,
|
|
456
|
+
]);
|
|
457
|
+
return instances;
|
|
458
|
+
}
|
|
459
|
+
/** How many free periods one run of rest holds. */
|
|
460
|
+
function freePeriodsIn(context, rule, run, strict) {
|
|
461
|
+
if (rule.containing === null) {
|
|
462
|
+
return length(run) / rule.minimum;
|
|
463
|
+
}
|
|
464
|
+
// Greedy, earliest end first: each free period ends as soon as it is long enough and holds
|
|
465
|
+
// enough windows, which leaves the most room for the next.
|
|
466
|
+
const { window, count } = rule.containing;
|
|
467
|
+
const instances = localWindowsIn(context, window, run.start, run.end, strict);
|
|
468
|
+
let cursor = run.start;
|
|
469
|
+
let first = 0;
|
|
470
|
+
let found = 0;
|
|
471
|
+
// Each free period takes at least one window, so there are no more of them than windows. The
|
|
472
|
+
// cursor only moves on, so the first window after it is found by moving on too.
|
|
473
|
+
for (let step = 0; step <= instances.length; step++) {
|
|
474
|
+
for (; first < instances.length; first++) {
|
|
475
|
+
if (instances[first].start >= cursor) {
|
|
476
|
+
break;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
const last = instances[first + count - 1];
|
|
480
|
+
const end = last === undefined ? null : max(cursor + rule.minimum, last.end);
|
|
481
|
+
if (end === null || end > run.end) {
|
|
482
|
+
break;
|
|
483
|
+
}
|
|
484
|
+
found++;
|
|
485
|
+
cursor = end;
|
|
486
|
+
}
|
|
487
|
+
return BigInt(found);
|
|
488
|
+
}
|
|
489
|
+
function evaluateFreePeriod(context, rule, at, anchor) {
|
|
490
|
+
const window = windowOf(context, rule.within, at, anchor);
|
|
491
|
+
// Every count below ends at or before `at`, so the runs of the whole log, cut to the count's
|
|
492
|
+
// span, are the runs of the log as it stands at `at`.
|
|
493
|
+
const rests = runIndex(context.store, rule.restStatuses).runs;
|
|
494
|
+
const countIn = (from, to, extendTo) => {
|
|
495
|
+
const inside = runsBetween(rests, from, to);
|
|
496
|
+
const runs = extendTo === undefined ? inside : withRestUntil(inside, at, extendTo);
|
|
497
|
+
// Rest supposed from `at` is not the log, so "reject" does not refuse its windows.
|
|
498
|
+
const strict = extendTo === undefined;
|
|
499
|
+
return runs.reduce((sum, run) => sum + freePeriodsIn(context, rule, run, strict), 0n);
|
|
500
|
+
};
|
|
501
|
+
// `atLeast` is a safe integer, so a count capped there compares with it as the count does.
|
|
502
|
+
const enough = (count) => count >= BigInt(rule.atLeast);
|
|
503
|
+
const { span } = window;
|
|
504
|
+
const found = exactCount(countIn(span.start, min(span.end, at)));
|
|
505
|
+
const unfinished = span.end > at;
|
|
506
|
+
const met = found >= rule.atLeast ||
|
|
507
|
+
(unfinished && enough(countIn(span.start, at, span.end)));
|
|
508
|
+
let dueBy = null;
|
|
509
|
+
if (found >= rule.atLeast && rule.atLeast > 0) {
|
|
510
|
+
if (rule.within.kind === "elapsed") {
|
|
511
|
+
// With no rest after `at`, the count of a window ending at t only falls as t grows, and
|
|
512
|
+
// a window starting at `at` holds none: find the last t that still holds enough.
|
|
513
|
+
const windowLength = rule.within.length;
|
|
514
|
+
let low = at;
|
|
515
|
+
let high = at + windowLength;
|
|
516
|
+
// A Temporal duration is under 2^53 seconds, so under 2^83 nanoseconds: 90 halvings
|
|
517
|
+
// always settle it.
|
|
518
|
+
for (let step = 0; step < 90 && high - low > 1n; step++) {
|
|
519
|
+
const middle = (low + high) / 2n;
|
|
520
|
+
if (enough(countIn(middle - windowLength, at))) {
|
|
521
|
+
low = middle;
|
|
522
|
+
}
|
|
523
|
+
else {
|
|
524
|
+
high = middle;
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
dueBy = low;
|
|
528
|
+
}
|
|
529
|
+
else {
|
|
530
|
+
// The window k periods later runs from the k-th period of this one, for `count` periods.
|
|
531
|
+
// Its count only falls as k grows, and k = count holds none, so search for the first short.
|
|
532
|
+
const scale = scaleFor(context, rule.within.unit);
|
|
533
|
+
const count = rule.within.count;
|
|
534
|
+
const first = scale.containing(span.start);
|
|
535
|
+
const unitAt = (index) => {
|
|
536
|
+
// The scale keeps the periods it walks, so the search below walks each one once.
|
|
537
|
+
const found = first === null ? null : periodAfter(scale, first, index);
|
|
538
|
+
if (found === null) {
|
|
539
|
+
throw new Unrepresentable("period outside the instant range");
|
|
540
|
+
}
|
|
541
|
+
return found;
|
|
542
|
+
};
|
|
543
|
+
let low = 1;
|
|
544
|
+
let high = count;
|
|
545
|
+
for (let step = 0; step < 32 && low < high; step++) {
|
|
546
|
+
const middle = (low + high) >> 1;
|
|
547
|
+
if (!enough(countIn(unitAt(middle).start, at))) {
|
|
548
|
+
high = middle;
|
|
549
|
+
}
|
|
550
|
+
else {
|
|
551
|
+
low = middle + 1;
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
dueBy = unitAt(low + count - 1).end;
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
else if (met) {
|
|
558
|
+
dueBy = span.end;
|
|
559
|
+
}
|
|
560
|
+
return {
|
|
561
|
+
satisfied: met,
|
|
562
|
+
used: tally(found),
|
|
563
|
+
limit: tally(rule.atLeast),
|
|
564
|
+
remaining: tally(rule.atLeast - found),
|
|
565
|
+
window: span,
|
|
566
|
+
periodBasis: basisOf(window),
|
|
567
|
+
dueBy,
|
|
568
|
+
resetAt: null,
|
|
569
|
+
excess: BigInt(rule.atLeast - found),
|
|
570
|
+
grouping: groupingOf(window),
|
|
571
|
+
};
|
|
572
|
+
}
|
|
573
|
+
/**
|
|
574
|
+
* The stretches without rest in the log as it stood at `at`: each runs from the end of one rest to
|
|
575
|
+
* the start of the next, the last to `at` (or nowhere, when a rest reaches `at`). The log's first
|
|
576
|
+
* entry starts one too, as a rest ending there would: time before the log is unknown, but the work
|
|
577
|
+
* logged before the first rest is a stretch without rest like any other.
|
|
578
|
+
*/
|
|
579
|
+
function restGaps(rests, logStart, at) {
|
|
580
|
+
const taken = rests.count;
|
|
581
|
+
const resting = rests.last !== undefined && rests.last.end === at;
|
|
582
|
+
const prepended = logStart !== undefined &&
|
|
583
|
+
(taken === 0 || viewRun(rests, 0).start !== logStart);
|
|
584
|
+
const startAt = (gap) => prepended
|
|
585
|
+
? gap === 0
|
|
586
|
+
? logStart
|
|
587
|
+
: viewRun(rests, gap - 1).end
|
|
588
|
+
: viewRun(rests, gap).end;
|
|
589
|
+
const endAt = (gap) => {
|
|
590
|
+
const next = prepended ? gap : gap + 1;
|
|
591
|
+
return next < taken
|
|
592
|
+
? viewRun(rests, next).start
|
|
593
|
+
: resting
|
|
594
|
+
? startAt(gap)
|
|
595
|
+
: at;
|
|
596
|
+
};
|
|
597
|
+
return {
|
|
598
|
+
count: prepended ? taken + 1 : taken,
|
|
599
|
+
resting,
|
|
600
|
+
startAt,
|
|
601
|
+
endAt,
|
|
602
|
+
};
|
|
603
|
+
}
|
|
604
|
+
/**
|
|
605
|
+
* The longest stretch without rest touching `[from, to)`, found from the first that ends after
|
|
606
|
+
* `from`.
|
|
607
|
+
*/
|
|
608
|
+
function widestGap(gaps, from, to) {
|
|
609
|
+
let widest = 0n;
|
|
610
|
+
for (let gap = firstWhere(gaps.count, (position) => gaps.endAt(position) > from); gap < gaps.count && gaps.startAt(gap) < to; gap++) {
|
|
611
|
+
widest = max(widest, gaps.endAt(gap) - gaps.startAt(gap));
|
|
612
|
+
}
|
|
613
|
+
return widest;
|
|
614
|
+
}
|
|
615
|
+
/** The widest stretch without rest in `[from, upper)` at `at`, and when the next rest falls due. */
|
|
616
|
+
function widestRestGap(context, index, at, from, upper, maxGap) {
|
|
617
|
+
const gaps = restGaps(runsUntil(index, at), logStartBefore(context.store, at), at);
|
|
618
|
+
return {
|
|
619
|
+
widest: widestGap(gaps, from, upper),
|
|
620
|
+
dueBy: gaps.count > 0 && !gaps.resting
|
|
621
|
+
? gaps.startAt(gaps.count - 1) + maxGap
|
|
622
|
+
: null,
|
|
623
|
+
};
|
|
624
|
+
}
|
|
625
|
+
function evaluateRestRequirement(context, rule, at, anchor) {
|
|
626
|
+
const window = windowOf(context, rule.per, at, anchor);
|
|
627
|
+
const { span } = window;
|
|
628
|
+
const index = runIndex(context.store, rule.restStatuses);
|
|
629
|
+
const upper = min(span.end, at);
|
|
630
|
+
// The count ends at or before `at`, so the runs of the whole log, cut to it, are the runs of
|
|
631
|
+
// the log as it stands at `at`.
|
|
632
|
+
const inside = span.start < upper ? runsBetween(index.runs, span.start, upper) : [];
|
|
633
|
+
const actual = restChecks(rule, inside.map(length));
|
|
634
|
+
const met = actual.met ||
|
|
635
|
+
(span.end > at &&
|
|
636
|
+
restChecks(rule, withRestUntil(inside, at, span.end).map(length)).met);
|
|
637
|
+
// A failed rule shows the floor it failed; one that holds, or can still be met before its
|
|
638
|
+
// window ends, shows the rest counted so far against the minimum.
|
|
639
|
+
const shown = (met ? undefined : actual.failing) ?? actual.total;
|
|
640
|
+
const rest = {
|
|
641
|
+
window: span,
|
|
642
|
+
periodBasis: basisOf(window),
|
|
643
|
+
resetAt: null,
|
|
644
|
+
grouping: groupingOf(window),
|
|
645
|
+
};
|
|
646
|
+
if (rule.maxGap !== null) {
|
|
647
|
+
const { widest, dueBy } = widestRestGap(context, index, at, span.start, upper, rule.maxGap);
|
|
648
|
+
if (widest > rule.maxGap) {
|
|
649
|
+
return {
|
|
650
|
+
satisfied: false,
|
|
651
|
+
used: duration(widest),
|
|
652
|
+
limit: duration(rule.maxGap),
|
|
653
|
+
remaining: duration(0n),
|
|
654
|
+
excess: widest - rule.maxGap,
|
|
655
|
+
dueBy,
|
|
656
|
+
...rest,
|
|
657
|
+
};
|
|
658
|
+
}
|
|
659
|
+
return floored(shown.used, shown.limit, met, {
|
|
660
|
+
...rest,
|
|
661
|
+
dueBy,
|
|
662
|
+
});
|
|
663
|
+
}
|
|
664
|
+
return floored(shown.used, shown.limit, met, {
|
|
665
|
+
...rest,
|
|
666
|
+
dueBy: null,
|
|
667
|
+
});
|
|
668
|
+
}
|
|
669
|
+
/** The rest right before a duty, measured whole, against the duty before it (`orFactor`). */
|
|
670
|
+
function restBeforeDutyScaled(rule, orFactor, { rests, dutyStart, onDuty, logStart }) {
|
|
671
|
+
// The rest judged is the one right before the duty, measured whole, against the duty it
|
|
672
|
+
// ends: from the end of the last rest of at least `minimum` before it, breaks included, to
|
|
673
|
+
// where it starts. A duty between an earlier rest and this one is never skipped, and more
|
|
674
|
+
// rest before the duty only lengthens the rest or shortens the duty before it.
|
|
675
|
+
const rest = runEndingAt(rests, dutyStart);
|
|
676
|
+
const restStart = rest?.start ?? dutyStart;
|
|
677
|
+
const fullRest = latestAtLeast(rests, endingAtOrBefore(rests, restStart), rule.minimum);
|
|
678
|
+
const dutyFrom = fullRest?.end ?? min(logStart, restStart);
|
|
679
|
+
const previousDuty = restStart - dutyFrom;
|
|
680
|
+
const { numerator, denominator } = orFactor.k;
|
|
681
|
+
// k × the duty, rounded up to the nanosecond, exactly.
|
|
682
|
+
const scaled = (previousDuty * numerator + denominator - 1n) / denominator;
|
|
683
|
+
const limit = max(rule.minimum, max(scaled, orFactor.floor));
|
|
684
|
+
const used = rest === undefined ? 0n : length(rest);
|
|
685
|
+
return {
|
|
686
|
+
...floored(used, limit, !onDuty || used >= limit, {
|
|
687
|
+
window: { start: dutyFrom, end: dutyStart },
|
|
688
|
+
periodBasis: "elapsed",
|
|
689
|
+
dueBy: null,
|
|
690
|
+
resetAt: null,
|
|
691
|
+
grouping: "start",
|
|
692
|
+
}),
|
|
693
|
+
// A rest that starts with the log, or a duty with none logged before it, may have more
|
|
694
|
+
// rest before the log: the record does not judge it.
|
|
695
|
+
beforeLog: restStart <= logStart,
|
|
696
|
+
key: restStart,
|
|
697
|
+
};
|
|
698
|
+
}
|
|
699
|
+
/** The longest run of rest inside `[windowStart, dutyStart)`, the latest on a tie. */
|
|
700
|
+
function longestRestInside(rests, windowStart, dutyStart) {
|
|
701
|
+
// Only the runs reaching into the window are read, and dutyStart is at most `at`, so the cut
|
|
702
|
+
// last run reads as it does whole.
|
|
703
|
+
let rest;
|
|
704
|
+
for (let position = firstEndingAfter(rests, windowStart); position < rests.count; position++) {
|
|
705
|
+
const run = viewRun(rests, position);
|
|
706
|
+
if (run.start >= dutyStart) {
|
|
707
|
+
break;
|
|
708
|
+
}
|
|
709
|
+
const inside = min(run.end, dutyStart) - max(run.start, windowStart);
|
|
710
|
+
if (inside > 0n && (rest === undefined || inside >= rest.inside)) {
|
|
711
|
+
rest = { run, inside };
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
return rest;
|
|
715
|
+
}
|
|
716
|
+
/** The rest before a duty: the longest inside the window, against the minimum. */
|
|
717
|
+
function restBeforeDutyWithin(rule, { rests, dutyStart, onDuty }) {
|
|
718
|
+
const windowStart = max(dutyStart - rule.within, MIN_EPOCH_NANOSECONDS);
|
|
719
|
+
const rest = longestRestInside(rests, windowStart, dutyStart);
|
|
720
|
+
const used = rest?.inside ?? 0n;
|
|
721
|
+
return {
|
|
722
|
+
...floored(used, rule.minimum, !onDuty || used >= rule.minimum, {
|
|
723
|
+
window: { start: windowStart, end: dutyStart },
|
|
724
|
+
periodBasis: "elapsed",
|
|
725
|
+
dueBy: null,
|
|
726
|
+
resetAt: null,
|
|
727
|
+
grouping: "start",
|
|
728
|
+
}),
|
|
729
|
+
// Every duty start after one short rest is the same failure: the record lists it once.
|
|
730
|
+
key: rest?.run.start ?? windowStart,
|
|
731
|
+
};
|
|
732
|
+
}
|
|
733
|
+
function evaluateRestBeforeDuty(context, rule, at) {
|
|
734
|
+
const { store } = context;
|
|
735
|
+
const rests = runsUntil(runIndex(store, rule.restStatuses), at);
|
|
736
|
+
const last = lastEntryBefore(store, at);
|
|
737
|
+
const onDuty = last !== undefined &&
|
|
738
|
+
last.end === at &&
|
|
739
|
+
!rule.restStatuses.has(last.status);
|
|
740
|
+
// On duty, the duty started where the run outside rest reaching `at` began; resting, a duty
|
|
741
|
+
// starting now is the one to be ready for.
|
|
742
|
+
const dutyStart = onDuty
|
|
743
|
+
? runsUntil(runIndex(store, { not: rule.restStatuses }), at)
|
|
744
|
+
.last.start
|
|
745
|
+
: at;
|
|
746
|
+
const started = {
|
|
747
|
+
rests,
|
|
748
|
+
dutyStart,
|
|
749
|
+
onDuty,
|
|
750
|
+
logStart: logStartBefore(store, at) ?? at,
|
|
751
|
+
};
|
|
752
|
+
return rule.orFactor === null
|
|
753
|
+
? restBeforeDutyWithin(rule, started)
|
|
754
|
+
: restBeforeDutyScaled(rule, rule.orFactor, started);
|
|
755
|
+
}
|
|
756
|
+
function evaluateRule(context, rule, at, anchor) {
|
|
757
|
+
// A free period reads only runs of rest, kept for the whole call, not the log cut at `at`.
|
|
758
|
+
if (rule.kind === "freePeriod") {
|
|
759
|
+
return evaluateFreePeriod(context, rule, at, anchor);
|
|
760
|
+
}
|
|
761
|
+
// The log as it stands at `at` is the whole log read up to `at`: no copy is made.
|
|
762
|
+
const { store } = context;
|
|
763
|
+
const first = logStartBefore(store, at) ?? at;
|
|
764
|
+
const viewOf = (test) => runsUntil(runIndex(store, test), at);
|
|
765
|
+
const timeOf = (test, from, to) => timeInBefore(runIndex(store, test), from, to, at);
|
|
766
|
+
switch (rule.kind) {
|
|
767
|
+
case "cumulativeCap": {
|
|
768
|
+
const reset = lastAtLeastUntil(viewOf(rule.since.statuses), rule.since.consecutive);
|
|
769
|
+
const from = reset?.end ?? first;
|
|
770
|
+
return capped(duration(timeOf(rule.statuses, from, at)), duration(rule.cap), {
|
|
771
|
+
window: { start: from, end: at },
|
|
772
|
+
periodBasis: null,
|
|
773
|
+
dueBy: null,
|
|
774
|
+
resetAt: reset?.end ?? null,
|
|
775
|
+
grouping: "start",
|
|
776
|
+
});
|
|
777
|
+
}
|
|
778
|
+
case "elapsedWindow": {
|
|
779
|
+
const rests = viewOf(rule.since.statuses);
|
|
780
|
+
const reset = lastAtLeastUntil(rests, rule.since.consecutive);
|
|
781
|
+
const after = reset?.end ?? null;
|
|
782
|
+
const opener = firstEntryIn(store, rule.startStatuses, after, at);
|
|
783
|
+
if (opener === undefined) {
|
|
784
|
+
return {
|
|
785
|
+
satisfied: true,
|
|
786
|
+
used: duration(0n),
|
|
787
|
+
limit: duration(rule.length),
|
|
788
|
+
remaining: duration(rule.length),
|
|
789
|
+
window: null,
|
|
790
|
+
periodBasis: null,
|
|
791
|
+
dueBy: null,
|
|
792
|
+
resetAt: after,
|
|
793
|
+
excess: 0n,
|
|
794
|
+
grouping: "start",
|
|
795
|
+
};
|
|
796
|
+
}
|
|
797
|
+
let opensAt = opener.start;
|
|
798
|
+
let second;
|
|
799
|
+
if (rule.exclude !== null) {
|
|
800
|
+
const latest = latestPairFrom(rests, firstStartingAtOrAfter(rests, opener.start), rule.since.consecutive, rule.exclude);
|
|
801
|
+
if (latest !== undefined) {
|
|
802
|
+
opensAt = latest.first.end;
|
|
803
|
+
second = latest.second;
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
// The window's time stops while the second rest of a pair lasts, so a second rest that
|
|
807
|
+
// starts before the close moves it by its whole length, and one that starts after the close
|
|
808
|
+
// moves nothing. The extension and the second rest each lengthen the window, so either one
|
|
809
|
+
// can bring the other inside it: apply each once, as soon as it falls inside.
|
|
810
|
+
let closesAt = opensAt + rule.length;
|
|
811
|
+
let limit = rule.length;
|
|
812
|
+
let excluded = 0n;
|
|
813
|
+
let extended = false;
|
|
814
|
+
for (let pass = 0; pass < 2; pass++) {
|
|
815
|
+
if (excluded === 0n &&
|
|
816
|
+
second !== undefined &&
|
|
817
|
+
second.start < closesAt) {
|
|
818
|
+
excluded = length(second);
|
|
819
|
+
closesAt += excluded;
|
|
820
|
+
}
|
|
821
|
+
if (!extended &&
|
|
822
|
+
rule.extension !== null &&
|
|
823
|
+
opener.start <= rule.extension.from &&
|
|
824
|
+
rule.extension.from < closesAt) {
|
|
825
|
+
extended = true;
|
|
826
|
+
closesAt += rule.extension.by;
|
|
827
|
+
limit += rule.extension.by;
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
const late = timeOf(rule.restrictedStatuses, closesAt, at);
|
|
831
|
+
return {
|
|
832
|
+
satisfied: late === 0n,
|
|
833
|
+
used: duration(at - opensAt - excluded),
|
|
834
|
+
limit: duration(limit),
|
|
835
|
+
remaining: duration(closesAt - at),
|
|
836
|
+
window: { start: opensAt, end: closesAt },
|
|
837
|
+
periodBasis: "elapsed",
|
|
838
|
+
dueBy: closesAt,
|
|
839
|
+
resetAt: after,
|
|
840
|
+
excess: late,
|
|
841
|
+
grouping: "start",
|
|
842
|
+
};
|
|
843
|
+
}
|
|
844
|
+
case "requiredInterruption": {
|
|
845
|
+
const breaks = viewOf({
|
|
846
|
+
not: rule.countedStatuses,
|
|
847
|
+
within: rule.outsideStatuses,
|
|
848
|
+
});
|
|
849
|
+
const resetAt = interruptionResetAt(breaks, rule.minimum, rule.orderedSplit);
|
|
850
|
+
const from = resetAt ?? first;
|
|
851
|
+
return capped(duration(timeOf(rule.countedStatuses, from, at)), duration(rule.after), {
|
|
852
|
+
window: { start: from, end: at },
|
|
853
|
+
periodBasis: null,
|
|
854
|
+
dueBy: null,
|
|
855
|
+
resetAt,
|
|
856
|
+
grouping: "start",
|
|
857
|
+
});
|
|
858
|
+
}
|
|
859
|
+
case "rollingCap": {
|
|
860
|
+
const window = windowOf(context, rule.window, at, anchor);
|
|
861
|
+
const reset = rule.reset === null
|
|
862
|
+
? undefined
|
|
863
|
+
: lastAtLeastUntil(viewOf(rule.reset.statuses), rule.reset.consecutive);
|
|
864
|
+
const from = reset !== undefined && reset.end > window.span.start
|
|
865
|
+
? reset.end
|
|
866
|
+
: window.span.start;
|
|
867
|
+
const to = min(window.span.end, at);
|
|
868
|
+
let used = timeOf(rule.statuses, from, to);
|
|
869
|
+
let limit = rule.cap;
|
|
870
|
+
if (rule.precondition !== null) {
|
|
871
|
+
const { restStatuses, minimum, beforeHours } = rule.precondition;
|
|
872
|
+
// `to` is at most `at`, so the runs of the whole log, cut to it, are the log's.
|
|
873
|
+
const rest = (from < to
|
|
874
|
+
? runsBetween(runIndex(store, restStatuses).runs, from, to)
|
|
875
|
+
: []).find((run) => length(run) >= minimum);
|
|
876
|
+
const before = rest === undefined ? used : timeOf(rule.statuses, from, rest.start);
|
|
877
|
+
if (rest === undefined || before > beforeHours) {
|
|
878
|
+
limit = beforeHours;
|
|
879
|
+
used = before;
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
return capped(duration(used), duration(limit), {
|
|
883
|
+
window: { start: from, end: window.span.end },
|
|
884
|
+
periodBasis: basisOf(window),
|
|
885
|
+
dueBy: null,
|
|
886
|
+
resetAt: reset?.end ?? null,
|
|
887
|
+
grouping: groupingOf(window),
|
|
888
|
+
});
|
|
889
|
+
}
|
|
890
|
+
case "fixedPeriodCap": {
|
|
891
|
+
const window = windowOf(context, repeated(rule.period, rule.adjacent), at, anchor);
|
|
892
|
+
const total = timeOf(rule.statuses, window.span.start, min(window.span.end, at));
|
|
893
|
+
const rest = {
|
|
894
|
+
window: window.span,
|
|
895
|
+
periodBasis: basisOf(window),
|
|
896
|
+
dueBy: null,
|
|
897
|
+
resetAt: null,
|
|
898
|
+
grouping: groupingOf(window),
|
|
899
|
+
};
|
|
900
|
+
if (!rule.average) {
|
|
901
|
+
return capped(duration(total), duration(rule.cap), rest);
|
|
902
|
+
}
|
|
903
|
+
const periods = BigInt(rule.adjacent);
|
|
904
|
+
const allowed = rule.cap * periods;
|
|
905
|
+
return {
|
|
906
|
+
satisfied: total <= allowed,
|
|
907
|
+
used: duration((total + periods - 1n) / periods),
|
|
908
|
+
limit: duration(rule.cap),
|
|
909
|
+
remaining: duration(allowed - total),
|
|
910
|
+
excess: total - allowed,
|
|
911
|
+
...rest,
|
|
912
|
+
};
|
|
913
|
+
}
|
|
914
|
+
case "restRequirement":
|
|
915
|
+
return evaluateRestRequirement(context, rule, at, anchor);
|
|
916
|
+
case "restBeforeDuty":
|
|
917
|
+
return evaluateRestBeforeDuty(context, rule, at);
|
|
918
|
+
case "quota": {
|
|
919
|
+
const continuing = entryHolding(store, at);
|
|
920
|
+
const running = continuing !== undefined && rule.statuses.has(continuing.status);
|
|
921
|
+
const runs = viewOf(rule.statuses);
|
|
922
|
+
const sizes = { minimum: rule.minimum, maximum: rule.maximum };
|
|
923
|
+
// A run going on at `at` is not an event yet.
|
|
924
|
+
const skipEndingAt = running ? at : null;
|
|
925
|
+
if ("every" in rule.reset) {
|
|
926
|
+
const window = windowOf(context, rule.reset.every, at, anchor);
|
|
927
|
+
const to = min(window.span.end, at);
|
|
928
|
+
const found = countEvents(runs, sizes, { from: window.span.start, to }, skipEndingAt);
|
|
929
|
+
return capped(tally(found), tally(rule.count), {
|
|
930
|
+
window: window.span,
|
|
931
|
+
periodBasis: basisOf(window),
|
|
932
|
+
dueBy: null,
|
|
933
|
+
resetAt: null,
|
|
934
|
+
grouping: groupingOf(window),
|
|
935
|
+
});
|
|
936
|
+
}
|
|
937
|
+
const reset = lastAtLeastUntil(viewOf(rule.reset.statuses), rule.reset.consecutive);
|
|
938
|
+
const from = reset?.end ?? first;
|
|
939
|
+
return capped(tally(countEvents(runs, sizes, { from, to: null }, skipEndingAt)), tally(rule.count), {
|
|
940
|
+
window: { start: from, end: at },
|
|
941
|
+
periodBasis: null,
|
|
942
|
+
dueBy: null,
|
|
943
|
+
resetAt: reset?.end ?? null,
|
|
944
|
+
grouping: "start",
|
|
945
|
+
});
|
|
946
|
+
}
|
|
947
|
+
case "dueBy": {
|
|
948
|
+
const events = viewOf(rule.statuses);
|
|
949
|
+
const event = lastAtLeastUntil(events, rule.minimum);
|
|
950
|
+
const reset = rule.reset === null
|
|
951
|
+
? undefined
|
|
952
|
+
: lastAtLeastUntil(viewOf(rule.reset.statuses), rule.reset.consecutive);
|
|
953
|
+
const clock = event === undefined
|
|
954
|
+
? (reset?.end ?? null)
|
|
955
|
+
: reset === undefined
|
|
956
|
+
? event.end
|
|
957
|
+
: max(event.end, reset.end);
|
|
958
|
+
const from = clock ?? first;
|
|
959
|
+
const due = boundaryAfter(context, rule.period, rule.periods, from);
|
|
960
|
+
const latest = events.last;
|
|
961
|
+
const pending = latest !== undefined && latest.end === at && latest.start <= due;
|
|
962
|
+
return {
|
|
963
|
+
satisfied: at <= due || pending,
|
|
964
|
+
used: duration(at - from),
|
|
965
|
+
limit: duration(due - from),
|
|
966
|
+
remaining: duration(due - at),
|
|
967
|
+
window: { start: from, end: due },
|
|
968
|
+
periodBasis: rule.period.kind === "elapsed"
|
|
969
|
+
? "elapsed"
|
|
970
|
+
: scaleFor(context, rule.period.unit).basis,
|
|
971
|
+
dueBy: due,
|
|
972
|
+
resetAt: clock,
|
|
973
|
+
excess: at - due,
|
|
974
|
+
grouping: "start",
|
|
975
|
+
};
|
|
976
|
+
}
|
|
977
|
+
case "pattern": {
|
|
978
|
+
const window = windowOf(context, repeated(rule.period, rule.lookback), at, anchor);
|
|
979
|
+
const { span } = window;
|
|
980
|
+
const to = min(span.end, at);
|
|
981
|
+
const unfinished = span.end > at;
|
|
982
|
+
const counts = new Map();
|
|
983
|
+
for (const named of rule.classes) {
|
|
984
|
+
const runs = viewOf(named.statuses);
|
|
985
|
+
const qualifies = (run) => run.start >= span.start &&
|
|
986
|
+
run.start < to &&
|
|
987
|
+
length(run) >= named.minimum;
|
|
988
|
+
const found = countEvents(runs, { minimum: named.minimum, maximum: null }, { from: span.start, to }, null);
|
|
989
|
+
const last = runs.last;
|
|
990
|
+
let best = found;
|
|
991
|
+
if (unfinished) {
|
|
992
|
+
// A run counts in the window it starts in, measured whole, so the most the window can
|
|
993
|
+
// still gain is the runs that can start before it ends, each `minimum` long before the
|
|
994
|
+
// next. A run still going at `at` that started inside the window qualifies by going on;
|
|
995
|
+
// one that started before it must end first.
|
|
996
|
+
let firstStart = at;
|
|
997
|
+
if (last !== undefined &&
|
|
998
|
+
last.end === at &&
|
|
999
|
+
!qualifies(last) &&
|
|
1000
|
+
last.start >= span.start) {
|
|
1001
|
+
best += 1;
|
|
1002
|
+
firstStart = last.start + named.minimum;
|
|
1003
|
+
}
|
|
1004
|
+
if (firstStart < span.end) {
|
|
1005
|
+
const room = span.end - firstStart;
|
|
1006
|
+
// `best` is only held to `atLeast`, a safe integer, so a count past the safe
|
|
1007
|
+
// integers is capped there without changing an answer.
|
|
1008
|
+
best += Number(min((room + named.minimum - 1n) / named.minimum, BigInt(Number.MAX_SAFE_INTEGER)));
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
counts.set(named.label, { found, best });
|
|
1012
|
+
}
|
|
1013
|
+
const slack = rule.require.map((required) => {
|
|
1014
|
+
const tallied = counts.get(required.label);
|
|
1015
|
+
return {
|
|
1016
|
+
...required,
|
|
1017
|
+
found: tallied.found,
|
|
1018
|
+
actual: tallied.found - required.atLeast,
|
|
1019
|
+
best: tallied.best - required.atLeast,
|
|
1020
|
+
};
|
|
1021
|
+
});
|
|
1022
|
+
const tightest = slack.reduce((worst, item) => item.actual < worst.actual ? item : worst);
|
|
1023
|
+
const met = slack.every((item) => item.actual >= 0) ||
|
|
1024
|
+
(unfinished && slack.every((item) => item.best >= 0));
|
|
1025
|
+
return {
|
|
1026
|
+
satisfied: met,
|
|
1027
|
+
used: tally(tightest.found),
|
|
1028
|
+
limit: tally(tightest.atLeast),
|
|
1029
|
+
remaining: tally(-tightest.actual),
|
|
1030
|
+
window: span,
|
|
1031
|
+
periodBasis: basisOf(window),
|
|
1032
|
+
dueBy: null,
|
|
1033
|
+
resetAt: null,
|
|
1034
|
+
excess: BigInt(-tightest.actual),
|
|
1035
|
+
grouping: groupingOf(window),
|
|
1036
|
+
};
|
|
1037
|
+
}
|
|
1038
|
+
case "occurrenceCap": {
|
|
1039
|
+
const scale = scaleFor(context, rule.per.unit);
|
|
1040
|
+
const runs = viewOf(rule.statuses);
|
|
1041
|
+
const blocks = [];
|
|
1042
|
+
let blockAnchor = anchor;
|
|
1043
|
+
for (let index = 0; index < rule.lookback; index++) {
|
|
1044
|
+
const block = periodsEndingAt(scale, rule.per.count, blockAnchor);
|
|
1045
|
+
if (block === null) {
|
|
1046
|
+
throw new Unrepresentable("period outside the instant range");
|
|
1047
|
+
}
|
|
1048
|
+
blocks.push(block);
|
|
1049
|
+
blockAnchor = block.start - 1n;
|
|
1050
|
+
}
|
|
1051
|
+
const occupied = blocks.filter((block) => {
|
|
1052
|
+
const to = min(block.end, at);
|
|
1053
|
+
// The first run that can count: starting in the block, or ending after it starts.
|
|
1054
|
+
const position = rule.byInitiationDate
|
|
1055
|
+
? firstStartingAtOrAfter(runs, block.start)
|
|
1056
|
+
: firstEndingAfter(runs, block.start);
|
|
1057
|
+
return position < runs.count && viewRun(runs, position).start < to;
|
|
1058
|
+
}).length;
|
|
1059
|
+
const earliest = blocks[blocks.length - 1];
|
|
1060
|
+
const latest = blocks[0];
|
|
1061
|
+
return capped(tally(occupied), tally(rule.maximum), {
|
|
1062
|
+
window: { start: earliest.start, end: latest.end },
|
|
1063
|
+
periodBasis: scale.basis,
|
|
1064
|
+
dueBy: null,
|
|
1065
|
+
resetAt: null,
|
|
1066
|
+
grouping: rule.lookback * rule.per.count > 1 ? "slide" : "period",
|
|
1067
|
+
});
|
|
1068
|
+
}
|
|
1069
|
+
case "usageLookback": {
|
|
1070
|
+
const window = windowOf(context, rule.notWithin, at, anchor);
|
|
1071
|
+
const reset = lastAtLeastUntil(viewOf(rule.reset.statuses), rule.reset.consecutive);
|
|
1072
|
+
const from = reset !== undefined && reset.end > window.span.start
|
|
1073
|
+
? reset.end
|
|
1074
|
+
: window.span.start;
|
|
1075
|
+
// A use is an instant, and each window holds it once. An elapsed window runs up to and
|
|
1076
|
+
// including the use being made at `at`, so one exactly its length earlier is outside it; a
|
|
1077
|
+
// window of local periods holds only its own, so one on its end is the next's.
|
|
1078
|
+
const found = countInRange(rule.uses, rule.notWithin.kind === "elapsed"
|
|
1079
|
+
? max(from, at - rule.notWithin.length + 1n)
|
|
1080
|
+
: from, rule.notWithin.kind === "elapsed"
|
|
1081
|
+
? at + 1n
|
|
1082
|
+
: min(at + 1n, window.span.end));
|
|
1083
|
+
return capped(tally(found), tally(1), {
|
|
1084
|
+
window: { start: from, end: window.span.end },
|
|
1085
|
+
periodBasis: basisOf(window),
|
|
1086
|
+
dueBy: null,
|
|
1087
|
+
resetAt: reset?.end ?? null,
|
|
1088
|
+
grouping: groupingOf(window),
|
|
1089
|
+
});
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
const instantText = (nanoseconds) => Temporal.Instant.fromEpochNanoseconds(nanoseconds).toString();
|
|
1094
|
+
function measureText(measure) {
|
|
1095
|
+
if (measure === null) {
|
|
1096
|
+
return null;
|
|
1097
|
+
}
|
|
1098
|
+
if (!("duration" in measure)) {
|
|
1099
|
+
return measure.count;
|
|
1100
|
+
}
|
|
1101
|
+
const text = formatHourDuration(measure.duration);
|
|
1102
|
+
// A requirement `orFactor` scales can pass the longest duration Temporal holds.
|
|
1103
|
+
if (text === "") {
|
|
1104
|
+
throw new Unrepresentable("a duration past Temporal's range");
|
|
1105
|
+
}
|
|
1106
|
+
return text;
|
|
1107
|
+
}
|
|
1108
|
+
function spanText(span) {
|
|
1109
|
+
return { start: instantText(span.start), end: instantText(span.end) };
|
|
1110
|
+
}
|
|
1111
|
+
/**
|
|
1112
|
+
* Evaluate every rule at one instant.
|
|
1113
|
+
*
|
|
1114
|
+
* @param context the call's context
|
|
1115
|
+
* @param rules the resolved rules
|
|
1116
|
+
* @param at the instant, epoch nanoseconds
|
|
1117
|
+
* @returns one outcome per rule, in order
|
|
1118
|
+
*/
|
|
1119
|
+
export function evaluateDutyRules(context, rules, at) {
|
|
1120
|
+
return rules.map((rule) => {
|
|
1121
|
+
// The log is read up to `at`, so its local periods are the ones holding the instant before:
|
|
1122
|
+
// at a boundary, the period just ended is judged, and a roster ending there is checked whole.
|
|
1123
|
+
const evaluation = evaluateRule(context, rule, at, at - 1n);
|
|
1124
|
+
return {
|
|
1125
|
+
label: rule.label,
|
|
1126
|
+
kind: rule.kind,
|
|
1127
|
+
severity: rule.severity,
|
|
1128
|
+
satisfied: evaluation.satisfied,
|
|
1129
|
+
used: measureText(evaluation.used),
|
|
1130
|
+
limit: measureText(evaluation.limit),
|
|
1131
|
+
remaining: measureText(evaluation.remaining),
|
|
1132
|
+
window: evaluation.window === null ? null : spanText(evaluation.window),
|
|
1133
|
+
periodBasis: evaluation.periodBasis,
|
|
1134
|
+
dueBy: evaluation.dueBy === null ? null : instantText(evaluation.dueBy),
|
|
1135
|
+
resetAt: evaluation.resetAt === null ? null : instantText(evaluation.resetAt),
|
|
1136
|
+
};
|
|
1137
|
+
});
|
|
1138
|
+
}
|
|
1139
|
+
/** The elapsed lengths a rule's window slides by, for the candidate instants of a range. */
|
|
1140
|
+
function slideLengths(rule) {
|
|
1141
|
+
const periods = [];
|
|
1142
|
+
switch (rule.kind) {
|
|
1143
|
+
case "rollingCap":
|
|
1144
|
+
periods.push(rule.window);
|
|
1145
|
+
break;
|
|
1146
|
+
case "restRequirement":
|
|
1147
|
+
periods.push(rule.per);
|
|
1148
|
+
break;
|
|
1149
|
+
case "freePeriod":
|
|
1150
|
+
periods.push(rule.within);
|
|
1151
|
+
break;
|
|
1152
|
+
case "quota":
|
|
1153
|
+
if ("every" in rule.reset) {
|
|
1154
|
+
periods.push(rule.reset.every);
|
|
1155
|
+
}
|
|
1156
|
+
break;
|
|
1157
|
+
case "pattern":
|
|
1158
|
+
periods.push(repeated(rule.period, rule.lookback));
|
|
1159
|
+
break;
|
|
1160
|
+
case "usageLookback":
|
|
1161
|
+
periods.push(rule.notWithin);
|
|
1162
|
+
break;
|
|
1163
|
+
default:
|
|
1164
|
+
break;
|
|
1165
|
+
}
|
|
1166
|
+
return periods.flatMap((period) => period.kind === "elapsed" ? [period.length] : []);
|
|
1167
|
+
}
|
|
1168
|
+
/** The local units a rule counts in, whose boundaries are candidate instants of a range. */
|
|
1169
|
+
function unitsOf(rule) {
|
|
1170
|
+
const periods = [];
|
|
1171
|
+
switch (rule.kind) {
|
|
1172
|
+
case "rollingCap":
|
|
1173
|
+
periods.push(rule.window);
|
|
1174
|
+
break;
|
|
1175
|
+
case "fixedPeriodCap":
|
|
1176
|
+
periods.push(rule.period);
|
|
1177
|
+
break;
|
|
1178
|
+
case "restRequirement":
|
|
1179
|
+
periods.push(rule.per);
|
|
1180
|
+
break;
|
|
1181
|
+
case "freePeriod":
|
|
1182
|
+
periods.push(rule.within);
|
|
1183
|
+
break;
|
|
1184
|
+
case "quota":
|
|
1185
|
+
if ("every" in rule.reset) {
|
|
1186
|
+
periods.push(rule.reset.every);
|
|
1187
|
+
}
|
|
1188
|
+
break;
|
|
1189
|
+
case "dueBy":
|
|
1190
|
+
case "pattern":
|
|
1191
|
+
periods.push(rule.period);
|
|
1192
|
+
break;
|
|
1193
|
+
case "occurrenceCap":
|
|
1194
|
+
periods.push(rule.per);
|
|
1195
|
+
break;
|
|
1196
|
+
case "usageLookback":
|
|
1197
|
+
periods.push(rule.notWithin);
|
|
1198
|
+
break;
|
|
1199
|
+
default:
|
|
1200
|
+
break;
|
|
1201
|
+
}
|
|
1202
|
+
return periods.flatMap((period) => period.kind === "units" ? [period.unit] : []);
|
|
1203
|
+
}
|
|
1204
|
+
const NANOSECONDS_PER_DAY = 86400000000000n;
|
|
1205
|
+
/**
|
|
1206
|
+
* More than any one local period of a unit can last: its longest calendar length plus a week. A
|
|
1207
|
+
* clock change moves the wall clock by less than 48 hours, since Temporal holds every offset
|
|
1208
|
+
* strictly within ±24 hours, so neither a skipped date nor a repeated stretch can add a week.
|
|
1209
|
+
*/
|
|
1210
|
+
const LONGER_THAN_ANY = {
|
|
1211
|
+
operatorDay: 8n * NANOSECONDS_PER_DAY,
|
|
1212
|
+
day: 8n * NANOSECONDS_PER_DAY,
|
|
1213
|
+
week: 14n * NANOSECONDS_PER_DAY,
|
|
1214
|
+
month: 38n * NANOSECONDS_PER_DAY,
|
|
1215
|
+
year: 373n * NANOSECONDS_PER_DAY,
|
|
1216
|
+
};
|
|
1217
|
+
/**
|
|
1218
|
+
* Call `visit` with the end of every period of `scale` that ends inside `(from, until]`, starting
|
|
1219
|
+
* with the one `from` falls in.
|
|
1220
|
+
*
|
|
1221
|
+
* - Throws `Unrepresentable` when more than `MAX_PERIOD_COUNT` periods end there, or for a period
|
|
1222
|
+
* Temporal cannot hold.
|
|
1223
|
+
* - A span of `MAX_PERIOD_COUNT + 1` times `LONGER_THAN_ANY` or more certainly holds more ends
|
|
1224
|
+
* than that, so it is refused without a lookup. A shorter span is walked, and the walk decides.
|
|
1225
|
+
*/
|
|
1226
|
+
export function walkBoundaries(scale, unit, from, until, visit) {
|
|
1227
|
+
if (from >= until) {
|
|
1228
|
+
return;
|
|
1229
|
+
}
|
|
1230
|
+
if (until - from >= BigInt(MAX_PERIOD_COUNT + 1) * LONGER_THAN_ANY[unit]) {
|
|
1231
|
+
throw new Unrepresentable("too many periods in the range");
|
|
1232
|
+
}
|
|
1233
|
+
let current = scale.containing(from);
|
|
1234
|
+
for (let step = 0; current !== null && current.end <= until; step++) {
|
|
1235
|
+
if (step >= MAX_PERIOD_COUNT) {
|
|
1236
|
+
throw new Unrepresentable("too many periods in the range");
|
|
1237
|
+
}
|
|
1238
|
+
visit(current.end);
|
|
1239
|
+
current = scale.containing(current.end);
|
|
1240
|
+
}
|
|
1241
|
+
if (current === null) {
|
|
1242
|
+
throw new Unrepresentable("period outside the instant range");
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
/**
|
|
1246
|
+
* The runs whose lengths a rule compares with floors, and the floors: where a run reaches a floor
|
|
1247
|
+
* (`start + floor`), or, inside a sliding window, shrinks below it (`end + length − floor`), the
|
|
1248
|
+
* rule's answer can change between entry bounds.
|
|
1249
|
+
*/
|
|
1250
|
+
function runFloors(rule) {
|
|
1251
|
+
switch (rule.kind) {
|
|
1252
|
+
case "cumulativeCap":
|
|
1253
|
+
return [
|
|
1254
|
+
{
|
|
1255
|
+
test: rule.since.statuses,
|
|
1256
|
+
floors: [rule.since.consecutive],
|
|
1257
|
+
sliding: false,
|
|
1258
|
+
},
|
|
1259
|
+
];
|
|
1260
|
+
case "elapsedWindow":
|
|
1261
|
+
return [
|
|
1262
|
+
{
|
|
1263
|
+
test: rule.since.statuses,
|
|
1264
|
+
floors: [
|
|
1265
|
+
rule.since.consecutive,
|
|
1266
|
+
...(rule.exclude === null
|
|
1267
|
+
? []
|
|
1268
|
+
: [rule.exclude.each, rule.exclude.one]),
|
|
1269
|
+
],
|
|
1270
|
+
sliding: false,
|
|
1271
|
+
},
|
|
1272
|
+
];
|
|
1273
|
+
case "requiredInterruption": {
|
|
1274
|
+
return [
|
|
1275
|
+
{
|
|
1276
|
+
test: { not: rule.countedStatuses, within: rule.outsideStatuses },
|
|
1277
|
+
floors: [rule.minimum, ...(rule.orderedSplit ?? [])],
|
|
1278
|
+
sliding: false,
|
|
1279
|
+
},
|
|
1280
|
+
];
|
|
1281
|
+
}
|
|
1282
|
+
case "rollingCap":
|
|
1283
|
+
return [
|
|
1284
|
+
...(rule.reset === null
|
|
1285
|
+
? []
|
|
1286
|
+
: [
|
|
1287
|
+
{
|
|
1288
|
+
test: rule.reset.statuses,
|
|
1289
|
+
floors: [rule.reset.consecutive],
|
|
1290
|
+
sliding: false,
|
|
1291
|
+
},
|
|
1292
|
+
]),
|
|
1293
|
+
...(rule.precondition === null
|
|
1294
|
+
? []
|
|
1295
|
+
: [
|
|
1296
|
+
{
|
|
1297
|
+
test: rule.precondition.restStatuses,
|
|
1298
|
+
floors: [rule.precondition.minimum],
|
|
1299
|
+
sliding: true,
|
|
1300
|
+
},
|
|
1301
|
+
]),
|
|
1302
|
+
];
|
|
1303
|
+
case "restRequirement": {
|
|
1304
|
+
const floors = [rule.minimum];
|
|
1305
|
+
if (rule.composition !== null) {
|
|
1306
|
+
floors.push(rule.composition.longestAtLeast);
|
|
1307
|
+
if (rule.composition.othersAtLeast > 0n) {
|
|
1308
|
+
floors.push(rule.composition.othersAtLeast);
|
|
1309
|
+
}
|
|
1310
|
+
}
|
|
1311
|
+
if (rule.composite !== null) {
|
|
1312
|
+
floors.push(rule.composite.consecutive, rule.composite.blockMinimum, rule.composite.consecutive + rule.composite.additional);
|
|
1313
|
+
}
|
|
1314
|
+
return [{ test: rule.restStatuses, floors, sliding: true }];
|
|
1315
|
+
}
|
|
1316
|
+
case "freePeriod":
|
|
1317
|
+
// Multiples are added per run in `candidateInstants`: a run holds floor(length / minimum).
|
|
1318
|
+
return [];
|
|
1319
|
+
case "quota":
|
|
1320
|
+
return "every" in rule.reset
|
|
1321
|
+
? []
|
|
1322
|
+
: [
|
|
1323
|
+
{
|
|
1324
|
+
test: rule.reset.statuses,
|
|
1325
|
+
floors: [rule.reset.consecutive],
|
|
1326
|
+
sliding: false,
|
|
1327
|
+
},
|
|
1328
|
+
];
|
|
1329
|
+
case "dueBy":
|
|
1330
|
+
return [
|
|
1331
|
+
{ test: rule.statuses, floors: [rule.minimum], sliding: false },
|
|
1332
|
+
...(rule.reset === null
|
|
1333
|
+
? []
|
|
1334
|
+
: [
|
|
1335
|
+
{
|
|
1336
|
+
test: rule.reset.statuses,
|
|
1337
|
+
floors: [rule.reset.consecutive],
|
|
1338
|
+
sliding: false,
|
|
1339
|
+
},
|
|
1340
|
+
]),
|
|
1341
|
+
];
|
|
1342
|
+
case "pattern":
|
|
1343
|
+
return rule.classes.map((named) => ({
|
|
1344
|
+
test: named.statuses,
|
|
1345
|
+
floors: [named.minimum],
|
|
1346
|
+
sliding: false,
|
|
1347
|
+
}));
|
|
1348
|
+
case "usageLookback":
|
|
1349
|
+
return [
|
|
1350
|
+
{
|
|
1351
|
+
test: rule.reset.statuses,
|
|
1352
|
+
floors: [rule.reset.consecutive],
|
|
1353
|
+
sliding: false,
|
|
1354
|
+
},
|
|
1355
|
+
];
|
|
1356
|
+
default:
|
|
1357
|
+
return [];
|
|
1358
|
+
}
|
|
1359
|
+
}
|
|
1360
|
+
/**
|
|
1361
|
+
* The instants at which a rule's answer can change, inside `(start, end]`.
|
|
1362
|
+
*
|
|
1363
|
+
* A rule's measures are piecewise linear in the instant evaluated, so a failed window shows at a
|
|
1364
|
+
* breakpoint or just either side of one:
|
|
1365
|
+
*
|
|
1366
|
+
* - every entry bound and use, those bounds shifted by the rule's sliding lengths, and every
|
|
1367
|
+
* boundary of its local periods;
|
|
1368
|
+
* - where a run reaches or, in a sliding window, shrinks past a floor the rule compares it with;
|
|
1369
|
+
* - for a rest rule that picks its longest runs, where two runs cross as the longest;
|
|
1370
|
+
* - where a gap passes `maxGap`, a rest falls due, and a free period gains or loses a local window;
|
|
1371
|
+
* - the first instant after `start`, so a window failing as the range opens is seen.
|
|
1372
|
+
*/
|
|
1373
|
+
function candidateInstants(context, rule, range) {
|
|
1374
|
+
// Nothing after the log's last entry is judged: the log says nothing about that time.
|
|
1375
|
+
const logEnd = context.entries[context.entries.length - 1]?.end;
|
|
1376
|
+
if (logEnd === undefined) {
|
|
1377
|
+
return [];
|
|
1378
|
+
}
|
|
1379
|
+
const until = min(range.end, logEnd);
|
|
1380
|
+
const base = [];
|
|
1381
|
+
for (const entry of context.entries) {
|
|
1382
|
+
base.push(entry.start, entry.end);
|
|
1383
|
+
}
|
|
1384
|
+
if (rule.kind === "usageLookback") {
|
|
1385
|
+
base.push(...rule.uses);
|
|
1386
|
+
}
|
|
1387
|
+
if (rule.kind === "elapsedWindow" && rule.extension !== null) {
|
|
1388
|
+
base.push(rule.extension.from);
|
|
1389
|
+
}
|
|
1390
|
+
// A rule's answer changes only at a breakpoint, so the instants either side of each one also
|
|
1391
|
+
// show where a failure starts and where a pass between two failures starts. Only the instants
|
|
1392
|
+
// inside `(range.start, until]` are kept.
|
|
1393
|
+
const points = new Set([range.start + 1n, until]);
|
|
1394
|
+
const add = (point) => {
|
|
1395
|
+
if (point > range.start && point <= until) {
|
|
1396
|
+
points.add(point);
|
|
1397
|
+
}
|
|
1398
|
+
};
|
|
1399
|
+
const around = (point) => {
|
|
1400
|
+
add(point - 1n);
|
|
1401
|
+
add(point);
|
|
1402
|
+
add(point + 1n);
|
|
1403
|
+
if (points.size > MAX_CANDIDATE_INSTANTS) {
|
|
1404
|
+
throw new Unrepresentable("too many instants to check");
|
|
1405
|
+
}
|
|
1406
|
+
};
|
|
1407
|
+
for (const point of base) {
|
|
1408
|
+
around(point);
|
|
1409
|
+
}
|
|
1410
|
+
const shifts = slideLengths(rule);
|
|
1411
|
+
for (const shift of shifts) {
|
|
1412
|
+
for (const point of base) {
|
|
1413
|
+
// A run leaves a window the instant after its bound plus the window's length.
|
|
1414
|
+
around(point + shift);
|
|
1415
|
+
}
|
|
1416
|
+
}
|
|
1417
|
+
for (const { test, floors, sliding } of runFloors(rule)) {
|
|
1418
|
+
for (const run of runIndex(context.store, test).runs) {
|
|
1419
|
+
for (const floor of floors) {
|
|
1420
|
+
around(run.start + floor);
|
|
1421
|
+
if (sliding) {
|
|
1422
|
+
for (const shift of shifts) {
|
|
1423
|
+
around(run.end + shift - floor);
|
|
1424
|
+
}
|
|
1425
|
+
}
|
|
1426
|
+
}
|
|
1427
|
+
}
|
|
1428
|
+
}
|
|
1429
|
+
if (rule.kind === "elapsedWindow" && rule.exclude !== null) {
|
|
1430
|
+
// The second rest of a pair completes the combined floor part-way through. Its partner is
|
|
1431
|
+
// the one `restPairs` gives it: the last earlier run long enough to be half of a pair, with no
|
|
1432
|
+
// full rest between. A run shorter than `each` is skipped, never a partner.
|
|
1433
|
+
const fullRest = rule.since.consecutive;
|
|
1434
|
+
let partner;
|
|
1435
|
+
for (const run of runIndex(context.store, rule.since.statuses).runs) {
|
|
1436
|
+
if (partner !== undefined) {
|
|
1437
|
+
around(run.start + rule.exclude.combined - length(partner));
|
|
1438
|
+
}
|
|
1439
|
+
const taken = length(run);
|
|
1440
|
+
if (taken >= fullRest) {
|
|
1441
|
+
partner = undefined;
|
|
1442
|
+
}
|
|
1443
|
+
else if (taken >= rule.exclude.each) {
|
|
1444
|
+
partner = run;
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
}
|
|
1448
|
+
if (rule.kind === "restRequirement") {
|
|
1449
|
+
const rests = runIndex(context.store, rule.restStatuses).runs;
|
|
1450
|
+
const ranks = rule.composition !== null || rule.composite !== null;
|
|
1451
|
+
if (rule.maxGap !== null) {
|
|
1452
|
+
// A stretch without rest starts at each rest's end and at the log's first entry.
|
|
1453
|
+
for (const start of [
|
|
1454
|
+
...rests.map((run) => run.end),
|
|
1455
|
+
...context.entries.slice(0, 1).map((entry) => entry.start),
|
|
1456
|
+
]) {
|
|
1457
|
+
around(start + rule.maxGap);
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
for (const shift of ranks ? shifts : []) {
|
|
1461
|
+
// A rest that ends two window lengths before the range, or starts two after it, is out of
|
|
1462
|
+
// every window the range judges, so it crosses nothing there.
|
|
1463
|
+
const near = rests.filter((run) => run.end >= range.start - 2n * shift &&
|
|
1464
|
+
run.start <= until + 2n * shift);
|
|
1465
|
+
for (let index = 0; index < near.length; index++) {
|
|
1466
|
+
const earlier = near[index];
|
|
1467
|
+
// A rest shrinking out of the window crosses one growing at its end, or one held whole.
|
|
1468
|
+
// The rests are ordered and separate, so those within two window lengths of `earlier`
|
|
1469
|
+
// are one stretch of them: from the first that ends within reach to the first that
|
|
1470
|
+
// starts out of it.
|
|
1471
|
+
for (let other = firstWhere(near.length, (position) => near[position].end > earlier.start - 2n * shift); other < near.length; other++) {
|
|
1472
|
+
const later = near[other];
|
|
1473
|
+
if (later.start - earlier.end >= 2n * shift) {
|
|
1474
|
+
break;
|
|
1475
|
+
}
|
|
1476
|
+
const crossing = (earlier.end + shift + later.start) / 2n;
|
|
1477
|
+
around(crossing);
|
|
1478
|
+
around(crossing + 1n);
|
|
1479
|
+
around(earlier.end + shift - length(later));
|
|
1480
|
+
around(later.start + length(earlier));
|
|
1481
|
+
}
|
|
1482
|
+
}
|
|
1483
|
+
}
|
|
1484
|
+
}
|
|
1485
|
+
if (rule.kind === "freePeriod") {
|
|
1486
|
+
const minimum = rule.minimum;
|
|
1487
|
+
// A run's points lie at most `atLeast + 1` free periods and a window length past its end, so
|
|
1488
|
+
// a run further than that before the range, or after it, adds none inside it.
|
|
1489
|
+
const farthest = (BigInt(rule.atLeast) + 1n) * minimum +
|
|
1490
|
+
shifts.reduce((longest, shift) => max(longest, shift), 0n);
|
|
1491
|
+
const rests = runIndex(context.store, rule.restStatuses).runs.filter((run) => run.end + farthest >= range.start && run.start <= until + 1n);
|
|
1492
|
+
// A window fails only while it holds fewer than `atLeast` free periods, so a run's count
|
|
1493
|
+
// changing above `atLeast` changes no answer: each run's first `atLeast + 1` multiples are
|
|
1494
|
+
// the ones that matter. Of those, only the ones that land in the range are taken.
|
|
1495
|
+
const reach = BigInt(rule.atLeast) + 1n;
|
|
1496
|
+
const multiplesFrom = (origin, last) => {
|
|
1497
|
+
const first = max(0n, floorDivide(range.start - origin, minimum) - 1n);
|
|
1498
|
+
const final = min(last, floorDivide(until - origin, minimum) + 1n);
|
|
1499
|
+
for (let multiple = first; multiple <= final; multiple++) {
|
|
1500
|
+
around(origin + multiple * minimum);
|
|
1501
|
+
}
|
|
1502
|
+
};
|
|
1503
|
+
const multiplesBefore = (origin, last) => {
|
|
1504
|
+
const first = max(0n, floorDivide(origin - until, minimum) - 1n);
|
|
1505
|
+
const final = min(last, floorDivide(origin - range.start, minimum) + 1n);
|
|
1506
|
+
for (let multiple = first; multiple <= final; multiple++) {
|
|
1507
|
+
around(origin - multiple * minimum);
|
|
1508
|
+
}
|
|
1509
|
+
};
|
|
1510
|
+
for (const run of rests) {
|
|
1511
|
+
const multiples = min(length(run) / minimum + 1n, reach);
|
|
1512
|
+
multiplesFrom(run.start, multiples);
|
|
1513
|
+
for (const shift of shifts) {
|
|
1514
|
+
multiplesBefore(run.end + shift, multiples);
|
|
1515
|
+
}
|
|
1516
|
+
if (rule.containing !== null) {
|
|
1517
|
+
const windows = localWindowsIn(context, rule.containing.window, run.start, run.end, false);
|
|
1518
|
+
for (const window of windows) {
|
|
1519
|
+
multiplesFrom(window.end, multiples);
|
|
1520
|
+
for (const shift of shifts) {
|
|
1521
|
+
around(window.start + shift);
|
|
1522
|
+
}
|
|
1523
|
+
}
|
|
1524
|
+
}
|
|
1525
|
+
}
|
|
1526
|
+
}
|
|
1527
|
+
if (rule.kind === "dueBy") {
|
|
1528
|
+
// A rest falls due the instant after its deadline; each run long enough to start the clock,
|
|
1529
|
+
// and the log's start, set one.
|
|
1530
|
+
const clocks = [
|
|
1531
|
+
context.entries[0]?.start,
|
|
1532
|
+
...runIndex(context.store, rule.statuses)
|
|
1533
|
+
.runs.filter((run) => length(run) >= rule.minimum)
|
|
1534
|
+
.map((run) => run.end),
|
|
1535
|
+
...(rule.reset === null
|
|
1536
|
+
? []
|
|
1537
|
+
: runIndex(context.store, rule.reset.statuses)
|
|
1538
|
+
.runs.filter((run) => length(run) >=
|
|
1539
|
+
rule.reset.consecutive)
|
|
1540
|
+
.map((run) => run.end)),
|
|
1541
|
+
];
|
|
1542
|
+
for (const clock of clocks) {
|
|
1543
|
+
if (clock !== undefined) {
|
|
1544
|
+
around(boundaryAfter(context, rule.period, rule.periods, clock));
|
|
1545
|
+
}
|
|
1546
|
+
}
|
|
1547
|
+
}
|
|
1548
|
+
// Before the log's first entry and the first use, no rule has anything to fail on, so the
|
|
1549
|
+
// period boundaries walked are the ones from there to `until`, however long `range` is.
|
|
1550
|
+
const from = max(range.start, firstEvidence(context, rule));
|
|
1551
|
+
for (const unit of unitsOf(rule)) {
|
|
1552
|
+
walkBoundaries(scaleFor(context, unit), unit, from, until, around);
|
|
1553
|
+
}
|
|
1554
|
+
return [...points]
|
|
1555
|
+
.filter((point) => point > range.start && point <= until)
|
|
1556
|
+
.sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
|
|
1557
|
+
}
|
|
1558
|
+
/** `a / b` rounded down, for a positive `b`: bigint division rounds towards zero. */
|
|
1559
|
+
function floorDivide(a, b) {
|
|
1560
|
+
return a >= 0n ? a / b : -((-a + b - 1n) / b);
|
|
1561
|
+
}
|
|
1562
|
+
/**
|
|
1563
|
+
* The worse of two failures, `a` the earlier: the larger excess, and on a tie the earlier, whose
|
|
1564
|
+
* window is the first to show it (a cap's window ends when the time over it was worked, not after
|
|
1565
|
+
* the rest that followed).
|
|
1566
|
+
*/
|
|
1567
|
+
function worse(a, b) {
|
|
1568
|
+
return b.evaluation.excess > a.evaluation.excess ? b : a;
|
|
1569
|
+
}
|
|
1570
|
+
const keyOf = (evaluation) => evaluation.key ?? evaluation.window.start;
|
|
1571
|
+
/** Whether a failure continues a violation: no passing check between, or the same key. */
|
|
1572
|
+
function continues(violation, failure) {
|
|
1573
|
+
return violation.grouping === "slide"
|
|
1574
|
+
? violation.open
|
|
1575
|
+
: keyOf(failure.evaluation) === violation.key;
|
|
1576
|
+
}
|
|
1577
|
+
/** A violation's report after one more failure: the last check of a period, else the worst. */
|
|
1578
|
+
function report(violation, failure) {
|
|
1579
|
+
return violation.grouping === "period"
|
|
1580
|
+
? failure
|
|
1581
|
+
: worse(violation.worst, failure);
|
|
1582
|
+
}
|
|
1583
|
+
/** The kinds that hold rest to a floor, which the record does not judge before the log starts. */
|
|
1584
|
+
const FLOOR_KINDS = new Set([
|
|
1585
|
+
"restRequirement",
|
|
1586
|
+
"freePeriod",
|
|
1587
|
+
"pattern",
|
|
1588
|
+
"restBeforeDuty",
|
|
1589
|
+
]);
|
|
1590
|
+
/**
|
|
1591
|
+
* The most instants one rule may be checked at in one range. A log of a year has a few tens of
|
|
1592
|
+
* thousands; more than this is refused rather than checked one by one.
|
|
1593
|
+
*/
|
|
1594
|
+
const MAX_CANDIDATE_INSTANTS = 1_000_000;
|
|
1595
|
+
/** Thirty days: how far past a range's end the scan reads at a time, so a period walk stays short. */
|
|
1596
|
+
const FORWARD_CHUNK = 2592000000000000n;
|
|
1597
|
+
/**
|
|
1598
|
+
* The earliest instant a rule has anything to fail on: the log's first entry, or for
|
|
1599
|
+
* `usageLookback` its first use when that is earlier. Undefined for an empty log.
|
|
1600
|
+
*/
|
|
1601
|
+
function firstEvidence(context, rule) {
|
|
1602
|
+
const first = context.entries[0]?.start;
|
|
1603
|
+
return first === undefined
|
|
1604
|
+
? undefined
|
|
1605
|
+
: [first, ...(rule.kind === "usageLookback" ? rule.uses : [])].reduce(min);
|
|
1606
|
+
}
|
|
1607
|
+
/**
|
|
1608
|
+
* The violations of one rule, each listed in the range it began in and reported by its worst
|
|
1609
|
+
* window, which may end after the range.
|
|
1610
|
+
*
|
|
1611
|
+
* - Failures inside `range` are grouped into violations as `scanDutyViolations` describes.
|
|
1612
|
+
* - The first is dropped when it was already failing at `range.start`: it belongs to the range
|
|
1613
|
+
* before. So two adjacent ranges list every violation once.
|
|
1614
|
+
* - The last is followed past `range.end` to its worst window, up to the log's last entry, never
|
|
1615
|
+
* into time the log does not cover.
|
|
1616
|
+
*/
|
|
1617
|
+
function ruleViolations(context, rule, asked) {
|
|
1618
|
+
const evidence = firstEvidence(context, rule);
|
|
1619
|
+
if (evidence === undefined) {
|
|
1620
|
+
return [];
|
|
1621
|
+
}
|
|
1622
|
+
// Nothing fails before the rule's first evidence, so a range opening earlier opens just
|
|
1623
|
+
// before it: no check is made, and no local window resolved, decades before the log.
|
|
1624
|
+
const range = { start: max(asked.start, evidence - 1n), end: asked.end };
|
|
1625
|
+
// A floor on rest is not judged on a window that starts before the log: the log cannot say
|
|
1626
|
+
// what happened then. A cap is, since time no entry covers never counts towards one.
|
|
1627
|
+
const logStart = context.entries[0]?.start;
|
|
1628
|
+
const judgesRest = FLOOR_KINDS.has(rule.kind);
|
|
1629
|
+
const check = (at) => {
|
|
1630
|
+
const evaluation = evaluateRule(context, rule, at, at - 1n);
|
|
1631
|
+
const judged = evaluation.window !== null &&
|
|
1632
|
+
!(judgesRest &&
|
|
1633
|
+
logStart !== undefined &&
|
|
1634
|
+
(evaluation.window.start < logStart || evaluation.beforeLog === true));
|
|
1635
|
+
const failure = judged && !evaluation.satisfied ? { evaluation, at } : null;
|
|
1636
|
+
return { evaluation, failure };
|
|
1637
|
+
};
|
|
1638
|
+
const violations = [];
|
|
1639
|
+
const candidates = candidateInstants(context, rule, range);
|
|
1640
|
+
let firstChecked;
|
|
1641
|
+
for (const at of candidates) {
|
|
1642
|
+
const { failure } = check(at);
|
|
1643
|
+
const last = violations[violations.length - 1];
|
|
1644
|
+
if (firstChecked === undefined) {
|
|
1645
|
+
firstChecked = failure;
|
|
1646
|
+
}
|
|
1647
|
+
if (failure === null) {
|
|
1648
|
+
if (last !== undefined) {
|
|
1649
|
+
last.open = false;
|
|
1650
|
+
}
|
|
1651
|
+
}
|
|
1652
|
+
else if (last !== undefined && continues(last, failure)) {
|
|
1653
|
+
last.worst = report(last, failure);
|
|
1654
|
+
}
|
|
1655
|
+
else {
|
|
1656
|
+
violations.push({
|
|
1657
|
+
worst: failure,
|
|
1658
|
+
grouping: failure.evaluation.grouping,
|
|
1659
|
+
key: keyOf(failure.evaluation),
|
|
1660
|
+
open: true,
|
|
1661
|
+
});
|
|
1662
|
+
}
|
|
1663
|
+
}
|
|
1664
|
+
const first = violations[0];
|
|
1665
|
+
if (first !== undefined) {
|
|
1666
|
+
let before;
|
|
1667
|
+
if (first.grouping === "slide") {
|
|
1668
|
+
// Failing from the range's first instant, and already at its start.
|
|
1669
|
+
before =
|
|
1670
|
+
firstChecked !== undefined &&
|
|
1671
|
+
firstChecked !== null &&
|
|
1672
|
+
check(range.start).failure !== null;
|
|
1673
|
+
}
|
|
1674
|
+
else {
|
|
1675
|
+
const key = first.key;
|
|
1676
|
+
before =
|
|
1677
|
+
key < range.start &&
|
|
1678
|
+
candidateInstants(context, rule, { start: key, end: range.start }).some((at) => {
|
|
1679
|
+
const { failure } = check(at);
|
|
1680
|
+
return failure !== null && continues(first, failure);
|
|
1681
|
+
});
|
|
1682
|
+
}
|
|
1683
|
+
if (before) {
|
|
1684
|
+
violations.shift();
|
|
1685
|
+
}
|
|
1686
|
+
}
|
|
1687
|
+
const last = violations[violations.length - 1];
|
|
1688
|
+
const logEnd = context.entries[context.entries.length - 1]?.end;
|
|
1689
|
+
if (last !== undefined &&
|
|
1690
|
+
logEnd !== undefined &&
|
|
1691
|
+
logEnd > range.end &&
|
|
1692
|
+
(last.grouping !== "slide" || last.open)) {
|
|
1693
|
+
let cursor = range.end;
|
|
1694
|
+
let going = true;
|
|
1695
|
+
for (let chunk = 0; going && cursor < logEnd && chunk <= MAX_PERIOD_COUNT; chunk++) {
|
|
1696
|
+
const until = min(cursor + FORWARD_CHUNK, logEnd);
|
|
1697
|
+
for (const at of candidateInstants(context, rule, {
|
|
1698
|
+
start: cursor,
|
|
1699
|
+
end: until,
|
|
1700
|
+
})) {
|
|
1701
|
+
const { evaluation, failure } = check(at);
|
|
1702
|
+
if (last.grouping === "slide") {
|
|
1703
|
+
if (failure === null) {
|
|
1704
|
+
going = false;
|
|
1705
|
+
break;
|
|
1706
|
+
}
|
|
1707
|
+
last.worst = report(last, failure);
|
|
1708
|
+
}
|
|
1709
|
+
else if (evaluation.window === null ||
|
|
1710
|
+
keyOf(evaluation) !== last.key) {
|
|
1711
|
+
going = false;
|
|
1712
|
+
break;
|
|
1713
|
+
}
|
|
1714
|
+
else if (failure !== null) {
|
|
1715
|
+
last.worst = report(last, failure);
|
|
1716
|
+
}
|
|
1717
|
+
}
|
|
1718
|
+
cursor = until;
|
|
1719
|
+
}
|
|
1720
|
+
}
|
|
1721
|
+
return violations.map((violation) => violation.worst);
|
|
1722
|
+
}
|
|
1723
|
+
/**
|
|
1724
|
+
* Every violation of the rules whose severity is `"violation"` inside a range. A moving window's
|
|
1725
|
+
* failures are one violation while no check passes between them; a count since a reset, or one
|
|
1726
|
+
* fixed period, is one violation however often it is checked. Each is reported by its worst
|
|
1727
|
+
* window and listed in the range it began in.
|
|
1728
|
+
*
|
|
1729
|
+
* @param context the call's context
|
|
1730
|
+
* @param rules the resolved rules
|
|
1731
|
+
* @param range the range, epoch nanoseconds
|
|
1732
|
+
* @returns the violations, ordered by window start and then by rule
|
|
1733
|
+
*/
|
|
1734
|
+
export function scanDutyViolations(context, rules, range) {
|
|
1735
|
+
const found = [];
|
|
1736
|
+
rules.forEach((rule, order) => {
|
|
1737
|
+
if (rule.severity === "violation") {
|
|
1738
|
+
for (const failure of ruleViolations(context, rule, range)) {
|
|
1739
|
+
found.push({ order, label: rule.label, failure });
|
|
1740
|
+
}
|
|
1741
|
+
}
|
|
1742
|
+
});
|
|
1743
|
+
return found
|
|
1744
|
+
.sort((a, b) => {
|
|
1745
|
+
const aStart = a.failure.evaluation.window.start;
|
|
1746
|
+
const bStart = b.failure.evaluation.window.start;
|
|
1747
|
+
return aStart < bStart ? -1 : aStart > bStart ? 1 : a.order - b.order;
|
|
1748
|
+
})
|
|
1749
|
+
.map(({ label, failure }) => ({
|
|
1750
|
+
label,
|
|
1751
|
+
window: spanText(failure.evaluation.window),
|
|
1752
|
+
used: measureText(failure.evaluation.used),
|
|
1753
|
+
limit: measureText(failure.evaluation.limit),
|
|
1754
|
+
}));
|
|
1755
|
+
}
|