@smcv/opening-hours 1.0.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/LICENSE +21 -0
- package/README.md +314 -0
- package/dist/index.d.ts +420 -0
- package/dist/index.global.d.ts +420 -0
- package/dist/index.global.js +1009 -0
- package/dist/index.js +966 -0
- package/package.json +70 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,420 @@
|
|
|
1
|
+
type OpenState = "closed" | "open";
|
|
2
|
+
declare const Days: {
|
|
3
|
+
readonly sunday: 0;
|
|
4
|
+
readonly monday: 1;
|
|
5
|
+
readonly tuesday: 2;
|
|
6
|
+
readonly wednesday: 3;
|
|
7
|
+
readonly thursday: 4;
|
|
8
|
+
readonly friday: 5;
|
|
9
|
+
readonly saturday: 6;
|
|
10
|
+
};
|
|
11
|
+
type Day = keyof typeof Days;
|
|
12
|
+
type DateValue = Date | number | string;
|
|
13
|
+
type TimeRangeString = string;
|
|
14
|
+
type TimeRangeWithData<T extends Record<string, unknown> = Record<string, unknown>> = {
|
|
15
|
+
hours?: TimeRangeString;
|
|
16
|
+
time?: TimeRangeString;
|
|
17
|
+
} & T;
|
|
18
|
+
type TimeRangeInput<T extends Record<string, unknown> = Record<string, unknown>> = TimeRangeString | TimeRangeWithData<T>;
|
|
19
|
+
type DayRange = `${Day}...${Day}`;
|
|
20
|
+
type DateRange = `${string}...${string}`;
|
|
21
|
+
type OpeningHoursConfig<T extends Record<string, unknown> = Record<string, unknown>> = Record<Day | DayRange, TimeRangeInput<T>[] | TimeRangeWithData<T>>;
|
|
22
|
+
/**
|
|
23
|
+
* Schema.org OpeningHoursSpecification interface
|
|
24
|
+
* @see https://schema.org/OpeningHoursSpecification
|
|
25
|
+
*/
|
|
26
|
+
interface OpeningHoursSpecification {
|
|
27
|
+
"@type": "OpeningHoursSpecification";
|
|
28
|
+
dayOfWeek?: string | string[];
|
|
29
|
+
opens?: string;
|
|
30
|
+
closes?: string;
|
|
31
|
+
validFrom?: string;
|
|
32
|
+
validThrough?: string;
|
|
33
|
+
}
|
|
34
|
+
declare class Time {
|
|
35
|
+
private readonly hour;
|
|
36
|
+
private readonly minute;
|
|
37
|
+
constructor(hour: number, minute?: number);
|
|
38
|
+
/**
|
|
39
|
+
* Create a Time instance from a string.
|
|
40
|
+
* Supports formats like '09:00', '09:00:00', or '09:00:00-05:00'.
|
|
41
|
+
*/
|
|
42
|
+
static fromString(timeString: string): Time;
|
|
43
|
+
/**
|
|
44
|
+
* Create a Time instance from a Date object
|
|
45
|
+
*/
|
|
46
|
+
static fromDate(date: Date): Time;
|
|
47
|
+
/**
|
|
48
|
+
* Get the hour component
|
|
49
|
+
*/
|
|
50
|
+
getHour(): number;
|
|
51
|
+
/**
|
|
52
|
+
* Get the minute component
|
|
53
|
+
*/
|
|
54
|
+
getMinute(): number;
|
|
55
|
+
/**
|
|
56
|
+
* Format the time as a string
|
|
57
|
+
*/
|
|
58
|
+
format(format?: string): string;
|
|
59
|
+
/**
|
|
60
|
+
* Convert to string in H:i format
|
|
61
|
+
*/
|
|
62
|
+
toString(): string;
|
|
63
|
+
/**
|
|
64
|
+
* Check if this time is before another time
|
|
65
|
+
*/
|
|
66
|
+
isBefore(time: Time): boolean;
|
|
67
|
+
/**
|
|
68
|
+
* Check if this time is after another time
|
|
69
|
+
*/
|
|
70
|
+
isAfter(time: Time): boolean;
|
|
71
|
+
/**
|
|
72
|
+
* Check if this time is equal to another time
|
|
73
|
+
*/
|
|
74
|
+
isEqual(time: Time): boolean;
|
|
75
|
+
/**
|
|
76
|
+
* Add minutes to the time
|
|
77
|
+
*/
|
|
78
|
+
addMinutes(minutes: number): Time;
|
|
79
|
+
/**
|
|
80
|
+
* Get the time as minutes since midnight
|
|
81
|
+
*/
|
|
82
|
+
toMinutesSinceMidnight(): number;
|
|
83
|
+
/**
|
|
84
|
+
* Calculate difference in minutes between two times
|
|
85
|
+
*/
|
|
86
|
+
diffInMinutes(time: Time): number;
|
|
87
|
+
/**
|
|
88
|
+
* Create a date with this time
|
|
89
|
+
*/
|
|
90
|
+
toDate(baseDate?: Date): Date;
|
|
91
|
+
}
|
|
92
|
+
type TimeRangeData<T extends Record<string, unknown> = Record<string, unknown>> = T;
|
|
93
|
+
declare class TimeRange<T extends Record<string, unknown> = Record<string, unknown>> {
|
|
94
|
+
private readonly start;
|
|
95
|
+
private readonly end;
|
|
96
|
+
private readonly data?;
|
|
97
|
+
constructor(start: Time, end: Time, data?: T);
|
|
98
|
+
/**
|
|
99
|
+
* Create a TimeRange from a string (e.g., '09:00-17:00')
|
|
100
|
+
*/
|
|
101
|
+
static fromString<T extends Record<string, unknown> = Record<string, unknown>>(rangeString: string, data?: T): TimeRange<T>;
|
|
102
|
+
/**
|
|
103
|
+
* Get the start time
|
|
104
|
+
*/
|
|
105
|
+
getStart(): Time;
|
|
106
|
+
/**
|
|
107
|
+
* Get the end time
|
|
108
|
+
*/
|
|
109
|
+
getEnd(): Time;
|
|
110
|
+
/**
|
|
111
|
+
* Get the associated data
|
|
112
|
+
*/
|
|
113
|
+
getData(): T | undefined;
|
|
114
|
+
/**
|
|
115
|
+
* Check if a specific time is contained in this range
|
|
116
|
+
*/
|
|
117
|
+
containsTime(time: Time, overflow?: boolean): boolean;
|
|
118
|
+
/**
|
|
119
|
+
* Check if the range spans overnight (end time is before start time)
|
|
120
|
+
*/
|
|
121
|
+
spansOvernight(): boolean;
|
|
122
|
+
/**
|
|
123
|
+
* Check if this range overlaps with another range
|
|
124
|
+
*/
|
|
125
|
+
overlaps(timeRange: TimeRange<T>, overflow?: boolean): boolean;
|
|
126
|
+
/**
|
|
127
|
+
* Get the duration of this range in minutes
|
|
128
|
+
*/
|
|
129
|
+
durationInMinutes(overflow?: boolean): number;
|
|
130
|
+
/**
|
|
131
|
+
* Convert to string representation
|
|
132
|
+
*/
|
|
133
|
+
toString(): string;
|
|
134
|
+
}
|
|
135
|
+
declare class OpeningHoursForDay<T extends Record<string, unknown> = Record<string, unknown>> {
|
|
136
|
+
private readonly timeRanges;
|
|
137
|
+
private readonly overflow;
|
|
138
|
+
private readonly displayOptions?;
|
|
139
|
+
private readonly data?;
|
|
140
|
+
constructor(timeRanges?: TimeRange<T>[], overflow?: boolean, displayOptions?: DisplayOptions, data?: T);
|
|
141
|
+
/**
|
|
142
|
+
* Check if open at the given time
|
|
143
|
+
*/
|
|
144
|
+
isOpenAt(time: Time): boolean;
|
|
145
|
+
/**
|
|
146
|
+
* Check if open at the given DateTime
|
|
147
|
+
*/
|
|
148
|
+
isOpenAtDateTime(dateTime: Date): boolean;
|
|
149
|
+
/**
|
|
150
|
+
* Check if the business is open during the day (has any time ranges)
|
|
151
|
+
*/
|
|
152
|
+
isOpenDuringDay(): boolean;
|
|
153
|
+
/**
|
|
154
|
+
* Get all time ranges
|
|
155
|
+
*/
|
|
156
|
+
getTimeRanges(): TimeRange<T>[];
|
|
157
|
+
/**
|
|
158
|
+
* Get the data associated with this day (e.g. a note on a closed exception)
|
|
159
|
+
*/
|
|
160
|
+
getData(): T | undefined;
|
|
161
|
+
/**
|
|
162
|
+
* Find the current open range at the given time
|
|
163
|
+
*/
|
|
164
|
+
getCurrentOpenRange(time: Time): TimeRange<T> | null;
|
|
165
|
+
/**
|
|
166
|
+
* Find the current open range at the given DateTime
|
|
167
|
+
*/
|
|
168
|
+
getCurrentOpenRangeAtDateTime(dateTime: Date): TimeRange<T> | null;
|
|
169
|
+
/**
|
|
170
|
+
* Check if this day has the same opening hours as another day
|
|
171
|
+
*/
|
|
172
|
+
equals(openingHoursForDay: OpeningHoursForDay<T>): boolean;
|
|
173
|
+
/**
|
|
174
|
+
* Format a time range for display
|
|
175
|
+
*/
|
|
176
|
+
protected formatTimeRange(timeRange: TimeRange<T>, options?: DisplayOptions): string;
|
|
177
|
+
/**
|
|
178
|
+
* Convert to string representation
|
|
179
|
+
*/
|
|
180
|
+
toString(options?: DisplayOptions): string;
|
|
181
|
+
}
|
|
182
|
+
type DayOfWeek = keyof typeof Days;
|
|
183
|
+
interface OpeningHoursOptions<T extends Record<string, unknown> = Record<string, unknown>> extends Partial<OpeningHoursConfig<T>> {
|
|
184
|
+
overflow?: boolean;
|
|
185
|
+
exceptions?: Record<string, TimeRangeInput<T>[] | ((date: Date) => TimeRangeInput<T>[])>;
|
|
186
|
+
filters?: Array<(date: Date) => TimeRangeInput<T>[]>;
|
|
187
|
+
/**
|
|
188
|
+
* IANA timezone name representing the organization's local time
|
|
189
|
+
*/
|
|
190
|
+
timezone?: string;
|
|
191
|
+
}
|
|
192
|
+
interface DisplayOptions {
|
|
193
|
+
locale?: string;
|
|
194
|
+
weekday?: "narrow" | "short" | "long";
|
|
195
|
+
firstDayOfWeek?: "monday" | "sunday";
|
|
196
|
+
dayRangeSeparator?: string;
|
|
197
|
+
timeRangeSeparator?: string;
|
|
198
|
+
timeFormat?: string;
|
|
199
|
+
timeRangesSeparator?: string;
|
|
200
|
+
showTimezone?: boolean;
|
|
201
|
+
timeZoneName?: "short" | "long" | "shortOffset" | "longOffset" | "shortGeneric" | "longGeneric";
|
|
202
|
+
closedText?: string;
|
|
203
|
+
}
|
|
204
|
+
declare class OpeningHours<T extends Record<string, unknown> = Record<string, unknown>> {
|
|
205
|
+
private readonly config;
|
|
206
|
+
private readonly schedule;
|
|
207
|
+
private readonly exceptions;
|
|
208
|
+
private readonly filters;
|
|
209
|
+
private readonly timezone?;
|
|
210
|
+
private readonly overflow;
|
|
211
|
+
private readonly displayOptions?;
|
|
212
|
+
constructor(config: OpeningHoursOptions<T> & DisplayOptions);
|
|
213
|
+
private initializeSchedule;
|
|
214
|
+
private normalizeTimeRanges;
|
|
215
|
+
/**
|
|
216
|
+
* Check if a TimeRangeInput has no hours/time (metadata-only item)
|
|
217
|
+
*/
|
|
218
|
+
private isMetadataOnly;
|
|
219
|
+
/**
|
|
220
|
+
* Filter out metadata-only items, keeping only actual time ranges
|
|
221
|
+
*/
|
|
222
|
+
private filterActualRanges;
|
|
223
|
+
/**
|
|
224
|
+
* Extract data from a metadata-only item in a schedule (no hours/time)
|
|
225
|
+
*/
|
|
226
|
+
private extractDataFromSchedule;
|
|
227
|
+
/**
|
|
228
|
+
* Get the data for a specific date (from exceptions only)
|
|
229
|
+
*/
|
|
230
|
+
private getDataForDate;
|
|
231
|
+
/**
|
|
232
|
+
* Convert a TimeRangeInput to a TimeRange object
|
|
233
|
+
*/
|
|
234
|
+
private convertToTimeRange;
|
|
235
|
+
/**
|
|
236
|
+
* Get day name from a Date object
|
|
237
|
+
*/
|
|
238
|
+
private getDayName;
|
|
239
|
+
/**
|
|
240
|
+
* Format a date as YYYY-MM-DD
|
|
241
|
+
*/
|
|
242
|
+
private formatDate;
|
|
243
|
+
/**
|
|
244
|
+
* Get time ranges for a specific date
|
|
245
|
+
*/
|
|
246
|
+
private getTimeRangesForDate;
|
|
247
|
+
/**
|
|
248
|
+
* Create a static instance of OpeningHours
|
|
249
|
+
*/
|
|
250
|
+
static create<T extends Record<string, unknown> = Record<string, unknown>>(config: OpeningHoursOptions<T> & DisplayOptions): OpeningHours<T>;
|
|
251
|
+
/**
|
|
252
|
+
* Check if the business is open on a specific day
|
|
253
|
+
*/
|
|
254
|
+
isOpenOn(day: Day): boolean;
|
|
255
|
+
/**
|
|
256
|
+
* Check if the business is open at a specific date and time
|
|
257
|
+
*/
|
|
258
|
+
isOpenAt(dateTime: Date): boolean;
|
|
259
|
+
/**
|
|
260
|
+
* Check if the business is closed at a specific date and time
|
|
261
|
+
*/
|
|
262
|
+
isClosedAt(dateTime: Date): boolean;
|
|
263
|
+
/**
|
|
264
|
+
* Get opening hours for a specific day of the week
|
|
265
|
+
*/
|
|
266
|
+
forDay(day: Day): OpeningHoursForDay<T>;
|
|
267
|
+
/**
|
|
268
|
+
* Get opening hours for all days of the week
|
|
269
|
+
*/
|
|
270
|
+
forWeek(): Record<Day, OpeningHoursForDay<T>>;
|
|
271
|
+
/**
|
|
272
|
+
* Get opening hours for a specific date
|
|
273
|
+
*/
|
|
274
|
+
forDate(date: Date): OpeningHoursForDay<T>;
|
|
275
|
+
/**
|
|
276
|
+
* Get all exceptions
|
|
277
|
+
*/
|
|
278
|
+
getExceptions(): Record<string, OpeningHoursForDay<T>>;
|
|
279
|
+
/**
|
|
280
|
+
* Calculate the difference in open time between two dates (in hours)
|
|
281
|
+
*/
|
|
282
|
+
diffInOpenHours(startDate: Date, endDate: Date): number;
|
|
283
|
+
/**
|
|
284
|
+
* Calculate the difference in open time between two dates (in minutes)
|
|
285
|
+
*/
|
|
286
|
+
diffInOpenMinutes(startDate: Date, endDate: Date): number;
|
|
287
|
+
/**
|
|
288
|
+
* Calculate the open minutes within a timespan (all within the same day)
|
|
289
|
+
*/
|
|
290
|
+
private calculateOpenMinutesForTimespan;
|
|
291
|
+
/**
|
|
292
|
+
* Check if there are exceptions between two dates
|
|
293
|
+
*/
|
|
294
|
+
private hasExceptionBetween;
|
|
295
|
+
/**
|
|
296
|
+
* Calculate the difference in open time between two dates (in seconds)
|
|
297
|
+
*/
|
|
298
|
+
diffInOpenSeconds(startDate: Date, endDate: Date): number;
|
|
299
|
+
/**
|
|
300
|
+
* Calculate the difference in closed time between two dates (in hours)
|
|
301
|
+
*/
|
|
302
|
+
diffInClosedHours(startDate: Date, endDate: Date): number;
|
|
303
|
+
/**
|
|
304
|
+
* Calculate the difference in closed time between two dates (in minutes)
|
|
305
|
+
*/
|
|
306
|
+
diffInClosedMinutes(startDate: Date, endDate: Date): number;
|
|
307
|
+
/**
|
|
308
|
+
* Calculate the difference in closed time between two dates (in seconds)
|
|
309
|
+
*/
|
|
310
|
+
diffInClosedSeconds(startDate: Date, endDate: Date): number;
|
|
311
|
+
/**
|
|
312
|
+
* Get the current open range at a specific date and time
|
|
313
|
+
*/
|
|
314
|
+
currentOpenRange(dateTime: Date): TimeRange<T> | null;
|
|
315
|
+
/**
|
|
316
|
+
* Get the start of the current open range at a specific date and time
|
|
317
|
+
*/
|
|
318
|
+
currentOpenRangeStart(dateTime: Date): Date | null;
|
|
319
|
+
/**
|
|
320
|
+
* Get the end of the current open range at a specific date and time
|
|
321
|
+
*/
|
|
322
|
+
currentOpenRangeEnd(dateTime: Date): Date | null;
|
|
323
|
+
/**
|
|
324
|
+
* Find the next open range after a specific date and time
|
|
325
|
+
*/
|
|
326
|
+
private findNextOpenRange;
|
|
327
|
+
/**
|
|
328
|
+
* Find the previous open range before a specific date and time
|
|
329
|
+
*/
|
|
330
|
+
private findPreviousOpenRange;
|
|
331
|
+
/**
|
|
332
|
+
* Get the next open range after a specific date and time
|
|
333
|
+
*/
|
|
334
|
+
nextOpenRange(dateTime: Date): TimeRange<T> | null;
|
|
335
|
+
/**
|
|
336
|
+
* Get the start of the next open range after a specific date and time
|
|
337
|
+
*/
|
|
338
|
+
nextOpenRangeStart(dateTime: Date): Date | null;
|
|
339
|
+
/**
|
|
340
|
+
* Get the end of the next open range after a specific date and time
|
|
341
|
+
*/
|
|
342
|
+
nextOpenRangeEnd(dateTime: Date): Date | null;
|
|
343
|
+
/**
|
|
344
|
+
* Convenience alias for nextOpenRangeStart
|
|
345
|
+
*/
|
|
346
|
+
nextOpen(dateTime: Date): Date | null;
|
|
347
|
+
/**
|
|
348
|
+
* Get the next closing time after a specific date and time
|
|
349
|
+
*/
|
|
350
|
+
nextClose(dateTime: Date): Date | null;
|
|
351
|
+
/**
|
|
352
|
+
* Get the previous open range before a specific date and time
|
|
353
|
+
*/
|
|
354
|
+
previousOpenRange(dateTime: Date): TimeRange<T> | null;
|
|
355
|
+
/**
|
|
356
|
+
* Get the start of the previous open range before a specific date and time
|
|
357
|
+
*/
|
|
358
|
+
previousOpenRangeStart(dateTime: Date): Date | null;
|
|
359
|
+
/**
|
|
360
|
+
* Get the end of the previous open range before a specific date and time
|
|
361
|
+
*/
|
|
362
|
+
previousOpenRangeEnd(dateTime: Date): Date | null;
|
|
363
|
+
static from<T extends Record<string, unknown> = Record<string, unknown>>(config: OpeningHoursOptions<T> & DisplayOptions): OpeningHours<T>;
|
|
364
|
+
/**
|
|
365
|
+
* Create OpeningHours from structured data (schema.org format)
|
|
366
|
+
*/
|
|
367
|
+
static createFromStructuredData<T extends Record<string, unknown> = Record<string, unknown>>(inputData: unknown, displayOptions?: DisplayOptions): OpeningHours<T>;
|
|
368
|
+
/**
|
|
369
|
+
* Format a Time object as ISO-8601 time with timezone offset
|
|
370
|
+
*/
|
|
371
|
+
private formatISOTime;
|
|
372
|
+
/**
|
|
373
|
+
* Convert to structured data (schema.org format)
|
|
374
|
+
*/
|
|
375
|
+
asStructuredData(timezone?: string | null): OpeningHoursSpecification[];
|
|
376
|
+
/**
|
|
377
|
+
* Convert a date to the configured timezone.
|
|
378
|
+
* Returns a date object whose clock time reflects the target timezone
|
|
379
|
+
* but represents the same absolute instant.
|
|
380
|
+
*/
|
|
381
|
+
private toTimezone;
|
|
382
|
+
/**
|
|
383
|
+
* Convert a date interpreted in the configured timezone back to UTC.
|
|
384
|
+
*/
|
|
385
|
+
private fromTimezone;
|
|
386
|
+
/**
|
|
387
|
+
* Get a string representation of a day's schedule for comparison
|
|
388
|
+
*/
|
|
389
|
+
private getScheduleStringForDay;
|
|
390
|
+
/**
|
|
391
|
+
* Get time ranges for a specific day of the week
|
|
392
|
+
*/
|
|
393
|
+
private getTimeRangesForDayOfWeek;
|
|
394
|
+
/**
|
|
395
|
+
* Format a day range, e.g. "Mon...Fri" or "Sat"
|
|
396
|
+
*/
|
|
397
|
+
protected formatDayRange(days: DayOfWeek[], options?: DisplayOptions): string;
|
|
398
|
+
/**
|
|
399
|
+
* Format a time range for display (e.g. 9:00-17:00)
|
|
400
|
+
*/
|
|
401
|
+
protected formatTimeRange(timeRange: TimeRange<T>, options?: DisplayOptions): string;
|
|
402
|
+
/**
|
|
403
|
+
* Render opening hours as array where each array item corresponds to a line of output
|
|
404
|
+
* and contains day range followed by time ranges
|
|
405
|
+
*/
|
|
406
|
+
toArray(options?: DisplayOptions): string[][];
|
|
407
|
+
/**
|
|
408
|
+
* Format a day name using Intl.DateTimeFormat
|
|
409
|
+
*/
|
|
410
|
+
private formatDayName;
|
|
411
|
+
/**
|
|
412
|
+
* Get timezone abbreviation for display
|
|
413
|
+
*/
|
|
414
|
+
private getTimezoneName;
|
|
415
|
+
/**
|
|
416
|
+
* Render opening hours as multi-line string
|
|
417
|
+
*/
|
|
418
|
+
toString(options?: DisplayOptions): string;
|
|
419
|
+
}
|
|
420
|
+
export { TimeRangeWithData, TimeRangeString, TimeRangeInput, TimeRangeData, TimeRange, Time, OpeningHoursSpecification, OpeningHoursOptions, OpeningHoursForDay, OpeningHoursConfig, OpeningHours, OpenState, Days, DayRange, Day, DateValue, DateRange };
|