import { type IndexRef, type Maybe, type TimezoneString, type Minutes, type FractionalHour, type TimezoneStringRef, type ISO8601DayString } from '@dereekb/util'; import { type DateRange, type DateRangeDayDistanceInput } from './date.range'; import { type DateDurationSpan } from './date.duration'; import { type DateTimezoneUtcNormalFunctionInput, type DateTimezoneUtcNormalInstance } from './date.timezone'; /** * Index from 0 of which day this block represents. * * It is easiest to think of DateCellIndexes as days on a calendar. An index of 0 means the entire first day for that timezone. * * It is not the time from the startsAt time to the endsAt time for a period. * * @semanticType * @semanticTopic numeric * @semanticTopic reference * @semanticTopic dereekb-date:cell */ export type DateCellIndex = number; /** * Returns true if the index is a non-negative integer, which is required for valid date cell indexing. * * @param input - The index to validate. * @returns Whether the input is a valid date cell index (>= 0 and an integer) * * @example * ```ts * isValidDateCellIndex(0); // true * isValidDateCellIndex(5); // true * isValidDateCellIndex(-1); // false * isValidDateCellIndex(0.5); // false * ``` */ export declare function isValidDateCellIndex(input: DateCellIndex): boolean; /** * Input type that is either a Date or a DateCellIndex. */ export type DateOrDateCellIndex = Date | DateCellIndex; /** * A date and the relative date index. */ export interface DateCellIndexDatePair extends Readonly { readonly date: Date; } /** * A duration-span block. */ export interface DateCell extends IndexRef { i: DateCellIndex; } /** * Normalizes a number or {@link DateCell} to a DateCell object. * * @param dateCellOrIndex - A numeric index or existing DateCell. * @returns A DateCell object with the `i` property set. * * @example * ```ts * dateCell(3); // { i: 3 } * dateCell({ i: 3 }); // { i: 3 } (returned as-is) * ``` */ export declare function dateCell(dateCellOrIndex: DateCellIndex | DateCell): DateCell; /** * An array of DateCell-like values. */ export type DateCellArray = B[]; /** * Reference to a DateCellArray */ export type DateCellArrayRef = { blocks: DateCellArray; }; /** * The DateCellTimingStartsAt and startsAt times and timezone. * * Used to derive the indexes for the days. */ export type DateCellTimingStartsAt = Pick; /** * Input for dateCellTimingStartsAtForStartOfDay() */ export interface DateCellTimingStartsAtForStartOfDayInput { /** * "Now" date in the system timezone normal. */ readonly now?: Date | ISO8601DayString; /** * Timezone string */ readonly timezone?: TimezoneString; } /** * Creates a {@link DateCellTimingStartsAt} positioned at the start of the current day in the given timezone. * * Useful for initializing a timing range that begins "today" in a particular timezone. * * @param input - Optional timezone and "now" override. * @returns A DateCellTimingStartsAt with startsAt at midnight and the resolved timezone. * * @example * ```ts * const timing = dateCellTimingStartsAtForStartOfDay({ timezone: 'America/Denver' }); * // timing.startsAt is midnight today in Denver, timing.timezone === 'America/Denver' * ``` */ export declare function dateCellTimingStartsAtForStartOfDay(input?: DateCellTimingStartsAtForStartOfDayInput): DateCellTimingStartsAt; /** * The DateCellTimingEnd and endsAt times and timezone. */ export type DateCellTimingEnd = Pick; /** * Is combination of DateRange and DateDurationSpan. The DateRange captures a range of days that a DateCell takes up, and the DateDurationSpan * captures the Dates at which the Job occurs at. * * NOTES: * - The startsAt time is the time of the first event. * - The end time is the ending date/time of the final end duration. * - The timezone is required to properly handle daylight savings and timezone differences. */ export interface DateCellTiming extends DateDurationSpan, TimezoneStringRef, Pick { } /** * Corresponds to the range of dates in a DateCellTiming. * * NOTES: * - The start time is midnight in the given timezone of the first day of the range. * - The end time is the ending date/time of the final end duration. * - The timezone is required to properly handle daylight savings and timezone differences. */ export interface DateCellTimingDateRange extends DateRange, TimezoneStringRef { } /** * A DateCellTimingDateRange, but the start time is the startsAt time for the first event. */ export type DateCellTimingEventRange = DateCellTimingDateRange; /** * Reference to a DateCellTiming */ export interface DateCellTimingRef { timing: DateCellTiming; } /** * An object that implements DateCellTimingRef and DateCellArrayRef */ export interface DateCellCollection extends DateCellTimingRef, DateCellArrayRef { } /** * An expanded DateCell that implements DateDurationSpan and contains the DateCell values. */ export type DateCellDurationSpan = DateDurationSpan & B; /** * The DateRange input for dateCellTiming() */ export type DateCellTimingRangeInput = DateRangeDayDistanceInput | DateRange | number; /** * Can use any timezone instance that has a timezone configured, or is using the */ export type DateCellTimingTimezoneInput = Omit; /** * Creates a {@link DateTimezoneUtcNormalInstance} from the input, guaranteeing that a timezone string is configured. * * Falls back to the system timezone if no input is provided. * * @param timezoneInput - Timezone configuration or undefined for system timezone. * @returns A DateTimezoneUtcNormalInstance with a guaranteed configured timezone. * @throws {Error} When the timezone cannot be resolved to a known timezone string. * * @example * ```ts * const instance = dateCellTimingTimezoneNormalInstance('America/Denver'); * instance.configuredTimezoneString; // 'America/Denver' * ``` */ export declare function dateCellTimingTimezoneNormalInstance(timezoneInput?: DateCellTimingTimezoneInput): DateTimezoneUtcNormalInstance; /** * A DateCellTiming that also implements DateCellTimingDateRange. */ export interface FullDateCellTiming extends DateCellTiming, DateCellTimingDateRange { } /** * The start date within a FullDateCellTiming. */ export type FullDateCellTimingStart = Pick; /** * Derives a {@link FullDateCellTiming} from a {@link DateCellTiming} by computing the `start` date (midnight in the timing's timezone). * * @param timing - The base timing to expand. * @returns The timing with the `start` field populated. * * @example * ```ts * const timing: DateCellTiming = { startsAt, end, duration: 60, timezone: 'America/Denver' }; * const full = fullDateCellTiming(timing); * // full.start is midnight for the startsAt day in Denver * ``` */ export declare function fullDateCellTiming(timing: DateCellTiming): FullDateCellTiming; export interface FullDateCellTimingTimezonePair { readonly fullTiming: FullDateCellTiming; readonly normalInstance: DateTimezoneUtcNormalInstance; } /** * Creates a {@link FullDateCellTimingTimezonePair} containing both the expanded timing and the timezone normal instance. * * Useful when both the full timing and the timezone conversion utilities are needed together. * * @param timing - The base timing to expand. * @returns The full timing paired with its timezone normal instance. */ export declare function fullDateCellTimingTimezonePair(timing: DateCellTiming): FullDateCellTimingTimezonePair; /** * Validates that a date has zero minutes, seconds, and milliseconds, which is required for a valid DateCellTiming start date (midnight in the target timezone). * * @param date - The start date to validate. * @returns Whether the date is at a valid hour boundary. * * @example * ```ts * isValidDateCellTimingStartDate(new Date('2024-01-01T06:00:00.000Z')); // true * isValidDateCellTimingStartDate(new Date('2024-01-01T06:30:00.000Z')); // false * ``` */ export declare function isValidDateCellTimingStartDate(date: Date): boolean; /** * Creates a valid DateCell timing from the DateDurationSpan and range input. * * The duration is first considered, then the date range is applied to it. * * If a number is passed as the input range, then the duration's startsAt date will be used and the input number used as the distance. * The input range's date takes priority over the duration's startsAt start date, meaning the input date range will be adapted * to fit the startsAt time. * * The input range date is used as the start and end date ranges, meaning they will be used as the expected date offset (have only hours, no minutes/seconds/milliseconds) and be validated as such. * The end date is used just to determine the number of days, but a minimum of 1 day is always enforced as a DateCellTiming must contain atleast 1 day. * * The start date from the inputDate is considered to to have the offset noted in DateCell, and will be retained. * * @param durationInput - The duration span containing the startsAt time and event duration in minutes. * @param rangeInput - Specifies the date range: a number of days, a DateRange, or a DateRangeDayDistanceInput. * @param timezoneInput - Optional timezone configuration; defaults to the system timezone if omitted. * @returns A fully computed FullDateCellTiming with start, startsAt, end, duration, and timezone. * @throws {Error} When `durationInput.duration` exceeds 24 hours. */ export declare function dateCellTiming(durationInput: DateDurationSpan, rangeInput: DateCellTimingRangeInput, timezoneInput?: DateCellTimingTimezoneInput): FullDateCellTiming; export interface DateCellTimingStartPair { readonly start: Date; readonly normalInstance: DateTimezoneUtcNormalInstance; } /** * Computes the start-of-day date for a timing and returns it paired with the timezone normal instance. * * @param timing - Timing with startsAt and timezone. * @returns The midnight start date and the timezone normal instance used to compute it. */ export declare function dateCellTimingStartPair(timing: DateCellTimingStartsAt): DateCellTimingStartPair; /** * Computes the start-of-day (midnight) date for a {@link DateCellTimingStartsAt} in its configured timezone. * * @param timing - Timing with startsAt and timezone. * @returns The midnight Date for the timing's first day in its timezone. */ export declare function dateCellTimingStart(timing: DateCellTimingStartsAt): Date; /** * The DateRange component and timezone for a DateCellTiming. The start date is a DateCellTimingStartsAt. */ export type DateCellTimingStartsAtEndRange = Pick; /** * The startsAt time of the event. */ export type DateCellTimingEventStartsAt = Pick; /** * A startsAt time and duration that represents a single event. */ export type DateCellTimingEvent = Pick; /** * Null-safe equality check for two {@link DateCellTimingStartsAtEndRange} values, comparing timezone, startsAt, and end. * * @param a - First range. * @param b - Second range. * @returns Whether the two ranges are equivalent. */ export declare function isSameDateCellTimingEventStartsAtEndRange(a: Maybe, b: Maybe): boolean; /** * Null-safe equality check for two {@link DateCellTiming} values, comparing duration and the starts-at/end range. * * @param a - First timing. * @param b - Second timing. * @returns Whether the two timings are equivalent. */ export declare function isSameDateCellTiming(a: Maybe, b: Maybe): boolean; /** * Strict equality check for {@link FullDateCellTiming} values, including the derived `start` date. * * In most cases {@link isSameDateCellTiming} is sufficient since `start` is derived from `startsAt`. * * @param a - First full timing. * @param b - Second full timing. * @returns Whether all fields are exactly equal. */ export declare function isSameFullDateCellTiming(a: Maybe, b: Maybe): boolean; /** * Type guard that checks whether the input has the shape of a {@link DateCellTiming} (startsAt, end, timezone, duration). * * Does not validate correctness (e.g. end after start). Use {@link isValidDateCellTiming} for validation. * * @param input - Value to check. * @returns Whether the input matches the DateCellTiming shape. */ export declare function isDateCellTiming(input: unknown): input is DateCellTiming; /** * Type guard that checks whether the input has the shape of a {@link FullDateCellTiming} (includes `start` field plus all DateCellTiming fields). * * Does not validate correctness. Use {@link isValidFullDateCellTiming} for validation. * * @param input - Value to check. * @returns Whether the input matches the FullDateCellTiming shape. */ export declare function isFullDateCellTiming(input: unknown): input is FullDateCellTiming; /** * Derives a {@link DateCellTimingDateRange} from a timing, using midnight in the timing's timezone as the start and the event's end time as the end. * * @param timing - Timing with startsAt, end, and timezone. * @returns Date range spanning from midnight of the first day to the end of the last event. */ export declare function dateCellTimingDateRange(timing: DateCellTimingStartsAtEndRange): DateCellTimingDateRange; /** * Returns a {@link DateCellTimingEventRange} spanning from the first event's startsAt to the last event's end time. * * Unlike {@link dateCellTimingDateRange}, the start is the event time rather than midnight. * * @param timing - Timing with startsAt, end, and timezone. * @returns The event range. */ export declare function dateCellTimingEventRange(timing: Pick): DateCellTimingEventRange; /** * Returns the date range of the first event only (from startsAt to startsAt + duration). * * @param timing - Timing to extract the first event from. * @returns Date range of the first event. */ export declare function getDateCellTimingFirstEventDateRange(timing: DateCellTimingStartsAtEndRange): DateRange; /** * Converts a timing's duration from minutes to fractional hours. * * @param timing - Timing with a duration in minutes. * @returns The duration expressed as fractional hours (e.g. 90 minutes = 1.5) */ export declare function getDateCellTimingHoursInEvent(timing: Pick): FractionalHour; /** * Returns a copy of the input timing with the start date adjusted and the new timezone set. * * The startsAt time remains the same, while the end date may be updated to reflect timezone differences. */ export type UpdateDateCellTimingToTimezoneFunction = ((timing: T) => T & FullDateCellTiming) & { readonly _timezone: TimezoneString; }; /** * Creates a function that updates a timing's timezone and recalculates the `start` date, while preserving the original `startsAt` instant. * * The event occurs at the same absolute moment in time, but is now associated with a different timezone. * * @param timezone - IANA timezone to associate with future timings. * @returns Updater that rebinds timings to the configured timezone. * * @__NO_SIDE_EFFECTS__ */ export declare function updateDateCellTimingToTimezoneFunction(timezone: TimezoneString): UpdateDateCellTimingToTimezoneFunction; /** * Updates the timing's timezone to the system timezone while preserving the absolute startsAt instant. * * @param timing - Timing to update. * @returns The timing with the system timezone applied. */ export declare function updateDateCellTimingToSystemTimezone(timing: T): T; /** * Updates the timing's timezone to UTC while preserving the absolute startsAt instant. * * @param timing - Timing to update. * @returns The timing with UTC timezone applied. */ export declare function updateDateCellTimingToUTCTimezone(timing: T): T; /** * Updates a timing's timezone while preserving the absolute startsAt instant. * * Shorthand for creating an {@link updateDateCellTimingToTimezoneFunction} and immediately invoking it. * * @param timing - Timing to update. * @param timezone - The new IANA timezone. * @returns The timing with the new timezone applied. */ export declare function updateDateCellTimingToTimezone(timing: T, timezone: TimezoneString): T; /** * Returns a copy of the input timing adjusted for the input timezone and all FullDateCellTiming values updated to reflect the changes. * * The startsAt and end times are adjusted to match the same "time" in the new timezone. I.E: A timing of 8AM UTC that is converted to America/Denver would be converted to 8AM America/Denver. * * @param timing */ export type ShiftDateCellTimingToTimezoneFunction = ((timing: T) => T & FullDateCellTiming) & { readonly _normalInstance: DateTimezoneUtcNormalInstance; }; /** * Creates a function that shifts a timing's startsAt and end to represent the same "wall clock time" in a new timezone. * * Unlike {@link updateDateCellTimingToTimezoneFunction}, which preserves the absolute instant, this shifts the absolute times * so the local time appearance remains the same (e.g. 8AM UTC becomes 8AM Denver). * * @param timezoneInput - Destination timezone for the wall-clock shift. * @returns Shifter that rewrites timings to keep wall-clock time in the new timezone. * * @__NO_SIDE_EFFECTS__ */ export declare function shiftDateCellTimingToTimezoneFunction(timezoneInput: DateCellTimingTimezoneInput): ShiftDateCellTimingToTimezoneFunction; /** * Shifts a timing to the system timezone, preserving the wall clock time appearance. * * @param timing - Timing to shift. * @returns The timing shifted to the system timezone. */ export declare function shiftDateCellTimingToSystemTimezone(timing: T): T; /** * Shifts a timing to UTC, preserving the wall clock time appearance. * * @param timing - Timing to shift. * @returns The timing shifted to UTC. */ export declare function shiftDateCellTimingToUTCTimezone(timing: T): T; /** * Shifts a timing to a new timezone, preserving the wall clock time appearance. * * Shorthand for creating a {@link shiftDateCellTimingToTimezoneFunction} and immediately invoking it. * * @param timing - Timing to shift. * @param timezone - The target timezone. * @returns The timing shifted to the new timezone. */ export declare function shiftDateCellTimingToTimezone(timing: T, timezone: DateCellTimingTimezoneInput): T; export interface CalculateExpectedDateCellTimingDurationPair { readonly duration: Minutes; readonly expectedFinalStartsAt: Date; } /** * Calculates the expected duration and the final event's startsAt from a timing range, accounting for DST transitions. * * @param timing - The timing range to analyze. * @returns The computed duration in minutes and the expected startsAt of the last event. */ export declare function calculateExpectedDateCellTimingDurationPair(timing: DateCellTimingStartsAtEndRange): CalculateExpectedDateCellTimingDurationPair; /** * Calculates the expected event duration in minutes from a timing range by analyzing the gap between startsAt and end. * * @param timing - The timing range to analyze. * @returns The duration in minutes. */ export declare function calculateExpectedDateCellTimingDuration(timing: DateCellTimingStartsAtEndRange): Minutes; /** * Converts a {@link DateCellTimingStartsAtEndRange} to a full {@link DateCellTiming} by computing the duration from the range. * * @param timing - The starts-at/end range to convert. * @returns A DateCellTiming with the calculated duration. */ export declare function dateCellTimingFromDateCellTimingStartsAtEndRange(timing: DateCellTimingStartsAtEndRange): DateCellTiming; /** * Computes the startsAt time and duration for the final event in a timing range. * * @param timing - The timing range to analyze. * @returns A DateCellTimingEvent representing the last scheduled event. */ export declare function dateCellTimingFinalStartsAtEvent(timing: DateCellTimingStartsAtEndRange): DateCellTimingEvent; /** * Detailed validation result for a {@link DateCellTiming}, with individual boolean flags for each validation rule. */ export interface IsValidDateCellTimingInfo { readonly isValid: boolean; readonly startsAtHasZeroSeconds: boolean; readonly endIsAfterTheStartsAtTime: boolean; readonly durationGreaterThanZero: boolean; readonly durationLessThan24Hours: boolean; readonly isExpectedValidEnd: boolean; readonly normalInstance: DateTimezoneUtcNormalInstance; } /** * Performs detailed validation of a {@link DateCellTiming}, returning an info object with individual check results. * * Validates that end is after startsAt, duration is within bounds, startsAt has no fractional seconds, and the computed duration matches the expected value. * * @param timing - The timing to validate. * @returns Detailed validation info with individual boolean flags. */ export declare function isValidDateCellTimingInfo(timing: DateCellTiming): IsValidDateCellTimingInfo; /** * Returns true if the {@link DateCellTiming} passes all validation checks. * * Shorthand for {@link isValidDateCellTimingInfo} when only the boolean result is needed. * * @param timing - The timing to validate. * @returns Whether the timing is valid. */ export declare function isValidDateCellTiming(timing: DateCellTiming): boolean; /** * Extended validation result for a {@link FullDateCellTiming}, adding checks for the derived `start` date alignment. */ export interface IsValidFullDateCellTimingInfo extends IsValidDateCellTimingInfo { readonly isStartRoundedToSeconds: boolean; readonly startIsAtMidnight: boolean; readonly startHasZeroSeconds: boolean; readonly startsAtIsAfterStart: boolean; readonly startsAtIsLessThan24HoursAfterStart: boolean; } /** * Performs detailed validation of a {@link FullDateCellTiming}, including all {@link isValidDateCellTimingInfo} checks * plus additional checks that the `start` date is at midnight and properly aligned with `startsAt`. * * @param timing - The full timing to validate. * @returns Detailed validation info with individual boolean flags. */ export declare function isValidFullDateCellTimingInfo(timing: FullDateCellTiming): IsValidFullDateCellTimingInfo; /** * Returns true if the {@link FullDateCellTiming} passes all validation checks, including start date alignment. * * Shorthand for {@link isValidFullDateCellTimingInfo} when only the boolean result is needed. * * @param timing - The full timing to validate. * @returns Whether the timing is valid. */ export declare function isValidFullDateCellTiming(timing: FullDateCellTiming): boolean;