1 | import { CanBeInvalid, DefaultValidity, IfValid, Invalid, Valid } from "./_util";
|
2 | import {
|
3 | _UseLocaleWeekOption,
|
4 | DateObjectUnits,
|
5 | DateTime,
|
6 | DateTimeOptions,
|
7 | DiffOptions,
|
8 | LocaleOptions,
|
9 | ToISOTimeOptions,
|
10 | } from "./datetime";
|
11 | import { Duration, DurationLike, DurationMaybeValid, DurationUnit } from "./duration";
|
12 |
|
13 | export interface IntervalObject {
|
14 | start?: DateTime | undefined;
|
15 | end?: DateTime | undefined;
|
16 | }
|
17 |
|
18 | export type DateInput = DateTime | DateObjectUnits | Date;
|
19 |
|
20 | export type IntervalMaybeValid = CanBeInvalid extends true ? (Interval<Valid> | Interval<Invalid>) : Interval;
|
21 |
|
22 | export type CountOptions = _UseLocaleWeekOption;
|
23 |
|
24 | /**
|
25 | * An Interval object represents a half-open interval of time, where each endpoint is a {@link DateTime}.
|
26 | * Conceptually, it is a container for those two endpoints, accompanied by methods for
|
27 | * creating, parsing, interrogating, comparing, transforming, and formatting them.
|
28 | *
|
29 | * Here is a brief overview of the most commonly used methods and getters in Interval:
|
30 | *
|
31 | * * **Creation** To create an Interval, use {@link Interval.fromDateTimes}, {@link Interval.after}, {@link Interval.before}, or {@link Interval.fromISO}.
|
32 | * * **Accessors** Use {@link Interval#start} and {@link Interval#end} to get the start and end.
|
33 | * * **Interrogation** To analyze the Interval, use {@link Interval#count}, {@link Interval#length}, {@link Interval#hasSame},
|
34 | * * {@link Interval#contains}, {@link Interval#isAfter}, or {@link Interval#isBefore}.
|
35 | * * **Transformation** To create other Intervals out of this one, use {@link Interval#set}, {@link Interval#splitAt}, {@link Interval#splitBy}, {@link Interval#divideEqually},
|
36 | * * {@link Interval.merge}, {@link Interval.xor}, {@link Interval#union}, {@link Interval#intersection}, or {@link Interval#difference}.
|
37 | * * **Comparison** To compare this Interval to another one, use {@link Interval#equals}, {@link Interval#overlaps}, {@link Interval#abutsStart}, {@link Interval#abutsEnd}, {@link Interval#engulfs}
|
38 | * * **Output** To convert the Interval into other representations, see {@link Interval#toString}, {@link Interval#toLocaleString}, {@link Interval#toISO}, {@link Interval#toISODate},
|
39 | * * {@link Interval#toISOTime}, {@link Interval#toFormat}, and {@link Interval#toDuration}.
|
40 | */
|
41 | export class Interval<IsValid extends boolean = DefaultValidity> {
|
42 | /**
|
43 | * Create an invalid Interval.
|
44 | *
|
45 | * @param reason - simple string of why this Interval is invalid. Should not contain parameters or anything else data-dependent
|
46 | * @param explanation - longer explanation, may include parameters and other useful debugging information.
|
47 | */
|
48 | static invalid(reason: string, explanation?: string): Interval<Invalid>;
|
49 |
|
50 | /**
|
51 | * Create an Interval from a start DateTime and an end DateTime. Inclusive of the start but not the end.
|
52 | *
|
53 | * @param start
|
54 | * @param end
|
55 | */
|
56 | static fromDateTimes(start: DateInput, end: DateInput): IntervalMaybeValid;
|
57 |
|
58 | /**
|
59 | * Create an Interval from a start DateTime and a Duration to extend to.
|
60 | *
|
61 | * @param start
|
62 | * @param duration - the length of the Interval.
|
63 | */
|
64 | static after(start: DateInput, duration: DurationLike): IntervalMaybeValid;
|
65 |
|
66 | /**
|
67 | * Create an Interval from an end DateTime and a Duration to extend backwards to.
|
68 | *
|
69 | * @param end
|
70 | * @param duration - the length of the Interval.
|
71 | */
|
72 | static before(end: DateInput, duration: DurationLike): IntervalMaybeValid;
|
73 |
|
74 | /**
|
75 | * Create an Interval from an ISO 8601 string.
|
76 | * Accepts `<start>/<end>`, `<start>/<duration>`, and `<duration>/<end>` formats.
|
77 | * @see https://en.wikipedia.org/wiki/ISO_8601#Time_intervals
|
78 | *
|
79 | * @param text - the ISO string to parse
|
80 | * @param opts - options to pass {@link DateTime.fromISO} and optionally {@link Duration.fromISO}
|
81 | */
|
82 | static fromISO(text: string, opts?: DateTimeOptions): IntervalMaybeValid;
|
83 |
|
84 | /**
|
85 | * Check if an object is an Interval. Works across context boundaries
|
86 | *
|
87 | * @param o
|
88 | */
|
89 | static isInterval(o: unknown): o is IntervalMaybeValid;
|
90 |
|
91 | private constructor(config: unknown);
|
92 |
|
93 | /**
|
94 | * Returns the start of the Interval
|
95 | */
|
96 | get start(): IfValid<DateTime<Valid>, null, IsValid>;
|
97 |
|
98 | /**
|
99 | * Returns the end of the Interval
|
100 | */
|
101 | get end(): IfValid<DateTime<Valid>, null, IsValid>;
|
102 |
|
103 | /**
|
104 | * Returns whether this Interval's end is at least its start, meaning that the Interval isn't 'backwards'.
|
105 | */
|
106 | get isValid(): IfValid<true, false, IsValid>;
|
107 |
|
108 | /**
|
109 | * Returns an error code if this Interval is invalid, or null if the Interval is valid
|
110 | */
|
111 | get invalidReason(): IfValid<null, string, IsValid>;
|
112 |
|
113 | /**
|
114 | * Returns an explanation of why this Interval became invalid, or null if the Interval is valid
|
115 | */
|
116 | get invalidExplanation(): IfValid<null, string | null, IsValid>;
|
117 |
|
118 | /**
|
119 | * Returns the length of the Interval in the specified unit.
|
120 | *
|
121 | * @param unit - the unit (such as 'hours' or 'days') to return the length in.
|
122 | */
|
123 | length(unit?: DurationUnit): IfValid<number, typeof NaN, IsValid>;
|
124 |
|
125 | /**
|
126 | * Returns the count of minutes, hours, days, months, or years included in the Interval, even in part.
|
127 | * Unlike {this counts sections of the calendar, not periods of time, e.g. specifying 'day'
Interval#length} |
128 | * asks 'what dates are included in this interval?', not 'how many days long is this interval?'
|
129 | *
|
130 | * 'milliseconds'.
unit - the unit of time to count. Defaults to |
131 | */
|
132 | count(unit?: DurationUnit, opts?: CountOptions): IfValid<number, typeof NaN, IsValid>;
|
133 |
|
134 | /**
|
135 | * Returns whether this Interval's start and end are both in the same unit of time
|
136 | *
|
137 | * @param unit - the unit of time to check sameness on
|
138 | */
|
139 | hasSame(unit: DurationUnit): IfValid<boolean, false, IsValid>;
|
140 |
|
141 | /**
|
142 | * Return whether this Interval has the same start and end DateTimes.
|
143 | */
|
144 | isEmpty(): boolean;
|
145 |
|
146 | /**
|
147 | * Return whether this Interval's start is after the specified DateTime.
|
148 | *
|
149 | * @param dateTime
|
150 | */
|
151 | isAfter(dateTime: DateTime): IfValid<boolean, false, IsValid>;
|
152 |
|
153 | /**
|
154 | * Return whether this Interval's end is before the specified DateTime.
|
155 | *
|
156 | * @param dateTime
|
157 | */
|
158 | isBefore(dateTime: DateTime): IfValid<boolean, false, IsValid>;
|
159 |
|
160 | /**
|
161 | * Return whether this Interval contains the specified DateTime.
|
162 | *
|
163 | * @param dateTime
|
164 | */
|
165 | contains(dateTime: DateTime): IfValid<boolean, false, IsValid>;
|
166 |
|
167 | /**
|
168 | * "Sets" the start and/or end dates. Returns a newly-constructed Interval.
|
169 | *
|
170 | * @param values - the values to set
|
171 | * @param values.start - the starting DateTime
|
172 | * @param values.end - the ending DateTime
|
173 | */
|
174 | set(values?: IntervalObject): IntervalMaybeValid;
|
175 |
|
176 | /**
|
177 | * Split this Interval at each of the specified DateTimes
|
178 | *
|
179 | * @param dateTimes - the unit of time to count.
|
180 | */
|
181 | splitAt(...dateTimes: DateTime[]): IfValid<Interval[], [], IsValid>;
|
182 |
|
183 | /**
|
184 | * Split this Interval into smaller Intervals, each of the specified length.
|
185 | * Left over time is grouped into a smaller interval
|
186 | *
|
187 | * @param duration - The length of each resulting interval.
|
188 | */
|
189 | splitBy(duration: DurationLike): IfValid<Interval[], [], IsValid>;
|
190 |
|
191 | /**
|
192 | * Split this Interval into the specified number of smaller intervals.
|
193 | *
|
194 | * @param numberOfParts - The number of Intervals to divide the Interval into.
|
195 | */
|
196 | divideEqually(numberOfParts: number): IfValid<Interval[], [], IsValid>;
|
197 |
|
198 | /**
|
199 | * Return whether this Interval overlaps with the specified Interval
|
200 | */
|
201 | overlaps(other: Interval): boolean;
|
202 |
|
203 | /**
|
204 | * Return whether this Interval's end is adjacent to the specified Interval's start.
|
205 | */
|
206 | abutsStart(other: Interval): IfValid<boolean, false, IsValid>;
|
207 |
|
208 | /**
|
209 | * Return whether this Interval's start is adjacent to the specified Interval's end.
|
210 | */
|
211 | abutsEnd(other: Interval): IfValid<boolean, false, IsValid>;
|
212 |
|
213 | /**
|
214 | * Return whether this Interval engulfs the start and end of the specified Interval.
|
215 | */
|
216 | engulfs(other: Interval): IfValid<boolean, false, IsValid>;
|
217 |
|
218 | /**
|
219 | * Return whether this Interval has the same start and end as the specified Interval.
|
220 | */
|
221 | equals(other: Interval): IfValid<boolean, false, IsValid>;
|
222 |
|
223 | /**
|
224 | * Return an Interval representing the intersection of this Interval and the specified Interval.
|
225 | * Specifically, the resulting Interval has the maximum start time and the minimum end time of the two Intervals.
|
226 | * Returns null if the intersection is empty, meaning the intervals do not intersect.
|
227 | */
|
228 | intersection(other: Interval): Interval | null;
|
229 |
|
230 | /**
|
231 | * Return an Interval representing the union of this Interval and the specified Interval.
|
232 | * Specifically, the resulting Interval has the minimum start time and the maximum end time of the two Intervals.
|
233 | */
|
234 | union(other: Interval): IntervalMaybeValid;
|
235 |
|
236 | /**
|
237 | * Merge an array of Intervals into an equivalent minimal set of Intervals.
|
238 | * Combines overlapping and adjacent Intervals.
|
239 | */
|
240 | static merge(intervals: Interval[]): IntervalMaybeValid[];
|
241 |
|
242 | /**
|
243 | * Return an array of Intervals representing the spans of time that only appear in one of the specified Intervals.
|
244 | */
|
245 | static xor(intervals: Interval[]): IntervalMaybeValid[];
|
246 |
|
247 | /**
|
248 | * Return Intervals representing the spans of time in this Interval that not overlap with any of the specified Intervals.
|
249 | */
|
250 | difference(...intervals: Interval[]): IntervalMaybeValid[];
|
251 |
|
252 | /**
|
253 | * Returns a string representation of this Interval appropriate for debugging.
|
254 | */
|
255 | toString(): IfValid<string, "Invalid Interval", IsValid>;
|
256 |
|
257 | /**
|
258 | * Returns a localized string representing this Interval. Accepts the same options as the
|
259 | * Intl.DateTimeFormat constructor and any presets defined by Luxon, such as
|
260 | * {@link DateTime.DATE_FULL} or {@link DateTime.TIME_SIMPLE}. The exact behavior of this method
|
261 | * is browser-specific, but in general it will return an appropriate representation of the
|
262 | * Interval in the assigned locale. Defaults to the system's locale if no locale has been
|
263 | * specified.
|
264 | * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat
|
265 | * @param formatOpts - Either a DateTime preset or Intl.DateTimeFormat constructor options. Defaults to DateTime.DATE_SHORT
|
266 | * @param opts - Options to override the configuration of the start DateTime.
|
267 | *
|
268 | * @example
|
269 | * Interval.fromISO('2022-11-07T09:00Z/2022-11-08T09:00Z').toLocaleString(); //=> 11/7/2022 – 11/8/2022
|
270 | * @example
|
271 | * Interval.fromISO('2022-11-07T09:00Z/2022-11-08T09:00Z').toLocaleString(DateTime.DATE_FULL); //=> November 7 – 8, 2022
|
272 | * @example
|
273 | * Interval.fromISO('2022-11-07T09:00Z/2022-11-08T09:00Z').toLocaleString(DateTime.DATE_FULL, { locale: 'fr-FR' }); //=> 7–8 novembre 2022
|
274 | * @example
|
275 | * Interval.fromISO('2022-11-07T17:00Z/2022-11-07T19:00Z').toLocaleString(DateTime.TIME_SIMPLE); //=> 6:00 – 8:00 PM
|
276 | * @example
|
277 | * Interval.fromISO("2022-11-07T17:00Z/2022-11-07T19:00Z").toLocaleString({
|
278 | * weekday: "short",
|
279 | * month: "short",
|
280 | * day: "2-digit",
|
281 | * hour: "2-digit",
|
282 | * minute: "2-digit",
|
283 | * }); //=> Mon, Nov 07, 6:00 – 8:00 p
|
284 | */
|
285 | toLocaleString(
|
286 | formatOpts?: Intl.DateTimeFormatOptions,
|
287 | opts?: LocaleOptions,
|
288 | ): IfValid<string, "Invalid Interval", IsValid>;
|
289 |
|
290 | /**
|
291 | * Returns an ISO 8601-compliant string representation of this Interval.
|
292 | * @see https://en.wikipedia.org/wiki/ISO_8601#Time_intervals
|
293 | *
|
294 | * @param opts - The same options as {@link DateTime#toISO}
|
295 | */
|
296 | toISO(opts?: ToISOTimeOptions): IfValid<string, "Invalid Interval", IsValid>;
|
297 |
|
298 | /**
|
299 | * Returns an ISO 8601-compliant string representation of the dates in this Interval.
|
300 | * The time components are ignored.
|
301 | * @see https://en.wikipedia.org/wiki/ISO_8601#Time_intervals
|
302 | */
|
303 | toISODate(): IfValid<string, "Invalid Interval", IsValid>;
|
304 |
|
305 | /**
|
306 | * Returns an ISO 8601-compliant string representation of the times in this Interval.
|
307 | * The date components are ignored.
|
308 | * @see https://en.wikipedia.org/wiki/ISO_8601#Time_intervals
|
309 | *
|
310 | * @param opts - The same options as {@link DateTime.toISO}
|
311 | */
|
312 | toISOTime(opts?: ToISOTimeOptions): IfValid<string, "Invalid Interval", IsValid>;
|
313 |
|
314 | /**
|
315 | * Returns a string representation of this Interval formatted according to the specified format string.
|
316 | *
|
317 | * @param dateFormat - the format string. This string formats the start and end time. See {@link DateTime.toFormat} for details.
|
318 | * @param opts - options
|
319 | * @param opts.separator - a separator to place between the start and end representations. Defaults to ' - '.
|
320 | */
|
321 | toFormat(
|
322 | dateFormat: string,
|
323 | opts?: {
|
324 | separator?: string | undefined;
|
325 | },
|
326 | ): IfValid<string, "Invalid Interval", IsValid>;
|
327 |
|
328 | /**
|
329 | * Return a Duration representing the time spanned by this interval.
|
330 | *
|
331 | * @param unit - the unit or units (such as 'hours' or 'days') to include in the duration. Defaults to ['milliseconds'].
|
332 | * @param opts - options that affect the creation of the Duration
|
333 | * @param opts.conversionAccuracy - the conversion system to use. Defaults to 'casual'.
|
334 | *
|
335 | * @example
|
336 | * Interval.fromDateTimes(dt1, dt2).toDuration().toObject() //=> { milliseconds: 88489257 }
|
337 | * @example
|
338 | * Interval.fromDateTimes(dt1, dt2).toDuration('days').toObject() //=> { days: 1.0241812152777778 }
|
339 | * @example
|
340 | * Interval.fromDateTimes(dt1, dt2).toDuration(['hours', 'minutes']).toObject() //=> { hours: 24, minutes: 34.82095 }
|
341 | * @example
|
342 | * Interval.fromDateTimes(dt1, dt2).toDuration(['hours', 'minutes', 'seconds']).toObject() //=> { hours: 24, minutes: 34, seconds: 49.257 }
|
343 | * @example
|
344 | * Interval.fromDateTimes(dt1, dt2).toDuration('seconds').toObject() //=> { seconds: 88489.257 }
|
345 | */
|
346 | toDuration(unit?: DurationUnit | DurationUnit[], opts?: DiffOptions): DurationMaybeValid;
|
347 |
|
348 | /**
|
349 | * Run mapFn on the interval start and end, returning a new Interval from the resulting DateTimes
|
350 | *
|
351 | * @example
|
352 | * Interval.fromDateTimes(dt1, dt2).mapEndpoints(endpoint => endpoint.toUTC())
|
353 | * @example
|
354 | * Interval.fromDateTimes(dt1, dt2).mapEndpoints(endpoint => endpoint.plus({ hours: 2 }))
|
355 | */
|
356 | mapEndpoints(mapFn: (d: DateTime) => DateTime): IntervalMaybeValid;
|
357 | }
|