ts-time-utils 2.0.0 → 3.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/README.md CHANGED
@@ -8,7 +8,7 @@ A lightweight TypeScript utility library for time formatting, calculations, and
8
8
  - **⚡ Fast** - Zero dependencies, pure JavaScript functions
9
9
  - **🔧 TypeScript** - Full type safety and IntelliSense support
10
10
  - **🌳 Tree-shakable** - Import individual functions to minimize bundle size
11
- - **📚 Comprehensive** - 25 utility categories with 287+ functions
11
+ - **📚 Comprehensive** - 26 utility categories with 320+ functions
12
12
 
13
13
  ### 🔄 Recurrence utilities **(NEW!)**
14
14
 
@@ -198,6 +198,34 @@ A lightweight TypeScript utility library for time formatting, calculations, and
198
198
 
199
199
  - Sort date arrays ascending or descending
200
200
  - Find min/max/median/average dates in arrays
201
+ - Find closest/farthest dates from target
202
+ - Remove duplicate dates
203
+ - Group dates by year/month/day/weekday
204
+ - Snap dates to grid and round to nearest unit
205
+ - Validate chronological order
206
+ - Get date span and partition into groups
207
+ - Select nth dates from sorted arrays
208
+
209
+ ### ⏭️ Date Iteration & Counting **(NEW!)**
210
+
211
+ - Iterate through date sequences: days, weekdays, weekends, weeks, months, quarters, years
212
+ - Count dates in ranges: count all days, weekdays, weekend days, weeks, months
213
+ - Lazy iteration with generators for memory efficiency
214
+ - Filter dates by custom conditions
215
+ - Iterate specific day patterns (e.g., all Mondays)
216
+ - Get month-end dates in range
217
+ - Get nth day of each month in range
218
+
219
+ ### 🌍 International Holidays **(NEW!)**
220
+
221
+ - Calculate public holidays for 9 countries: UK, Netherlands, Germany, Canada, Australia, Italy, Spain, China, India
222
+ - Fixed holidays (New Year, Christmas, National Days)
223
+ - Easter-based holidays (Good Friday, Easter Monday, Whit Monday)
224
+ - Movable holidays (Victoria Day, Thanksgiving, Spring Bank Holiday)
225
+ - Unified API: check if date is holiday, get holiday name, find next holiday
226
+ - Weekend adjustment for substitute holidays
227
+ - Get upcoming holidays within timeframe
228
+ - Support for both federal and regional observances
201
229
  - Find closest date to a target (past, future, or any)
202
230
  - Clamp dates to ranges
203
231
  - Remove duplicate dates with precision control
@@ -295,6 +323,13 @@ import {
295
323
  countWeekdays,
296
324
  iterateDays,
297
325
  } from "ts-time-utils/iterate";
326
+ // NEW: International holidays
327
+ import {
328
+ getHolidays,
329
+ isHoliday,
330
+ getNextHoliday,
331
+ getSupportedCountries,
332
+ } from "ts-time-utils/holidays";
298
333
  ```
299
334
 
300
335
  ## 📖 Examples
@@ -927,6 +962,60 @@ eachInterval(start, end, { days: 7 }); // Every 7 days
927
962
  eachInterval(start, end, { hours: 6 }); // Every 6 hours
928
963
  ```
929
964
 
