ts-time-utils 1.1.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.
Files changed (92) hide show
  1. package/README.md +567 -12
  2. package/dist/calculate.d.ts +7 -2
  3. package/dist/calculate.d.ts.map +1 -1
  4. package/dist/calculate.js +13 -3
  5. package/dist/calendar.d.ts +103 -0
  6. package/dist/calendar.d.ts.map +1 -1
  7. package/dist/calendar.js +224 -0
  8. package/dist/chain.d.ts +269 -0
  9. package/dist/chain.d.ts.map +1 -0
  10. package/dist/chain.js +422 -0
  11. package/dist/compare.d.ts +217 -0
  12. package/dist/compare.d.ts.map +1 -0
  13. package/dist/compare.js +417 -0
  14. package/dist/cron.d.ts +82 -0
  15. package/dist/cron.d.ts.map +1 -0
  16. package/dist/cron.js +294 -0
  17. package/dist/esm/calculate.d.ts +7 -2
  18. package/dist/esm/calculate.d.ts.map +1 -1
  19. package/dist/esm/calculate.js +13 -3
  20. package/dist/esm/calendar.d.ts +103 -0
  21. package/dist/esm/calendar.d.ts.map +1 -1
  22. package/dist/esm/calendar.js +224 -0
  23. package/dist/esm/chain.d.ts +269 -0
  24. package/dist/esm/chain.d.ts.map +1 -0
  25. package/dist/esm/chain.js +422 -0
  26. package/dist/esm/compare.d.ts +217 -0
  27. package/dist/esm/compare.d.ts.map +1 -0
  28. package/dist/esm/compare.js +417 -0
  29. package/dist/esm/cron.d.ts +82 -0
  30. package/dist/esm/cron.d.ts.map +1 -0
  31. package/dist/esm/cron.js +294 -0
  32. package/dist/esm/fiscal.d.ts +195 -0
  33. package/dist/esm/fiscal.d.ts.map +1 -0
  34. package/dist/esm/fiscal.js +295 -0
  35. package/dist/esm/format.d.ts +65 -0
  36. package/dist/esm/format.d.ts.map +1 -1
  37. package/dist/esm/format.js +202 -0
  38. package/dist/esm/holidays.d.ts +62 -0
  39. package/dist/esm/holidays.d.ts.map +1 -0
  40. package/dist/esm/holidays.js +793 -0
  41. package/dist/esm/index.d.ts +18 -6
  42. package/dist/esm/index.d.ts.map +1 -1
  43. package/dist/esm/index.js +20 -6
  44. package/dist/esm/iterate.d.ts +212 -0
  45. package/dist/esm/iterate.d.ts.map +1 -0
  46. package/dist/esm/iterate.js +409 -0
  47. package/dist/esm/parse.d.ts +45 -0
  48. package/dist/esm/parse.d.ts.map +1 -1
  49. package/dist/esm/parse.js +207 -0
  50. package/dist/esm/plugins.d.ts +129 -0
  51. package/dist/esm/plugins.d.ts.map +1 -0
  52. package/dist/esm/plugins.js +173 -0
  53. package/dist/esm/timezone.d.ts +52 -0
  54. package/dist/esm/timezone.d.ts.map +1 -1
  55. package/dist/esm/timezone.js +171 -0
  56. package/dist/esm/validate.d.ts +51 -0
  57. package/dist/esm/validate.d.ts.map +1 -1
  58. package/dist/esm/validate.js +92 -0
  59. package/dist/esm/workingHours.d.ts +70 -0
  60. package/dist/esm/workingHours.d.ts.map +1 -1
  61. package/dist/esm/workingHours.js +161 -0
  62. package/dist/fiscal.d.ts +195 -0
  63. package/dist/fiscal.d.ts.map +1 -0
  64. package/dist/fiscal.js +295 -0
  65. package/dist/format.d.ts +65 -0
  66. package/dist/format.d.ts.map +1 -1
  67. package/dist/format.js +202 -0
  68. package/dist/holidays.d.ts +62 -0
  69. package/dist/holidays.d.ts.map +1 -0
  70. package/dist/holidays.js +793 -0
  71. package/dist/index.d.ts +18 -6
  72. package/dist/index.d.ts.map +1 -1
  73. package/dist/index.js +20 -6
  74. package/dist/iterate.d.ts +212 -0
  75. package/dist/iterate.d.ts.map +1 -0
  76. package/dist/iterate.js +409 -0
  77. package/dist/parse.d.ts +45 -0
  78. package/dist/parse.d.ts.map +1 -1
  79. package/dist/parse.js +207 -0
  80. package/dist/plugins.d.ts +129 -0
  81. package/dist/plugins.d.ts.map +1 -0
  82. package/dist/plugins.js +173 -0
  83. package/dist/timezone.d.ts +52 -0
  84. package/dist/timezone.d.ts.map +1 -1
  85. package/dist/timezone.js +171 -0
  86. package/dist/validate.d.ts +51 -0
  87. package/dist/validate.d.ts.map +1 -1
  88. package/dist/validate.js +92 -0
  89. package/dist/workingHours.d.ts +70 -0
  90. package/dist/workingHours.d.ts.map +1 -1
  91. package/dist/workingHours.js +161 -0
  92. package/package.json +40 -1
