temporal-workdays 0.1.0 → 0.2.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/dist/index.d.ts CHANGED
@@ -1,8 +1,4 @@
1
- /**
2
- * The parts of a `Temporal.PlainDate` this library relies on. Described structurally so that
3
- * native Temporal, `temporal-polyfill`, `@js-temporal/polyfill` and their TypeScript types all work,
4
- * with no global `Temporal` type required.
5
- */
1
+ /** The parts of a `Temporal.PlainDate` this library relies on. */
6
2
  interface PlainDateLike {
7
3
  readonly calendarId: string;
8
4
  readonly year: number;
@@ -49,17 +45,176 @@ type HolidayInput = string | PlainDateLike | PlainMonthDayLike;
49
45
  type HolidayPredicate = {
50
46
  bivarianceHack(date: PlainDateLike): boolean;
51
47
  }['bivarianceHack'];
48
+ /** Which days are workdays. */
52
49
  interface WorkdayOptions {
53
50
  /** Non-working days of the week. Default `[6, 7]` (Saturday, Sunday). */
54
- weekend?: readonly DayOfWeek[];
51
+ readonly weekend?: readonly DayOfWeek[] | undefined;
55
52
  /** Holiday dates, or a function that decides whether a date is a holiday. */
56
- holidays?: Iterable<HolidayInput> | HolidayPredicate;
53
+ readonly holidays?: Iterable<HolidayInput> | HolidayPredicate | undefined;
57
54
  /**
58
55
  * Dates that count as workdays even if they fall on the weekend or a holiday
59
56
  * (for example, make-up working Saturdays). Single dates only.
60
57
  */
61
- extraWorkdays?: Iterable<string | PlainDateLike>;
58
+ readonly extraWorkdays?: Iterable<string | PlainDateLike> | undefined;
59
+ }
60
+ /** The parts of a `Temporal.PlainTime` this library relies on. */
61
+ interface PlainTimeLike {
62
+ readonly hour: number;
63
+ readonly minute: number;
64
+ readonly second: number;
65
+ readonly millisecond: number;
66
+ readonly microsecond: number;
67
+ readonly nanosecond: number;
68
+ }
69
+ /** Calendar and clock fields, as accepted by `Temporal.PlainDateTime#with`. */
70
+ interface DateTimeFields {
71
+ year: number;
72
+ month: number;
73
+ day: number;
74
+ hour: number;
75
+ minute: number;
76
+ second: number;
77
+ millisecond: number;
78
+ microsecond: number;
79
+ nanosecond: number;
80
+ }
81
+ /** A duration of clock time. `Temporal.Duration` and plain objects such as `{ hours: 4 }` both fit. */
82
+ interface DurationInput {
83
+ readonly years?: number | undefined;
84
+ readonly months?: number | undefined;
85
+ readonly weeks?: number | undefined;
86
+ readonly days?: number | undefined;
87
+ readonly hours?: number | undefined;
88
+ readonly minutes?: number | undefined;
89
+ readonly seconds?: number | undefined;
90
+ readonly milliseconds?: number | undefined;
91
+ readonly microseconds?: number | undefined;
92
+ readonly nanoseconds?: number | undefined;
93
+ }
94
+ /** The parts of a `Temporal.Duration` this library relies on. */
95
+ interface DurationLike {
96
+ add(other: {
97
+ seconds: number;
98
+ nanoseconds: number;
99
+ }): DurationLike;
100
+ round(options: {
101
+ largestUnit: 'hours';
102
+ }): DurationLike;
103
+ }
104
+ /** The parts of a `Temporal.PlainDateTime` this library relies on. */
105
+ interface PlainDateTimeLike extends PlainTimeLike {
106
+ readonly calendarId: string;
107
+ readonly year: number;
108
+ readonly month: number;
109
+ readonly day: number;
110
+ withCalendar(calendar: string): PlainDateTimeLike;
111
+ with(fields: DateTimeFields): PlainDateTimeLike;
112
+ /** Only ever called as `x.until(x)` to obtain a zero Duration; `never` accepts every implementation's signature. */
113
+ until(other: never): DurationLike;
114
+ toPlainDate(): PlainDateLike;
115
+ add(duration: {
116
+ days: number;
117
+ }): PlainDateTimeLike;
62
118
  }
119
+ /** The parts of a `Temporal.ZonedDateTime` this library relies on. */
120
+ interface ZonedDateTimeLike extends PlainTimeLike {
121
+ readonly calendarId: string;
122
+ readonly timeZoneId: string;
123
+ readonly epochNanoseconds: bigint;
124
+ readonly offsetNanoseconds: number;
125
+ readonly year: number;
126
+ readonly month: number;
127
+ readonly day: number;
128
+ withCalendar(calendar: string): ZonedDateTimeLike;
129
+ withTimeZone(timeZone: string): ZonedDateTimeLike;
130
+ with(fields: DateTimeFields, options: {
131
+ disambiguation: 'compatible';
132
+ offset: 'ignore';
133
+ }): ZonedDateTimeLike;
134
+ /** Only ever called as `x.until(x)` to obtain a zero Duration; `never` accepts every implementation's signature. */
135
+ until(other: never): DurationLike;
136
+ toPlainDate(): PlainDateLike;
137
+ add(duration: {
138
+ days?: number;
139
+ seconds?: number;
140
+ nanoseconds?: number;
141
+ }): ZonedDateTimeLike;
142
+ getTimeZoneTransition(direction: 'next' | 'previous'): ZonedDateTimeLike | null;
143
+ }
144
+ /** A date with a time of day: `Temporal.PlainDateTime` or `Temporal.ZonedDateTime`. */
145
+ type DateTimeInput = PlainDateTimeLike | ZonedDateTimeLike;
146
+ /** The `Temporal.Duration` type of the Temporal implementation that `T` comes from. */
147
+ type DurationOf<T> = T extends {
148
+ until(...args: never[]): infer D;
149
+ } ? D : never;
150
+ /** A time of day: `'HH:MM'`, `'HH:MM:SS'`, `'HH:MM:SS.fffffffff'` or a `Temporal.PlainTime`. */
151
+ type TimeInput = string | PlainTimeLike;
152
+ /** A working period within one day, `[start, end)`. `'24:00'` is allowed as an end. */
153
+ type TimeRange = readonly [start: TimeInput, end: TimeInput];
154
+ /** The working periods of one day, e.g. `[['09:00', '12:00'], ['13:00', '17:00']]`. */
155
+ type DayHours = readonly TimeRange[];
156
+ /** A normalized working period as returned by this library, e.g. `['09:00', '17:30']`. */
157
+ type TimeRangeText = readonly [start: string, end: string];
158
+ /** Hours per ISO day of week (1 = Monday … 7 = Sunday); `default` applies to days not listed. */
159
+ type WeeklyHours = Readonly<Partial<Record<DayOfWeek, DayHours>>> & {
160
+ readonly default?: DayHours;
161
+ };
162
+ /** The same hours on every workday, or hours per day of week. */
163
+ type WorkingHours = DayHours | WeeklyHours;
164
+ /**
165
+ * Decides the hours of a specific date. Receives an ISO `Temporal.PlainDate` and that date's
166
+ * regular hours (empty on weekends and holidays). Return `undefined` to keep the regular hours,
167
+ * `[]` to close, or other hours.
168
+ */
169
+ type SpecialHoursFunction = {
170
+ bivarianceHack(date: PlainDateLike, regular: readonly TimeRangeText[]): DayHours | undefined;
171
+ }['bivarianceHack'];
172
+ /** Hours for specific dates, keyed by `'YYYY-MM-DD'` (`[]` = closed), or a function. */
173
+ type SpecialHours = Readonly<Record<string, DayHours>> | SpecialHoursFunction;
174
+ /** Workdays plus working hours, for the working-time functions. */
175
+ interface WorkingTimeOptions extends WorkdayOptions {
176
+ /** Working hours on workdays. Weekends and holidays have no working hours. */
177
+ readonly hours: WorkingHours;
178
+ /** Overrides for specific dates (half days, extended hours, closures). Takes precedence over everything else. */
179
+ readonly specialHours?: SpecialHours | undefined;
180
+ }
181
+
182
+ /** Workday helpers bound to one configuration. See the standalone functions for details. */
183
+ interface WorkCalendar {
184
+ /** A frozen snapshot of the options the calendar was created with. */
185
+ readonly options: Readonly<WorkdayOptions>;
186
+ isWorkday(date: DateInput): boolean;
187
+ isWeekend(date: DateInput): boolean;
188
+ isHoliday(date: DateInput): boolean;
189
+ addWorkdays<T extends DateInput>(date: T, amount: number): T;
190
+ subtractWorkdays<T extends DateInput>(date: T, amount: number): T;
191
+ nextWorkday<T extends DateInput>(date: T): T;
192
+ previousWorkday<T extends DateInput>(date: T): T;
193
+ rollForward<T extends DateInput>(date: T): T;
194
+ rollBackward<T extends DateInput>(date: T): T;
195
+ workdaysBetween(start: DateInput, end: DateInput): number;
196
+ eachWorkday<T extends DateInput>(start: T, end: DateInput): Generator<T, void>;
197
+ }
198
+ /** A calendar created with `hours`: workday helpers plus working-time helpers. */
199
+ interface WorkTimeCalendar extends WorkCalendar {
200
+ readonly options: Readonly<WorkingTimeOptions>;
201
+ isWorkingTime(dateTime: DateTimeInput): boolean;
202
+ addWorkingTime<T extends DateTimeInput>(dateTime: T, duration: DurationInput): T;
203
+ subtractWorkingTime<T extends DateTimeInput>(dateTime: T, duration: DurationInput): T;
204
+ workingTimeBetween<T extends DateTimeInput>(start: T, end: NoInfer<T>): DurationOf<T>;
205
+ rollForwardToWorkingTime<T extends DateTimeInput>(dateTime: T): T;
206
+ rollBackwardToWorkingTime<T extends DateTimeInput>(dateTime: T): T;
207
+ getWorkingHours(date: DateInput): readonly TimeRangeText[];
208
+ }
209
+ /**
210
+ * Creates helpers bound to one configuration. The options are validated and read
211
+ * immediately (holidays and hours are parsed once), so later changes to the passed-in
212
+ * arrays don't affect the calendar. Prefer this over the standalone functions when the
213
+ * same configuration is used repeatedly. With `hours`, the working-time helpers are included.
214
+ */
215
+ declare function createWorkCalendar(options: WorkingTimeOptions): WorkTimeCalendar;
216
+ declare function createWorkCalendar(options?: WorkdayOptions): WorkCalendar;
217
+
63
218
  /** `true` if the date falls on a configured weekend day (ignores holidays and `extraWorkdays`). */
64
219
  declare function isWeekend(date: DateInput, options?: WorkdayOptions): boolean;
65
220
  /** `true` if the date is a configured holiday and not listed in `extraWorkdays`. */
@@ -93,27 +248,73 @@ declare function workdaysBetween(start: DateInput, end: DateInput, options?: Wor
93
248
  * Yields every workday from `start` to `end`, both inclusive, in ascending order.
94
249
  * Values have the type of `start` (time of day / zone preserved). Yields nothing if `end < start`.
95
250
  */
96
- declare function eachWorkday<T extends DateInput>(start: T, end: DateInput, options?: WorkdayOptions): Generator<T>;
97
- /** A set of workday helpers bound to one configuration. Holidays are parsed once. */
98
- interface WorkCalendar {
99
- readonly options: Readonly<WorkdayOptions>;
100
- isWorkday(date: DateInput): boolean;
101
- isWeekend(date: DateInput): boolean;
102
- isHoliday(date: DateInput): boolean;
103
- addWorkdays<T extends DateInput>(date: T, amount: number): T;
104
- subtractWorkdays<T extends DateInput>(date: T, amount: number): T;
105
- nextWorkday<T extends DateInput>(date: T): T;
106
- previousWorkday<T extends DateInput>(date: T): T;
107
- rollForward<T extends DateInput>(date: T): T;
108
- rollBackward<T extends DateInput>(date: T): T;
109
- workdaysBetween(start: DateInput, end: DateInput): number;
110
- eachWorkday<T extends DateInput>(start: T, end: DateInput): Generator<T>;
251
+ declare function eachWorkday<T extends DateInput>(start: T, end: DateInput, options?: WorkdayOptions): Generator<T, void>;
252
+
253
+ /** `true` if `dateTime` is inside working hours (periods are `[start, end)`: 17:00 is not working time in 09:00–17:00). */
254
+ declare function isWorkingTime(dateTime: DateTimeInput, options: WorkingTimeOptions): boolean;
255
+ /**
256
+ * Adds working time: only time inside working hours counts. Negative durations go back.
257
+ * Starting outside working hours, counting begins at the next working period. Landing
258
+ * exactly at the end of a period returns that end (`16:00 + 1h` → `17:00`, not the next morning).
259
+ *
260
+ * The result has the type of the input. For `ZonedDateTime`, elapsed time is exact across DST changes.
261
+ */
262
+ declare function addWorkingTime<T extends DateTimeInput>(dateTime: T, duration: DurationInput, options: WorkingTimeOptions): T;
263
+ /** Subtracts working time. Landing exactly at the start of a period returns that start. */
264
+ declare function subtractWorkingTime<T extends DateTimeInput>(dateTime: T, duration: DurationInput, options: WorkingTimeOptions): T;
265
+ /**
266
+ * Working time in `[start, end)` as a `Temporal.Duration` balanced up to hours (e.g. `PT27H30M`);
267
+ * negative when `end` is before `start`. Use `.total('hours')` for a number.
268
+ */
269
+ declare function workingTimeBetween<T extends DateTimeInput>(start: T, end: NoInfer<T>, options: WorkingTimeOptions): DurationOf<T>;
270
+ /** `dateTime` itself if it is working time, otherwise the start of the next working period. */
271
+ declare function rollForwardToWorkingTime<T extends DateTimeInput>(dateTime: T, options: WorkingTimeOptions): T;
272
+ /** `dateTime` itself if it is working time, otherwise the end of the previous working period. */
273
+ declare function rollBackwardToWorkingTime<T extends DateTimeInput>(dateTime: T, options: WorkingTimeOptions): T;
274
+ /** The working periods of a date after weekends, holidays and special hours, e.g. `[['09:00', '17:00']]`. */
275
+ declare function getWorkingHours(date: DateInput, options: WorkingTimeOptions): readonly TimeRangeText[];
276
+
277
+ /** The parts of a `date-holidays` holiday this adapter uses. */
278
+ interface DateHolidaysEntry {
279
+ /** Local start, `'YYYY-MM-DD hh:mm:ss'`, optionally with a `' -0600'`-style shift (eve-start holidays). */
280
+ readonly date: string;
281
+ /** `'public'`, `'bank'`, `'school'`, `'optional'` or `'observance'`. */
282
+ readonly type: string;
283
+ readonly start: Date;
284
+ readonly end: Date;
285
+ }
286
+ /** The parts of a `date-holidays` `Holidays` instance this adapter uses. */
287
+ interface DateHolidaysSource {
288
+ getHolidays(year: number): readonly DateHolidaysEntry[];
289
+ }
290
+ interface FromDateHolidaysOptions {
291
+ /** Holiday types that close the business. Default `['public']`. */
292
+ readonly types?: readonly string[] | undefined;
293
+ }
294
+ /** Spread into calendar options: `createWorkCalendar({ ...fromDateHolidays(hd), hours })`. */
295
+ interface DateHolidaysOptions {
296
+ /** `true` for dates that a holiday covers completely. */
297
+ readonly holidays: HolidayPredicate;
298
+ /** Regular hours minus partial-day closures (e.g. closing at 14:00 on Christmas Eve). */
299
+ readonly specialHours: SpecialHoursFunction;
111
300
  }
112
301
  /**
113
- * Creates helpers bound to one configuration. The options are validated and copied
114
- * immediately, so later changes to the passed-in arrays don't affect the calendar.
302
+ * Turns a `date-holidays` instance into `holidays` and `specialHours` options:
303
+ *
304
+ * ```ts
305
+ * import Holidays from 'date-holidays';
306
+ * const cal = createWorkCalendar({
307
+ * ...fromDateHolidays(new Holidays('DE', 'BY'), { types: ['public', 'bank'] }),
308
+ * hours: [['09:00', '17:00']],
309
+ * });
310
+ * ```
311
+ *
312
+ * Days a holiday covers completely are holidays. Days it covers partly (Christmas Eve from
313
+ * 14:00) stay workdays with reduced hours. Holidays that `date-holidays` starts on the
314
+ * evening before (Hijri and Hebrew calendar holidays) are taken as it reports them.
315
+ * Results are cached per year.
115
316
  */
116
- declare function createWorkCalendar(options?: WorkdayOptions): WorkCalendar;
317
+ declare function fromDateHolidays(source: DateHolidaysSource, options?: FromDateHolidaysOptions): DateHolidaysOptions;
117
318
 
118
- export { addWorkdays, createWorkCalendar, eachWorkday, isHoliday, isWeekend, isWorkday, nextWorkday, previousWorkday, rollBackward, rollForward, subtractWorkdays, workdaysBetween };
119
- export type { DateInput, DateTimeLike, DayOfWeek, HolidayInput, HolidayPredicate, PlainDateLike, PlainMonthDayLike, WorkCalendar, WorkdayOptions };
319
+ export { addWorkdays, addWorkingTime, createWorkCalendar, eachWorkday, fromDateHolidays, getWorkingHours, isHoliday, isWeekend, isWorkday, isWorkingTime, nextWorkday, previousWorkday, rollBackward, rollBackwardToWorkingTime, rollForward, rollForwardToWorkingTime, subtractWorkdays, subtractWorkingTime, workdaysBetween, workingTimeBetween };
320
+ export type { DateHolidaysEntry, DateHolidaysOptions, DateHolidaysSource, DateInput, DateTimeFields, DateTimeInput, DateTimeLike, DayHours, DayOfWeek, DurationInput, DurationLike, DurationOf, FromDateHolidaysOptions, HolidayInput, HolidayPredicate, PlainDateLike, PlainDateTimeLike, PlainMonthDayLike, PlainTimeLike, SpecialHours, SpecialHoursFunction, TimeInput, TimeRange, TimeRangeText, WeeklyHours, WorkCalendar, WorkTimeCalendar, WorkdayOptions, WorkingHours, WorkingTimeOptions, ZonedDateTimeLike };