965
+ ### International Holidays (NEW!)
966
+
967
+ ```ts
968
+ import {
969
+ getHolidays,
970
+ isHoliday,
971
+ getHolidayName,
972
+ getNextHoliday,
973
+ getUpcomingHolidays,
974
+ getSupportedCountries,
975
+ getUKHolidays,
976
+ getCanadaHolidays,
977
+ } from "ts-time-utils/holidays";
978
+
979
+ // Get all holidays for a country and year
980
+ const ukHolidays2024 = getHolidays(2024, "UK");
981
+ console.log(ukHolidays2024);
982
+ // [
983
+ // { name: "New Year's Day", date: Date, countryCode: "UK", type: "bank" },
984
+ // { name: "Good Friday", date: Date, countryCode: "UK", type: "bank" },
985
+ // { name: "Easter Monday", date: Date, countryCode: "UK", type: "bank" },
986
+ // ...
987
+ // ]
988
+
989
+ // Check if a date is a holiday
990
+ const christmas = new Date(2024, 11, 25);
991
+ isHoliday(christmas, "UK"); // true
992
+ isHoliday(new Date(2024, 5, 15), "UK"); // false
993
+
994
+ // Get holiday name for a date
995
+ getHolidayName(christmas, "UK"); // "Christmas Day"
996
+ getHolidayName(new Date(2024, 0, 1), "CA"); // "New Year's Day"
997
+
998
+ // Find next holiday from a date
999
+ const today = new Date();
1000
+ const nextHoliday = getNextHoliday(today, "CA");
1001
+ console.log(`Next holiday: ${nextHoliday?.name} on ${nextHoliday?.date}`);
1002
+
1003
+ // Get upcoming holidays in the next 90 days
1004
+ const upcoming = getUpcomingHolidays(today, 90, "AU");
1005
+ upcoming.forEach((h) => {
1006
+ console.log(`${h.name} - ${h.date.toDateString()}`);
1007
+ });
1008
+
1009
+ // Get supported countries
1010
+ getSupportedCountries(); // ["UK", "NL", "DE", "CA", "AU", "IT", "ES", "CN", "IN", "US"]
1011
+
1012
+ // Country-specific functions
1013
+ const nlHolidays = getHolidays(2024, "NL"); // Netherlands holidays (includes King's Day)
1014
+ const deHolidays = getHolidays(2024, "DE"); // German holidays (includes German Unity Day)
1015
+ const itHolidays = getHolidays(2024, "IT"); // Italian holidays (includes Republic Day)
1016
+ const esHolidays = getHolidays(2024, "ES"); // Spanish holidays (includes Constitution Day)
1017
+ ```
1018
+
930
1019
  ### Locale Utilities
931
1020
 