@@ -0,0 +1,793 @@
1
+ /**
2
+ * @fileoverview International holiday utilities
3
+ * Calculate holidays for multiple countries including fixed, movable, and lunar-based holidays
4
+ */
5
+ /**
6
+ * Calculate Easter Sunday using the Anonymous Gregorian algorithm
7
+ * @param year - The year
8
+ * @returns Date of Easter Sunday
9
+ */
10
+ function getEasterSunday(year) {
11
+ const a = year % 19;
12
+ const b = Math.floor(year / 100);
13
+ const c = year % 100;
14
+ const d = Math.floor(b / 4);
15
+ const e = b % 4;
16
+ const f = Math.floor((b + 8) / 25);
17
+ const g = Math.floor((b - f + 1) / 3);
18
+ const h = (19 * a + b - d - g + 15) % 30;
19
+ const i = Math.floor(c / 4);
20
+ const k = c % 4;
21
+ const l = (32 + 2 * e + 2 * i - h - k) % 7;
22
+ const m = Math.floor((a + 11 * h + 22 * l) / 451);
23
+ const month = Math.floor((h + l - 7 * m + 114) / 31);
24
+ const day = ((h + l - 7 * m + 114) % 31) + 1;
25
+ return new Date(year, month - 1, day);
26
+ }
27
+ /**
28
+ * Get nth occurrence of a weekday in a month
29
+ */
30
+ function getNthWeekdayOfMonth(year, month, dayOfWeek, n) {
31
+ const firstDay = new Date(year, month, 1);
32
+ const firstWeekday = firstDay.getDay();
33
+ let dayOffset = dayOfWeek - firstWeekday;
34
+ if (dayOffset < 0)
35
+ dayOffset += 7;
36
+ const date = 1 + dayOffset + (n - 1) * 7;
37
+ return new Date(year, month, date);
38
+ }
39
+ /**
40
+ * Get last occurrence of a weekday in a month
41
+ */
42
+ function getLastWeekdayOfMonth(year, month, dayOfWeek) {
43
+ const lastDay = new Date(year, month + 1, 0);
44
+ const lastDate = lastDay.getDate();
45
+ const lastWeekday = lastDay.getDay();
46
+ let diff = lastWeekday - dayOfWeek;
47
+ if (diff < 0)
48
+ diff += 7;
49
+ return new Date(year, month, lastDate - diff);
50
+ }
51
+ /**
52
+ * Adjust date if it falls on a weekend (move to Monday)
53
+ */
54
+ function adjustForWeekend(date) {
55
+ const day = date.getDay();
56
+ if (day === 0) { // Sunday
57
+ return new Date(date.getFullYear(), date.getMonth(), date.getDate() + 1);
58
+ }
59
+ else if (day === 6) { // Saturday
60
+ return new Date(date.getFullYear(), date.getMonth(), date.getDate() + 2);
61
+ }
62
+ return date;
63
+ }
64
+ // ============================================================================
65
+ // UK HOLIDAYS
66
+ // ============================================================================
67
+ export function getUKHolidays(year) {
68
+ const holidays = [];
69
+ // New Year's Day (or substitute)
70
+ holidays.push({
71
+ name: "New Year's Day",
72
+ date: adjustForWeekend(new Date(year, 0, 1)),
73
+ countryCode: 'UK',
74
+ type: 'bank'
75
+ });
76
+ // Good Friday (Easter - 2 days)
77
+ const easter = getEasterSunday(year);
78
+ holidays.push({
79
+ name: 'Good Friday',
80
+ date: new Date(easter.getFullYear(), easter.getMonth(), easter.getDate() - 2),
81
+ countryCode: 'UK',
82
+ type: 'bank'
83
+ });
84
+ // Easter Monday (Easter + 1 day)
85
+ holidays.push({
86
+ name: 'Easter Monday',
87
+ date: new Date(easter.getFullYear(), easter.getMonth(), easter.getDate() + 1),
88
+ countryCode: 'UK',
89
+ type: 'bank'
90
+ });
91
+ // Early May Bank Holiday (first Monday in May)
92
+ holidays.push({
93
+ name: 'Early May Bank Holiday',
94
+ date: getNthWeekdayOfMonth(year, 4, 1, 1),
95
+ countryCode: 'UK',
96
+ type: 'bank'
97
+ });
98
+ // Spring Bank Holiday (last Monday in May)
99
+ holidays.push({
100
+ name: 'Spring Bank Holiday',
101
+ date: getLastWeekdayOfMonth(year, 4, 1),
102
+ countryCode: 'UK',
103
+ type: 'bank'
104
+ });
105
+ // Summer Bank Holiday (last Monday in August)
106
+ holidays.push({
107
+ name: 'Summer Bank Holiday',
108
+ date: getLastWeekdayOfMonth(year, 7, 1),
109
+ countryCode: 'UK',
110
+ type: 'bank'
111
+ });
112
+ // Christmas Day
113
+ holidays.push({
114
+ name: 'Christmas Day',
115
+ date: adjustForWeekend(new Date(year, 11, 25)),
116
+ countryCode: 'UK',
117
+ type: 'bank'
118
+ });
119
+ // Boxing Day
120
+ const christmas = new Date(year, 11, 25);
121
+ let boxingDay = new Date(year, 11, 26);
122
+ if (christmas.getDay() === 6) { // Christmas on Saturday
123
+ boxingDay = new Date(year, 11, 28); // Monday
124
+ }
125
+ else if (christmas.getDay() === 0) { // Christmas on Sunday
126
+ boxingDay = new Date(year, 11, 27); // Tuesday (Monday is Christmas substitute)
127
+ }
128
+ else {
129
+ boxingDay = adjustForWeekend(boxingDay);
130
+ }
131
+ holidays.push({
132
+ name: 'Boxing Day',
133
+ date: boxingDay,
134
+ countryCode: 'UK',
135
+ type: 'bank'
136
+ });
137
+ return holidays;
138
+ }
139
+ // ============================================================================
140
+ // NETHERLANDS HOLIDAYS
141
+ // ============================================================================
142
+ export function getNetherlandsHolidays(year) {
143
+ const holidays = [];
144
+ const easter = getEasterSunday(year);
145
+ // New Year's Day
146
+ holidays.push({
147
+ name: "New Year's Day",
148
+ date: new Date(year, 0, 1),
149
+ countryCode: 'NL',
150
+ type: 'public'
151
+ });
152
+ // Good Friday
153
+ holidays.push({
154
+ name: 'Good Friday',
155
+ date: new Date(easter.getFullYear(), easter.getMonth(), easter.getDate() - 2),
156
+ countryCode: 'NL',
157
+ type: 'observance'
158
+ });
159
+ // Easter Sunday
160
+ holidays.push({
161
+ name: 'Easter Sunday',
162
+ date: easter,
163
+ countryCode: 'NL',
164
+ type: 'public'
165
+ });
166
+ // Easter Monday
167
+ holidays.push({
168
+ name: 'Easter Monday',
169
+ date: new Date(easter.getFullYear(), easter.getMonth(), easter.getDate() + 1),
170
+ countryCode: 'NL',
171
+ type: 'public'
172
+ });
173
+ // King's Day (April 27, or 26 if 27th is Sunday)
174
+ const kingsDay = new Date(year, 3, 27);
175
+ if (kingsDay.getDay() === 0) {
176
+ holidays.push({
177
+ name: "King's Day",
178
+ date: new Date(year, 3, 26),
179
+ countryCode: 'NL',
180
+ type: 'public'
181
+ });
182
+ }
183
+ else {
184
+ holidays.push({
185
+ name: "King's Day",
186
+ date: kingsDay,
187
+ countryCode: 'NL',
188
+ type: 'public'
189
+ });
190
+ }
191
+ // Liberation Day (May 5)
192
+ holidays.push({
193
+ name: 'Liberation Day',
194
+ date: new Date(year, 4, 5),
195
+ countryCode: 'NL',
196
+ type: 'public'
197
+ });
198
+ // Ascension Day (Easter + 39 days)
199
+ holidays.push({
200
+ name: 'Ascension Day',
201
+ date: new Date(easter.getFullYear(), easter.getMonth(), easter.getDate() + 39),
202
+ countryCode: 'NL',
203
+ type: 'public'
204
+ });
205
+ // Whit Sunday (Easter + 49 days)
206
+ holidays.push({
207
+ name: 'Whit Sunday',
208
+ date: new Date(easter.getFullYear(), easter.getMonth(), easter.getDate() + 49),
209
+ countryCode: 'NL',
210
+ type: 'public'
211
+ });
212
+ // Whit Monday (Easter + 50 days)
213
+ holidays.push({
214
+ name: 'Whit Monday',
215
+ date: new Date(easter.getFullYear(), easter.getMonth(), easter.getDate() + 50),
216
+ countryCode: 'NL',
217
+ type: 'public'
218
+ });
219
+ // Christmas Day
220
+ holidays.push({
221
+ name: 'Christmas Day',
222
+ date: new Date(year, 11, 25),
223
+ countryCode: 'NL',
224
+ type: 'public'
225
+ });
226
+ // Boxing Day
227
+ holidays.push({
228
+ name: 'Boxing Day',
229
+ date: new Date(year, 11, 26),
230
+ countryCode: 'NL',
231
+ type: 'public'
232
+ });
233
+ return holidays;
234
+ }
235
+ // ============================================================================
236
+ // GERMANY HOLIDAYS
237
+ // ============================================================================
238
+ export function getGermanyHolidays(year) {
239
+ const holidays = [];
240
+ const easter = getEasterSunday(year);
241
+ // New Year's Day
242
+ holidays.push({
243
+ name: "New Year's Day",
244
+ date: new Date(year, 0, 1),
245
+ countryCode: 'DE',
246
+ type: 'public'
247
+ });
248
+ // Good Friday
249
+ holidays.push({
250
+ name: 'Good Friday',
251
+ date: new Date(easter.getFullYear(), easter.getMonth(), easter.getDate() - 2),
252
+ countryCode: 'DE',
253
+ type: 'public'
254
+ });
255
+ // Easter Monday
256
+ holidays.push({
257
+ name: 'Easter Monday',
258
+ date: new Date(easter.getFullYear(), easter.getMonth(), easter.getDate() + 1),
259
+ countryCode: 'DE',
260
+ type: 'public'
261
+ });
262
+ // Labour Day
263
+ holidays.push({
264
+ name: 'Labour Day',
265
+ date: new Date(year, 4, 1),
266
+ countryCode: 'DE',
267
+ type: 'public'
268
+ });
269
+ // Ascension Day
270
+ holidays.push({
271
+ name: 'Ascension Day',
272
+ date: new Date(easter.getFullYear(), easter.getMonth(), easter.getDate() + 39),
273
+ countryCode: 'DE',
274
+ type: 'public'
275
+ });
276
+ // Whit Monday
277
+ holidays.push({
278
+ name: 'Whit Monday',
279
+ date: new Date(easter.getFullYear(), easter.getMonth(), easter.getDate() + 50),
280
+ countryCode: 'DE',
281
+ type: 'public'
282
+ });
283
+ // German Unity Day
284
+ holidays.push({
285
+ name: 'German Unity Day',
286
+ date: new Date(year, 9, 3),
287
+ countryCode: 'DE',
288
+ type: 'public'
289
+ });
290
+ // Christmas Day
291
+ holidays.push({
292
+ name: 'Christmas Day',
293
+ date: new Date(year, 11, 25),
294
+ countryCode: 'DE',
295
+ type: 'public'
296
+ });
297
+ // Boxing Day
298
+ holidays.push({
299
+ name: 'Boxing Day',
300
+ date: new Date(year, 11, 26),
301
+ countryCode: 'DE',
302
+ type: 'public'
303
+ });
304
+ return holidays;
305
+ }
306
+ // ============================================================================
307
+ // CANADA HOLIDAYS
308
+ // ============================================================================
309
+ export function getCanadaHolidays(year) {
310
+ const holidays = [];
311
+ const easter = getEasterSunday(year);
312
+ // New Year's Day
313
+ holidays.push({
314
+ name: "New Year's Day",
315
+ date: adjustForWeekend(new Date(year, 0, 1)),
316
+ countryCode: 'CA',
317
+ type: 'public'
318
+ });
319
+ // Good Friday
320
+ holidays.push({
321
+ name: 'Good Friday',
322
+ date: new Date(easter.getFullYear(), easter.getMonth(), easter.getDate() - 2),
323
+ countryCode: 'CA',
324
+ type: 'public'
325
+ });
326
+ // Victoria Day (Monday before May 25)
327
+ const may24 = new Date(year, 4, 24);
328
+ const victoriaDay = new Date(year, 4, 24 - ((may24.getDay() + 6) % 7));
329
+ holidays.push({
330
+ name: 'Victoria Day',
331
+ date: victoriaDay,
332
+ countryCode: 'CA',
333
+ type: 'public'
334
+ });
335
+ // Canada Day (July 1, or substitute)
336
+ holidays.push({
337
+ name: 'Canada Day',
338
+ date: adjustForWeekend(new Date(year, 6, 1)),
339
+ countryCode: 'CA',
340
+ type: 'public'
341
+ });
342
+ // Labour Day (first Monday in September)
343
+ holidays.push({
344
+ name: 'Labour Day',
345
+ date: getNthWeekdayOfMonth(year, 8, 1, 1),
346
+ countryCode: 'CA',
347
+ type: 'public'
348
+ });
349
+ // Thanksgiving (second Monday in October)
350
+ holidays.push({
351
+ name: 'Thanksgiving',
352
+ date: getNthWeekdayOfMonth(year, 9, 1, 2),
353
+ countryCode: 'CA',
354
+ type: 'public'
355
+ });
356
+ // Remembrance Day
357
+ holidays.push({
358
+ name: 'Remembrance Day',
359
+ date: new Date(year, 10, 11),
360
+ countryCode: 'CA',
361
+ type: 'public'
362
+ });
363
+ // Christmas Day
364
+ holidays.push({
365
+ name: 'Christmas Day',
366
+ date: adjustForWeekend(new Date(year, 11, 25)),
367
+ countryCode: 'CA',
368
+ type: 'public'
369
+ });
370
+ // Boxing Day
371
+ holidays.push({
372
+ name: 'Boxing Day',
373
+ date: adjustForWeekend(new Date(year, 11, 26)),
374
+ countryCode: 'CA',
375
+ type: 'public'
376
+ });
377
+ return holidays;
378
+ }
379
+ // ============================================================================
380
+ // AUSTRALIA HOLIDAYS
381
+ // ============================================================================
382
+ export function getAustraliaHolidays(year) {
383
+ const holidays = [];
384
+ const easter = getEasterSunday(year);
385
+ // New Year's Day
386
+ holidays.push({
387
+ name: "New Year's Day",
388
+ date: adjustForWeekend(new Date(year, 0, 1)),
389
+ countryCode: 'AU',
390
+ type: 'public'
391
+ });
392
+ // Australia Day (January 26)
393
+ holidays.push({
394
+ name: 'Australia Day',
395
+ date: adjustForWeekend(new Date(year, 0, 26)),
396
+ countryCode: 'AU',
397
+ type: 'public'
398
+ });
399
+ // Good Friday
400
+ holidays.push({
401
+ name: 'Good Friday',
402
+ date: new Date(easter.getFullYear(), easter.getMonth(), easter.getDate() - 2),
403
+ countryCode: 'AU',
404
+ type: 'public'
405
+ });
406
+ // Easter Saturday
407
+ holidays.push({
408
+ name: 'Easter Saturday',
409
+ date: new Date(easter.getFullYear(), easter.getMonth(), easter.getDate() - 1),
410
+ countryCode: 'AU',
411
+ type: 'public'
412
+ });
413
+ // Easter Monday
414
+ holidays.push({
415
+ name: 'Easter Monday',
416
+ date: new Date(easter.getFullYear(), easter.getMonth(), easter.getDate() + 1),
417
+ countryCode: 'AU',
418
+ type: 'public'
419
+ });
420
+ // Anzac Day (April 25)
421
+ holidays.push({
422
+ name: 'Anzac Day',
423
+ date: new Date(year, 3, 25),
424
+ countryCode: 'AU',
425
+ type: 'public'
426
+ });
427
+ // Queen's Birthday (second Monday in June)
428
+ holidays.push({
429
+ name: "Queen's Birthday",
430
+ date: getNthWeekdayOfMonth(year, 5, 1, 2),
431
+ countryCode: 'AU',
432
+ type: 'public'
433
+ });
434
+ // Christmas Day
435
+ holidays.push({
436
+ name: 'Christmas Day',
437
+ date: adjustForWeekend(new Date(year, 11, 25)),
438
+ countryCode: 'AU',
439
+ type: 'public'
440
+ });
441
+ // Boxing Day
442
+ holidays.push({
443
+ name: 'Boxing Day',
444
+ date: adjustForWeekend(new Date(year, 11, 26)),
445
+ countryCode: 'AU',
446
+ type: 'public'
447
+ });
448
+ return holidays;
449
+ }
450
+ // ============================================================================
451
+ // ITALY HOLIDAYS
452
+ // ============================================================================
453
+ export function getItalyHolidays(year) {
454
+ const holidays = [];
455
+ const easter = getEasterSunday(year);
456
+ // New Year's Day
457
+ holidays.push({
458
+ name: "New Year's Day",
459
+ date: new Date(year, 0, 1),
460
+ countryCode: 'IT',
461
+ type: 'public'
462
+ });
463
+ // Epiphany
464
+ holidays.push({
465
+ name: 'Epiphany',
466
+ date: new Date(year, 0, 6),
467
+ countryCode: 'IT',
468
+ type: 'public'
469
+ });
470
+ // Easter Monday
471
+ holidays.push({
472
+ name: 'Easter Monday',
473
+ date: new Date(easter.getFullYear(), easter.getMonth(), easter.getDate() + 1),
474
+ countryCode: 'IT',
475
+ type: 'public'
476
+ });
477
+ // Liberation Day
478
+ holidays.push({
479
+ name: 'Liberation Day',
480
+ date: new Date(year, 3, 25),
481
+ countryCode: 'IT',
482
+ type: 'public'
483
+ });
484
+ // Labour Day
485
+ holidays.push({
486
+ name: 'Labour Day',
487
+ date: new Date(year, 4, 1),
488
+ countryCode: 'IT',
489
+ type: 'public'
490
+ });
491
+ // Republic Day
492
+ holidays.push({
493
+ name: 'Republic Day',
494
+ date: new Date(year, 5, 2),
495
+ countryCode: 'IT',
496
+ type: 'public'
497
+ });
498
+ // Assumption of Mary
499
+ holidays.push({
500
+ name: 'Assumption of Mary',
501
+ date: new Date(year, 7, 15),
502
+ countryCode: 'IT',
503
+ type: 'public'
504
+ });
505
+ // All Saints' Day
506
+ holidays.push({
507
+ name: "All Saints' Day",
508
+ date: new Date(year, 10, 1),
509
+ countryCode: 'IT',
510
+ type: 'public'
511
+ });
512
+ // Immaculate Conception
513
+ holidays.push({
514
+ name: 'Immaculate Conception',
515
+ date: new Date(year, 11, 8),
516
+ countryCode: 'IT',
517
+ type: 'public'
518
+ });
519
+ // Christmas Day
520
+ holidays.push({
521
+ name: 'Christmas Day',
522
+ date: new Date(year, 11, 25),
523
+ countryCode: 'IT',
524
+ type: 'public'
525
+ });
526
+ // St. Stephen's Day
527
+ holidays.push({
528
+ name: "St. Stephen's Day",
529
+ date: new Date(year, 11, 26),
530
+ countryCode: 'IT',
531
+ type: 'public'
532
+ });
533
+ return holidays;
534
+ }
535
+ // ============================================================================
536
+ // SPAIN HOLIDAYS
537
+ // ============================================================================
538
+ export function getSpainHolidays(year) {
539
+ const holidays = [];
540
+ const easter = getEasterSunday(year);
541
+ // New Year's Day
542
+ holidays.push({
543
+ name: "New Year's Day",
544
+ date: new Date(year, 0, 1),
545
+ countryCode: 'ES',
546
+ type: 'public'
547
+ });
548
+ // Epiphany
549
+ holidays.push({
550
+ name: 'Epiphany',
551
+ date: new Date(year, 0, 6),
552
+ countryCode: 'ES',
553
+ type: 'public'
554
+ });
555
+ // Good Friday
556
+ holidays.push({
557
+ name: 'Good Friday',
558
+ date: new Date(easter.getFullYear(), easter.getMonth(), easter.getDate() - 2),
559
+ countryCode: 'ES',
560
+ type: 'public'
561
+ });
562
+ // Labour Day
563
+ holidays.push({
564
+ name: 'Labour Day',
565
+ date: new Date(year, 4, 1),
566
+ countryCode: 'ES',
567
+ type: 'public'
568
+ });
569
+ // Assumption of Mary
570
+ holidays.push({
571
+ name: 'Assumption of Mary',
572
+ date: new Date(year, 7, 15),
573
+ countryCode: 'ES',
574
+ type: 'public'
575
+ });
576
+ // National Day of Spain
577
+ holidays.push({
578
+ name: 'National Day of Spain',
579
+ date: new Date(year, 9, 12),
580
+ countryCode: 'ES',
581
+ type: 'public'
582
+ });
583
+ // All Saints' Day
584
+ holidays.push({
585
+ name: "All Saints' Day",
586
+ date: new Date(year, 10, 1),
587
+ countryCode: 'ES',
588
+ type: 'public'
589
+ });
590
+ // Constitution Day
591
+ holidays.push({
592
+ name: 'Constitution Day',
593
+ date: new Date(year, 11, 6),
594
+ countryCode: 'ES',
595
+ type: 'public'
596
+ });
597
+ // Immaculate Conception
598
+ holidays.push({
599
+ name: 'Immaculate Conception',
600
+ date: new Date(year, 11, 8),
601
+ countryCode: 'ES',
602
+ type: 'public'
603
+ });
604
+ // Christmas Day
605
+ holidays.push({
606
+ name: 'Christmas Day',
607
+ date: new Date(year, 11, 25),
608
+ countryCode: 'ES',
609
+ type: 'public'
610
+ });
611
+ return holidays;
612
+ }
613
+ // ============================================================================
614
+ // CHINA HOLIDAYS (Simplified - some are lunar calendar based)
615
+ // ============================================================================
616
+ export function getChinaHolidays(year) {
617
+ const holidays = [];
618
+ // New Year's Day
619
+ holidays.push({
620
+ name: "New Year's Day",
621
+ date: new Date(year, 0, 1),
622
+ countryCode: 'CN',
623
+ type: 'public'
624
+ });
625
+ // Note: Spring Festival (Chinese New Year) is lunar calendar based
626
+ // This is a simplified version - actual dates vary by year
627
+ // Would need a lunar calendar library for accurate dates
628
+ // Tomb Sweeping Day (April 4 or 5)
629
+ holidays.push({
630
+ name: 'Tomb Sweeping Day',
631
+ date: new Date(year, 3, 4),
632
+ countryCode: 'CN',
633
+ type: 'public'
634
+ });
635
+ // Labour Day
636
+ holidays.push({
637
+ name: 'Labour Day',
638
+ date: new Date(year, 4, 1),
639
+ countryCode: 'CN',
640
+ type: 'public'
641
+ });
642
+ // Dragon Boat Festival (lunar calendar - approximate)
643
+ // Note: Actual date varies, this is simplified
644
+ // Mid-Autumn Festival (lunar calendar - approximate)
645
+ // Note: Actual date varies, this is simplified
646
+ // National Day
647
+ holidays.push({
648
+ name: 'National Day',
649
+ date: new Date(year, 9, 1),
650
+ countryCode: 'CN',
651
+ type: 'public'
652
+ });
653
+ return holidays;
654
+ }
655
+ // ============================================================================
656
+ // INDIA HOLIDAYS (Simplified - many are lunar calendar based)
657
+ // ============================================================================
658
+ export function getIndiaHolidays(year) {
659
+ const holidays = [];
660
+ // Republic Day
661
+ holidays.push({
662
+ name: 'Republic Day',
663
+ date: new Date(year, 0, 26),
664
+ countryCode: 'IN',
665
+ type: 'public'
666
+ });
667
+ // Independence Day
668
+ holidays.push({
669
+ name: 'Independence Day',
670
+ date: new Date(year, 7, 15),
671
+ countryCode: 'IN',
672
+ type: 'public'
673
+ });
674
+ // Gandhi Jayanti
675
+ holidays.push({
676
+ name: 'Gandhi Jayanti',
677
+ date: new Date(year, 9, 2),
678
+ countryCode: 'IN',
679
+ type: 'public'
680
+ });
681
+ // Note: Diwali, Holi, Eid, etc. are lunar calendar based
682
+ // Would need a lunar calendar library for accurate dates
683
+ return holidays;
684
+ }
685
+ // ============================================================================
686
+ // UNIFIED API
687
+ // ============================================================================
688
+ /**
689
+ * Get holidays for a specific country and year
690
+ * @param year - The year
691
+ * @param countryCode - ISO country code
692
+ * @returns Array of holidays
693
+ */
694
+ export function getHolidays(year, countryCode) {
695
+ switch (countryCode) {
696
+ case 'UK':
697
+ return getUKHolidays(year);
698
+ case 'NL':
699
+ return getNetherlandsHolidays(year);
700
+ case 'DE':
701
+ return getGermanyHolidays(year);
702
+ case 'CA':
703
+ return getCanadaHolidays(year);
704
+ case 'AU':
705
+ return getAustraliaHolidays(year);
706
+ case 'IT':
707
+ return getItalyHolidays(year);
708
+ case 'ES':
709
+ return getSpainHolidays(year);
710
+ case 'CN':
711
+ return getChinaHolidays(year);
712
+ case 'IN':
713
+ return getIndiaHolidays(year);
714
+ case 'US':
715
+ // Import from existing calendar module
716
+ return [];
717
+ default:
718
+ return [];
719
+ }
720
+ }
721
+ /**
722
+ * Check if a date is a holiday in a specific country
723
+ * @param date - The date to check
724
+ * @param countryCode - ISO country code
725
+ * @returns True if date is a holiday
726
+ */
727
+ export function isHoliday(date, countryCode) {
728
+ const holidays = getHolidays(date.getFullYear(), countryCode);
729
+ // Normalize to local date components for comparison
730
+ const targetYear = date.getFullYear();
731
+ const targetMonth = date.getMonth();
732
+ const targetDay = date.getDate();
733
+ return holidays.some(h => h.date.getFullYear() === targetYear &&
734
+ h.date.getMonth() === targetMonth &&
735
+ h.date.getDate() === targetDay);
736
+ }
737
+ /**
738
+ * Get the holiday name for a specific date and country
739
+ * @param date - The date to check
740
+ * @param countryCode - ISO country code
741
+ * @returns Holiday name or null if not a holiday
742
+ */
743
+ export function getHolidayName(date, countryCode) {
744
+ const holidays = getHolidays(date.getFullYear(), countryCode);
745
+ // Normalize to local date components for comparison
746
+ const targetYear = date.getFullYear();
747
+ const targetMonth = date.getMonth();
748
+ const targetDay = date.getDate();
749
+ const holiday = holidays.find(h => h.date.getFullYear() === targetYear &&
750
+ h.date.getMonth() === targetMonth &&
751
+ h.date.getDate() === targetDay);
752
+ return holiday ? holiday.name : null;
753
+ }
754
+ /**
755
+ * Get next holiday from a given date
756
+ * @param date - The reference date
757
+ * @param countryCode - ISO country code
758
+ * @returns Next holiday or null
759
+ */
760
+ export function getNextHoliday(date, countryCode) {
761
+ const year = date.getFullYear();
762
+ let holidays = getHolidays(year, countryCode);
763
+ // Also get next year's holidays
764
+ holidays = [...holidays, ...getHolidays(year + 1, countryCode)];
765
+ const future = holidays
766
+ .filter(h => h.date > date)
767
+ .sort((a, b) => a.date.getTime() - b.date.getTime());
768
+ return future[0] || null;
769
+ }
770
+ /**
771
+ * Get upcoming holidays within N days
772
+ * @param date - The reference date
773
+ * @param days - Number of days to look ahead
774
+ * @param countryCode - ISO country code
775
+ * @returns Array of upcoming holidays
776
+ */
777
+ export function getUpcomingHolidays(date, days, countryCode) {
778
+ const year = date.getFullYear();
779
+ let holidays = getHolidays(year, countryCode);
780
+ // Also get next year's holidays
781
+ holidays = [...holidays, ...getHolidays(year + 1, countryCode)];
782
+ const maxDate = new Date(date.getTime() + days * 24 * 60 * 60 * 1000);
783
+ return holidays
784
+ .filter(h => h.date > date && h.date <= maxDate)
785
+ .sort((a, b) => a.date.getTime() - b.date.getTime());
786
+ }
787
+ /**
788
+ * Get all supported country codes
789
+ * @returns Array of country codes
790
+ */
791
+ export function getSupportedCountries() {
792
+ return ['UK', 'NL', 'DE', 'CA', 'AU', 'IT', 'ES', 'CN', 'IN', 'US'];
793
+ }