932
1021
  ```ts
@@ -1289,6 +1378,26 @@ console.log(comparison.weekStartsOn);
1289
1378
  - `iterateMonths(start, end)` - Lazy month iterator
1290
1379
  - `filterDays(start, end, filter)` - Filter days by predicate
1291
1380
 
1381
+ ### Holidays Functions
1382
+
1383
+ - `getHolidays(year, countryCode)` - Get all holidays for a country and year
1384
+ - `isHoliday(date, countryCode)` - Check if date is a holiday
1385
+ - `getHolidayName(date, countryCode)` - Get holiday name for date (or null)
1386
+ - `getNextHoliday(date, countryCode)` - Find next holiday after date
1387
+ - `getUpcomingHolidays(date, days, countryCode)` - Get holidays in next N days
1388
+ - `getSupportedCountries()` - Get array of supported country codes
1389
+ - `getUKHolidays(year)` - Get UK bank holidays (New Year, Easter, Spring/Summer Bank Holiday, Christmas)
1390
+ - `getNetherlandsHolidays(year)` - Get Netherlands holidays (King's Day, Liberation Day, Easter, Ascension, Whit)
1391
+ - `getGermanyHolidays(year)` - Get German holidays (Unity Day, Labour Day, Easter, Ascension, Whit, Christmas)
1392
+ - `getCanadaHolidays(year)` - Get Canadian federal holidays (Victoria Day, Canada Day, Labour Day, Thanksgiving)
1393
+ - `getAustraliaHolidays(year)` - Get Australian holidays (Australia Day, Anzac Day, Queen's Birthday)
1394
+ - `getItalyHolidays(year)` - Get Italian holidays (Epiphany, Liberation Day, Republic Day, Assumption)
1395
+ - `getSpainHolidays(year)` - Get Spanish holidays (National Day, Constitution Day, Immaculate Conception)
1396
+ - `getChinaHolidays(year)` - Get Chinese holidays (Spring Festival, National Day, New Year) - simplified
1397
+ - `getIndiaHolidays(year)` - Get Indian holidays (Republic Day, Independence Day, Gandhi Jayanti) - simplified
1398
+ - **Types**: `CountryCode` = "UK" | "NL" | "DE" | "CA" | "AU" | "IT" | "ES" | "CN" | "IN" | "US"
1399
+ - **Holiday Interface**: `{ name: string, date: Date, countryCode: CountryCode, type: string }`
1400
+
1292
1401
  ### Calculate Functions
1293
1402
 
1294
1403
  - `differenceInUnits(date1, date2, unit?, precise?)` - Calculate difference between dates
@@ -0,0 +1,269 @@
1
+ /**
2
+ * Fluent chain API for ts-time-utils
3
+ *
4
+ * Provides a chainable interface for date operations:
5
+ * ```ts
6
+ * chain(new Date())
7
+ * .add(1, 'day')
8
+ * .startOf('month')
9
+ * .format('YYYY-MM-DD')
10
+ * ```
11
+ */
12
+ import type { TimeUnit, DateInput, FormatOptions } from './types.js';
13
+ /** Units accepted by startOf/endOf */
14
+ type StartOfUnit = 'day' | 'week' | 'month' | 'year' | 'hour' | 'minute';
15
+ /**
16
+ * Immutable chainable date wrapper
17
+ * All transformation methods return a new ChainedDate instance
18
+ */
19
+ export declare class ChainedDate {
20
+ private readonly _date;
21
+ constructor(date?: DateInput);
22
+ /**
23
+ * Add time to the date
24
+ * @example chain(date).add(1, 'day').add(2, 'hours')
25
+ */
26
+ add(amount: number, unit: TimeUnit): ChainedDate;
27
+ /**
28
+ * Subtract time from the date
29
+ * @example chain(date).subtract(1, 'week')
30
+ */
31
+ subtract(amount: number, unit: TimeUnit): ChainedDate;
32
+ /**
33
+ * Get the start of a time period
34
+ * @example chain(date).startOf('month')
35
+ */
36
+ startOf(unit: StartOfUnit): ChainedDate;
37
+ /**
38
+ * Get the end of a time period
39
+ * @example chain(date).endOf('day')
40
+ */
41
+ endOf(unit: StartOfUnit): ChainedDate;
42
+ /**
43
+ * Set specific date/time components
44
+ * @example chain(date).set({ year: 2025, month: 1 })
45
+ */
46
+ set(values: {
47
+ year?: number;
48
+ month?: number;
49
+ day?: number;
50
+ hours?: number;
51
+ minutes?: number;
52
+ seconds?: number;
53
+ milliseconds?: number;
54
+ }): ChainedDate;
55
+ /**
56
+ * Clone the ChainedDate
57
+ */
58
+ clone(): ChainedDate;
59
+ /**
60
+ * Format date using pattern string
61
+ * @example chain(date).format('YYYY-MM-DD') // "2025-01-15"
62
+ */
63
+ format(pattern: string): string;
64
+ /**
65
+ * Format time in 12h, 24h, or ISO format
66
+ * @example chain(date).formatTime('12h') // "2:30 PM"
67
+ */
68
+ formatTime(fmt?: '12h' | '24h' | 'iso'): string;
69
+ /**
70
+ * Format as calendar date (Today, Yesterday, Monday, etc.)
71
+ * @example chain(date).calendar() // "Tomorrow"
72
+ */
73
+ calendar(): string;
74
+ /**
75
+ * Get relative time string
76
+ * @example chain(pastDate).ago() // "3 hours ago"
77
+ */
78
+ ago(options?: FormatOptions): string;
79
+ /**
80
+ * Get ISO string
81
+ */
82
+ toISOString(): string;
83
+ /**
84
+ * Get locale string
85
+ */
86
+ toLocaleString(locale?: string, options?: Intl.DateTimeFormatOptions): string;
87
+ /**
88
+ * Format day as ordinal
89
+ * @example chain(date).dayOrdinal() // "15th"
90
+ */
91
+ dayOrdinal(): string;
92
+ /**
93
+ * Check if date is valid
94
+ */
95
+ isValid(): boolean;
96
+ /**
97
+ * Check if date is today
98
+ */
99
+ isToday(): boolean;
100
+ /**
101
+ * Check if date is yesterday
102
+ */
103
+ isYesterday(): boolean;
104
+ /**
105
+ * Check if date is tomorrow
106
+ */
107
+ isTomorrow(): boolean;
108
+ /**
109
+ * Check if date is in the past
110
+ */
111
+ isPast(): boolean;
112
+ /**
113
+ * Check if date is in the future
114
+ */
115
+ isFuture(): boolean;
116
+ /**
117
+ * Check if date is a weekend
118
+ */
119
+ isWeekend(): boolean;
120
+ /**
121
+ * Check if date is a weekday
122
+ */
123
+ isWeekday(): boolean;
124
+ /**
125
+ * Check if date is in this week
126
+ */
127
+ isThisWeek(): boolean;
128
+ /**
129
+ * Check if date is in this month
130
+ */
131
+ isThisMonth(): boolean;
132
+ /**
133
+ * Check if date is in this year
134
+ */
135
+ isThisYear(): boolean;
136
+ /**
137
+ * Check if year is a leap year
138
+ */
139
+ isLeapYear(): boolean;
140
+ /**
141
+ * Check if date is a business day
142
+ */
143
+ isBusinessDay(holidays?: Date[]): boolean;
144
+ /**
145
+ * Check if date is same day as another
146
+ */
147
+ isSameDay(other: DateInput): boolean;
148
+ /**
149
+ * Check if date is same week as another
150
+ */
151
+ isSameWeek(other: DateInput): boolean;
152
+ /**
153
+ * Check if date is same month as another
154
+ */
155
+ isSameMonth(other: DateInput): boolean;
156
+ /**
157
+ * Check if date is same year as another
158
+ */
159
+ isSameYear(other: DateInput): boolean;
160
+ /**
161
+ * Check if date is before another
162
+ */
163
+ isBefore(other: DateInput): boolean;
164
+ /**
165
+ * Check if date is after another
166
+ */
167
+ isAfter(other: DateInput): boolean;
168
+ /**
169
+ * Check if date is between two dates
170
+ */
171
+ isBetween(start: DateInput, end: DateInput, inclusive?: boolean): boolean;
172
+ /**
173
+ * Get difference from another date
174
+ * @example chain(date).diff(other, 'days') // 5
175
+ */
176
+ diff(other: DateInput, unit?: TimeUnit, precise?: boolean): number;
177
+ /**
178
+ * Get the timestamp (milliseconds since epoch)
179
+ */
180
+ valueOf(): number;
181
+ /**
182
+ * Get year
183
+ */
184
+ year(): number;
185
+ /**
186
+ * Get month (1-12)
187
+ */
188
+ month(): number;
189
+ /**
190
+ * Get day of month (1-31)
191
+ */
192
+ day(): number;
193
+ /**
194
+ * Get day of week (0-6, 0=Sunday)
195
+ */
196
+ weekday(): number;
197
+ /**
198
+ * Get hours (0-23)
199
+ */
200
+ hours(): number;
201
+ /**
202
+ * Get minutes (0-59)
203
+ */
204
+ minutes(): number;
205
+ /**
206
+ * Get seconds (0-59)
207
+ */
208
+ seconds(): number;
209
+ /**
210
+ * Get milliseconds (0-999)
211
+ */
212
+ milliseconds(): number;
213
+ /**
214
+ * Get day of year (1-366)
215
+ */
216
+ dayOfYear(): number;
217
+ /**
218
+ * Get ISO week number (1-53)
219
+ */
220
+ week(): number;
221
+ /**
222
+ * Get quarter (1-4)
223
+ */
224
+ quarter(): number;
225
+ /**
226
+ * Get days in month
227
+ */
228
+ daysInMonth(): number;
229
+ /**
230
+ * Get the underlying Date object
231
+ */
232
+ toDate(): Date;
233
+ /**
234
+ * Get Unix timestamp (seconds)
235
+ */
236
+ unix(): number;
237
+ /**
238
+ * Convert to array [year, month, day, hours, minutes, seconds, ms]
239
+ */
240
+ toArray(): [number, number, number, number, number, number, number];
241
+ /**
242
+ * Convert to object
243
+ */
244
+ toObject(): {
245
+ year: number;
246
+ month: number;
247
+ day: number;
248
+ hours: number;
249
+ minutes: number;
250
+ seconds: number;
251
+ milliseconds: number;
252
+ };
253
+ }
254
+ /**
255
+ * Create a chainable date wrapper
256
+ * @example
257
+ * chain(new Date()).add(1, 'day').format('YYYY-MM-DD')
258
+ * chain('2025-01-15').startOf('month').toDate()
259
+ * chain().add(1, 'week').isWeekend()
260
+ */
261
+ export declare function chain(date?: DateInput): ChainedDate;
262
+ /**
263
+ * Format a duration in milliseconds
264
+ * Convenience export for use with chain().diff()
265
+ * @example formatMs(chain(a).diff(b)) // "2 days, 3 hours"
266
+ */
267
+ export declare function formatMs(ms: number, options?: FormatOptions): string;
268
+ export {};
269
+ //# sourceMappingURL=chain.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chain.d.ts","sourceRoot":"","sources":["../src/chain.ts"],"names":[],"mappings":"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"}