superjs-core 0.4.3 → 0.5.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.
@@ -365,6 +365,315 @@ function toTimezone(date, offsetHours) {
365
365
  function formatInTimezone(date, format, offsetHours) {
366
366
  return formatDate(toTimezone(date, offsetHours), format);
367
367
  }
368
+ function isToday(date) {
369
+ if (!isValidDate(date)) throw new InvalidDateError(date);
370
+ const now = /* @__PURE__ */ new Date();
371
+ return date.getFullYear() === now.getFullYear() && date.getMonth() === now.getMonth() && date.getDate() === now.getDate();
372
+ }
373
+ function isYesterday(date) {
374
+ if (!isValidDate(date)) throw new InvalidDateError(date);
375
+ const yesterday = /* @__PURE__ */ new Date();
376
+ yesterday.setDate(yesterday.getDate() - 1);
377
+ return date.getFullYear() === yesterday.getFullYear() && date.getMonth() === yesterday.getMonth() && date.getDate() === yesterday.getDate();
378
+ }
379
+ function isTomorrow(date) {
380
+ if (!isValidDate(date)) throw new InvalidDateError(date);
381
+ const tomorrow = /* @__PURE__ */ new Date();
382
+ tomorrow.setDate(tomorrow.getDate() + 1);
383
+ return date.getFullYear() === tomorrow.getFullYear() && date.getMonth() === tomorrow.getMonth() && date.getDate() === tomorrow.getDate();
384
+ }
385
+ function isPast(date) {
386
+ if (!isValidDate(date)) throw new InvalidDateError(date);
387
+ return date.getTime() < Date.now();
388
+ }
389
+ function isFuture(date) {
390
+ if (!isValidDate(date)) throw new InvalidDateError(date);
391
+ return date.getTime() > Date.now();
392
+ }
393
+ function isSameDay(date1, date2) {
394
+ if (!isValidDate(date1) || !isValidDate(date2)) {
395
+ throw new InvalidDateError("Invalid date provided to isSameDay");
396
+ }
397
+ return date1.getFullYear() === date2.getFullYear() && date1.getMonth() === date2.getMonth() && date1.getDate() === date2.getDate();
398
+ }
399
+ function daysInMonth(date) {
400
+ if (!isValidDate(date)) throw new InvalidDateError(date);
401
+ return new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate();
402
+ }
403
+ function dayOfYear(date) {
404
+ if (!isValidDate(date)) throw new InvalidDateError(date);
405
+ const start = new Date(date.getFullYear(), 0, 0);
406
+ return Math.floor((date.getTime() - start.getTime()) / MS_IN_DAY);
407
+ }
408
+ function weekOfYear(date) {
409
+ if (!isValidDate(date)) throw new InvalidDateError(date);
410
+ const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
411
+ const dayNum = d.getUTCDay() || 7;
412
+ d.setUTCDate(d.getUTCDate() + 4 - dayNum);
413
+ const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
414
+ const weekNum = Math.ceil(((d.getTime() - yearStart.getTime()) / 864e5 + 1) / 7);
415
+ return weekNum;
416
+ }
417
+ function quarter(date) {
418
+ if (!isValidDate(date)) throw new InvalidDateError(date);
419
+ return Math.floor(date.getMonth() / 3) + 1;
420
+ }
421
+ function maxDate(dates) {
422
+ if (dates.length === 0) throw new Error("maxDate requires at least one date");
423
+ const ms = Math.max(...dates.map((d) => {
424
+ if (!isValidDate(d)) throw new InvalidDateError(d);
425
+ return d.getTime();
426
+ }));
427
+ return new Date(ms);
428
+ }
429
+ function minDate(dates) {
430
+ if (dates.length === 0) throw new Error("minDate requires at least one date");
431
+ const ms = Math.min(...dates.map((d) => {
432
+ if (!isValidDate(d)) throw new InvalidDateError(d);
433
+ return d.getTime();
434
+ }));
435
+ return new Date(ms);
436
+ }
437
+ function getNextWeekday(date, targetDay) {
438
+ if (!isValidDate(date)) throw new InvalidDateError(date);
439
+ const result = new Date(date);
440
+ const currentDay = result.getDay();
441
+ let diff = targetDay - currentDay;
442
+ if (diff <= 0) diff += 7;
443
+ result.setDate(result.getDate() + diff);
444
+ return result;
445
+ }
446
+ function getLastWeekday(date, targetDay) {
447
+ if (!isValidDate(date)) throw new InvalidDateError(date);
448
+ const result = new Date(date);
449
+ const currentDay = result.getDay();
450
+ let diff = currentDay - targetDay;
451
+ if (diff <= 0) diff += 7;
452
+ result.setDate(result.getDate() - diff);
453
+ return result;
454
+ }
455
+ function nextMonday(date) {
456
+ return getNextWeekday(date, 1);
457
+ }
458
+ function nextTuesday(date) {
459
+ return getNextWeekday(date, 2);
460
+ }
461
+ function nextWednesday(date) {
462
+ return getNextWeekday(date, 3);
463
+ }
464
+ function nextThursday(date) {
465
+ return getNextWeekday(date, 4);
466
+ }
467
+ function nextFriday(date) {
468
+ return getNextWeekday(date, 5);
469
+ }
470
+ function nextSaturday(date) {
471
+ return getNextWeekday(date, 6);
472
+ }
473
+ function nextSunday(date) {
474
+ return getNextWeekday(date, 0);
475
+ }
476
+ function lastMonday(date) {
477
+ return getLastWeekday(date, 1);
478
+ }
479
+ function lastTuesday(date) {
480
+ return getLastWeekday(date, 2);
481
+ }
482
+ function lastWednesday(date) {
483
+ return getLastWeekday(date, 3);
484
+ }
485
+ function lastThursday(date) {
486
+ return getLastWeekday(date, 4);
487
+ }
488
+ function lastFriday(date) {
489
+ return getLastWeekday(date, 5);
490
+ }
491
+ function lastSaturday(date) {
492
+ return getLastWeekday(date, 6);
493
+ }
494
+ function lastSunday(date) {
495
+ return getLastWeekday(date, 0);
496
+ }
497
+ function parseDuration(input) {
498
+ const regex = /(\d+)\s*([wdhms])/g;
499
+ let ms = 0;
500
+ let match;
501
+ while ((match = regex.exec(input)) !== null) {
502
+ const val = parseInt(match[1], 10);
503
+ switch (match[2]) {
504
+ case "w":
505
+ ms += val * 7 * MS_IN_DAY;
506
+ break;
507
+ case "d":
508
+ ms += val * MS_IN_DAY;
509
+ break;
510
+ case "h":
511
+ ms += val * MS_IN_HOUR;
512
+ break;
513
+ case "m":
514
+ ms += val * MS_IN_MINUTE;
515
+ break;
516
+ case "s":
517
+ ms += val * MS_IN_SECOND;
518
+ break;
519
+ }
520
+ }
521
+ return ms;
522
+ }
523
+ var INDONESIAN_FIXED_HOLIDAYS = [
524
+ { name: "New Year", month: 0, day: 1 },
525
+ { name: "Labor Day", month: 4, day: 1 },
526
+ { name: "Pancasila Day", month: 5, day: 1 },
527
+ { name: "Independence Day", month: 7, day: 17 },
528
+ { name: "National Awakening Day", month: 4, day: 20 },
529
+ { name: "National Heroes Day", month: 10, day: 10 },
530
+ { name: "Christmas", month: 11, day: 25 }
531
+ ];
532
+ function computeEaster(year) {
533
+ const a = year % 19;
534
+ const b = Math.floor(year / 100);
535
+ const c = year % 100;
536
+ const d = Math.floor(b / 4);
537
+ const e = b % 4;
538
+ const f = Math.floor((b + 8) / 25);
539
+ const g = Math.floor((b - f + 1) / 3);
540
+ const h = (19 * a + b - d - g + 15) % 30;
541
+ const i = Math.floor(c / 4);
542
+ const k = c % 4;
543
+ const l = (32 + 2 * e + 2 * i - h - k) % 7;
544
+ const m = Math.floor((a + 11 * h + 22 * l) / 451);
545
+ const month = Math.floor((h + l - 7 * m + 114) / 31);
546
+ const day = (h + l - 7 * m + 114) % 31 + 1;
547
+ return new Date(year, month - 1, day);
548
+ }
549
+ var CHINESE_NEW_YEAR = {
550
+ 2024: { month: 1, day: 10 },
551
+ 2025: { month: 0, day: 29 },
552
+ 2026: { month: 1, day: 17 },
553
+ 2027: { month: 1, day: 6 },
554
+ 2028: { month: 0, day: 26 },
555
+ 2029: { month: 1, day: 13 },
556
+ 2030: { month: 2, day: 3 }
557
+ };
558
+ var NYEPI = {
559
+ 2024: { month: 2, day: 11 },
560
+ 2025: { month: 2, day: 29 },
561
+ 2026: { month: 2, day: 19 },
562
+ 2027: { month: 2, day: 7 },
563
+ 2028: { month: 2, day: 26 },
564
+ 2029: { month: 2, day: 15 },
565
+ 2030: { month: 2, day: 5 }
566
+ };
567
+ var VESAK = {
568
+ 2024: { month: 4, day: 23 },
569
+ 2025: { month: 4, day: 12 },
570
+ 2026: { month: 4, day: 31 },
571
+ 2027: { month: 4, day: 20 },
572
+ 2028: { month: 4, day: 9 },
573
+ 2029: { month: 4, day: 28 },
574
+ 2030: { month: 4, day: 18 }
575
+ };
576
+ var EID_AL_FITR = {
577
+ 2024: [{ month: 3, day: 10 }, { month: 3, day: 11 }],
578
+ 2025: [{ month: 2, day: 31 }, { month: 3, day: 1 }],
579
+ 2026: [{ month: 2, day: 21 }, { month: 2, day: 22 }],
580
+ 2027: [{ month: 2, day: 10 }, { month: 2, day: 11 }],
581
+ 2028: [{ month: 2, day: 28 }, { month: 2, day: 29 }],
582
+ 2029: [{ month: 2, day: 17 }, { month: 2, day: 18 }],
583
+ 2030: [{ month: 2, day: 7 }, { month: 2, day: 8 }]
584
+ };
585
+ var EID_AL_ADHA = {
586
+ 2024: { month: 5, day: 17 },
587
+ 2025: { month: 5, day: 7 },
588
+ 2026: { month: 4, day: 27 },
589
+ 2027: { month: 4, day: 17 },
590
+ 2028: { month: 5, day: 5 },
591
+ 2029: { month: 4, day: 25 },
592
+ 2030: { month: 4, day: 15 }
593
+ };
594
+ var ISLAMIC_NEW_YEAR = {
595
+ 2024: { month: 6, day: 7 },
596
+ 2025: { month: 5, day: 27 },
597
+ 2026: { month: 5, day: 16 },
598
+ 2027: { month: 5, day: 6 },
599
+ 2028: { month: 6, day: 24 },
600
+ 2029: { month: 6, day: 13 },
601
+ 2030: { month: 6, day: 3 }
602
+ };
603
+ var PROPHETS_BIRTHDAY = {
604
+ 2024: { month: 8, day: 16 },
605
+ 2025: { month: 8, day: 5 },
606
+ 2026: { month: 7, day: 26 },
607
+ 2027: { month: 7, day: 16 },
608
+ 2028: { month: 8, day: 3 },
609
+ 2029: { month: 7, day: 23 },
610
+ 2030: { month: 7, day: 13 }
611
+ };
612
+ var ISRA_MIRAJ = {
613
+ 2024: { month: 1, day: 8 },
614
+ 2025: { month: 0, day: 28 },
615
+ 2026: { month: 0, day: 17 },
616
+ 2027: { month: 0, day: 6 },
617
+ 2028: { month: 0, day: 26 },
618
+ 2029: { month: 1, day: 14 },
619
+ 2030: { month: 1, day: 3 }
620
+ };
621
+ function addHolidayEntry(entries, name, month, day) {
622
+ entries.push({ name, month, day });
623
+ }
624
+ function getIndonesianHolidaysForYear(year) {
625
+ const holidays = [...INDONESIAN_FIXED_HOLIDAYS];
626
+ const easter = computeEaster(year);
627
+ addHolidayEntry(holidays, "Good Friday", easter.getMonth(), easter.getDate() - 2);
628
+ addHolidayEntry(holidays, "Easter", easter.getMonth(), easter.getDate());
629
+ const ascension = new Date(easter);
630
+ ascension.setDate(ascension.getDate() + 39);
631
+ addHolidayEntry(holidays, "Ascension of Jesus Christ", ascension.getMonth(), ascension.getDate());
632
+ const cny = CHINESE_NEW_YEAR[year];
633
+ if (cny) addHolidayEntry(holidays, "Chinese New Year", cny.month, cny.day);
634
+ const nyepi = NYEPI[year];
635
+ if (nyepi) addHolidayEntry(holidays, "Nyepi (Day of Silence)", nyepi.month, nyepi.day);
636
+ const vesak = VESAK[year];
637
+ if (vesak) addHolidayEntry(holidays, "Vesak (Buddha's Birthday)", vesak.month, vesak.day);
638
+ const eidDays = EID_AL_FITR[year];
639
+ if (eidDays) {
640
+ eidDays.forEach((entry, idx) => {
641
+ addHolidayEntry(holidays, idx === 0 ? "Eid al-Fitr" : "Eid al-Fitr (Day 2)", entry.month, entry.day);
642
+ });
643
+ }
644
+ const eidAdha = EID_AL_ADHA[year];
645
+ if (eidAdha) addHolidayEntry(holidays, "Eid al-Adha", eidAdha.month, eidAdha.day);
646
+ const islNewYear = ISLAMIC_NEW_YEAR[year];
647
+ if (islNewYear) addHolidayEntry(holidays, "Islamic New Year", islNewYear.month, islNewYear.day);
648
+ const prophetBday = PROPHETS_BIRTHDAY[year];
649
+ if (prophetBday) addHolidayEntry(holidays, "Prophet Muhammad's Birthday", prophetBday.month, prophetBday.day);
650
+ const isra = ISRA_MIRAJ[year];
651
+ if (isra) addHolidayEntry(holidays, "Isra' Mi'raj (Ascension of Prophet Muhammad)", isra.month, isra.day);
652
+ return holidays;
653
+ }
654
+ function isHolidayIndonesia(date) {
655
+ if (!isValidDate(date)) throw new InvalidDateError(date);
656
+ const year = date.getFullYear();
657
+ const holidays = getIndonesianHolidaysForYear(year);
658
+ for (const h of holidays) {
659
+ if (h.month === date.getMonth() && h.day === date.getDate()) {
660
+ return true;
661
+ }
662
+ }
663
+ return false;
664
+ }
665
+ function getIndonesianHolidayNames(date) {
666
+ if (!isValidDate(date)) throw new InvalidDateError(date);
667
+ const year = date.getFullYear();
668
+ const holidays = getIndonesianHolidaysForYear(year);
669
+ const names = [];
670
+ for (const h of holidays) {
671
+ if (h.month === date.getMonth() && h.day === date.getDate()) {
672
+ names.push(h.name);
673
+ }
674
+ }
675
+ return names;
676
+ }
368
677
  export {
369
678
  InvalidDateError,
370
679
  TIMEZONE_WIB,
@@ -376,24 +685,53 @@ export {
376
685
  addYears,
377
686
  calculateAge,
378
687
  dateDiff,
688
+ dayOfYear,
689
+ daysInMonth,
379
690
  endOfDay,
380
691
  endOfMonth,
381
692
  endOfYear,
382
693
  formatDate,
383
694
  formatDuration,
384
695
  formatInTimezone,
696
+ getIndonesianHolidayNames,
385
697
  isAfter,
386
698
  isBefore,
387
699
  isBetween,
388
700
  isBusinessDay,
701
+ isFuture,
702
+ isHolidayIndonesia,
389
703
  isLeapYear,
704
+ isPast,
705
+ isSameDay,
706
+ isToday,
707
+ isTomorrow,
390
708
  isWeekend,
709
+ isYesterday,
710
+ lastFriday,
711
+ lastMonday,
712
+ lastSaturday,
713
+ lastSunday,
714
+ lastThursday,
715
+ lastTuesday,
716
+ lastWednesday,
717
+ maxDate,
718
+ minDate,
719
+ nextFriday,
720
+ nextMonday,
721
+ nextSaturday,
722
+ nextSunday,
723
+ nextThursday,
724
+ nextTuesday,
725
+ nextWednesday,
391
726
  parseDate,
727
+ parseDuration,
728
+ quarter,
392
729
  startOfDay,
393
730
  startOfMonth,
394
731
  startOfYear,
395
732
  timeAgo,
396
733
  timeRemaining,
397
- toTimezone
734
+ toTimezone,
735
+ weekOfYear
398
736
  };
399
737
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/date/index.ts"],"sourcesContent":["/**\r\n * Error thrown when a date value is invalid.\r\n */\r\nexport class InvalidDateError extends Error {\r\n constructor(input: unknown) {\r\n super(`Invalid date: ${String(input)}`)\r\n this.name = 'InvalidDateError'\r\n }\r\n}\r\n\r\nexport interface DateDiff {\r\n years: number\r\n months: number\r\n days: number\r\n hours: number\r\n minutes: number\r\n seconds: number\r\n}\r\n\r\nconst MONTH_NAMES_SHORT = [\r\n 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',\r\n 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',\r\n] as const\r\n\r\nconst MONTH_NAMES_FULL = [\r\n 'January', 'February', 'March', 'April', 'May', 'June',\r\n 'July', 'August', 'September', 'October', 'November', 'December',\r\n] as const\r\n\r\nconst MONTH_MAP: Record<string, number> = {\r\n jan: 0, january: 0,\r\n feb: 1, february: 1,\r\n mar: 2, march: 2,\r\n apr: 3, april: 3,\r\n may: 4,\r\n jun: 5, june: 5,\r\n jul: 6, july: 6,\r\n aug: 7, august: 7,\r\n sep: 8, september: 8,\r\n oct: 9, october: 9,\r\n nov: 10, november: 10,\r\n dec: 11, december: 11,\r\n}\r\n\r\n/**\r\n * Formats a Date to a string using the given format pattern.\r\n *\r\n * Supported tokens:\r\n * - `YYYY` — 4-digit year\r\n * - `YY` — 2-digit year\r\n * - `MMMM` — full month name\r\n * - `MMM` — abbreviated month name\r\n * - `MM` — 2-digit month (01–12)\r\n * - `DD` — 2-digit day (01–31)\r\n * - `HH` — 2-digit hours (00–23)\r\n * - `mm` — 2-digit minutes\r\n * - `ss` — 2-digit seconds\r\n * - `SSS` — milliseconds\r\n *\r\n * @param date - The date to format.\r\n * @param format - The format string (default `'YYYY-MM-DD'`).\r\n * @returns The formatted date string.\r\n */\r\nexport function formatDate(date: Date, format: string = 'YYYY-MM-DD'): string {\r\n const year = date.getFullYear()\r\n const month = date.getMonth()\r\n const day = date.getDate()\r\n const hours = date.getHours()\r\n const minutes = date.getMinutes()\r\n const seconds = date.getSeconds()\r\n const ms = date.getMilliseconds()\r\n\r\n const pad = (n: number, len: number = 2): string => String(n).padStart(len, '0')\r\n\r\n return format\r\n .replace(/YYYY/g, String(year))\r\n .replace(/YY/g, String(year).slice(-2))\r\n .replace(/MMMM/g, MONTH_NAMES_FULL[month]!)\r\n .replace(/MMM/g, MONTH_NAMES_SHORT[month]!)\r\n .replace(/MM/g, pad(month + 1))\r\n .replace(/DD/g, pad(day))\r\n .replace(/HH/g, pad(hours))\r\n .replace(/mm/g, pad(minutes))\r\n .replace(/ss/g, pad(seconds))\r\n .replace(/SSS/g, pad(ms, 3))\r\n}\r\n\r\n/**\r\n * Parses a date from a string, number (timestamp in ms), or Date object.\r\n *\r\n * Supported string formats:\r\n * - ISO (`YYYY-MM-DD`, `YYYY-MM-DDTHH:mm:ss`)\r\n * - `DD/MM/YYYY` or `DD-MM-YYYY`\r\n * - `DD MMM YYYY` or `DD MMMM YYYY`\r\n * - Unix timestamp (milliseconds)\r\n *\r\n * @param input - The value to parse.\r\n * @returns A valid Date object.\r\n * @throws {InvalidDateError} If the input cannot be parsed.\r\n */\r\nexport function parseDate(input: string | number | Date): Date {\r\n if (input instanceof Date) {\r\n if (isNaN(input.getTime())) throw new InvalidDateError(input)\r\n return new Date(input.getTime())\r\n }\r\n\r\n if (typeof input === 'number') {\r\n const d = new Date(input)\r\n if (isNaN(d.getTime())) throw new InvalidDateError(input)\r\n return d\r\n }\r\n\r\n const trimmed = input.trim()\r\n\r\n // ISO format: YYYY-MM-DD or YYYY-MM-DDTHH:mm:ss\r\n const isoMatch = trimmed.match(/^(\\d{4})-(\\d{2})-(\\d{2})(?:T(\\d{2}):(\\d{2}):(\\d{2})(?:\\.(\\d+))?)?(?:Z|[+-]\\d{2}:?\\d{2})?$/)\r\n if (isoMatch) {\r\n const d = new Date(\r\n parseInt(isoMatch[1]!, 10),\r\n parseInt(isoMatch[2]!, 10) - 1,\r\n parseInt(isoMatch[3]!, 10),\r\n isoMatch[4] ? parseInt(isoMatch[4]!, 10) : 0,\r\n isoMatch[5] ? parseInt(isoMatch[5]!, 10) : 0,\r\n isoMatch[6] ? parseInt(isoMatch[6]!, 10) : 0,\r\n isoMatch[7] ? parseInt(isoMatch[7]!.padEnd(3, '0'), 10) : 0\r\n )\r\n if (!isNaN(d.getTime())) return d\r\n }\r\n\r\n // DD/MM/YYYY or DD-MM-YYYY\r\n const dmyMatch = trimmed.match(/^(\\d{1,2})[\\/-](\\d{1,2})[\\/-](\\d{4})$/)\r\n if (dmyMatch) {\r\n const year = parseInt(dmyMatch[3]!, 10)\r\n const month = parseInt(dmyMatch[2]!, 10) - 1\r\n const day = parseInt(dmyMatch[1]!, 10)\r\n const d = new Date(year, month, day)\r\n // Validate that the date didn't overflow (e.g. Feb 29 in non-leap year)\r\n if (!isNaN(d.getTime()) && d.getMonth() === month && d.getDate() === day) return d\r\n }\r\n\r\n // DD MMM YYYY or DD MMMM YYYY\r\n const textMatch = trimmed.match(/^(\\d{1,2})\\s+([a-zA-Z]+)\\s+(\\d{4})$/)\r\n if (textMatch) {\r\n const monthIndex = MONTH_MAP[textMatch[2]!.toLowerCase()]\r\n if (monthIndex !== undefined) {\r\n const year = parseInt(textMatch[3]!, 10)\r\n const day = parseInt(textMatch[1]!, 10)\r\n const d = new Date(year, monthIndex, day)\r\n if (!isNaN(d.getTime()) && d.getMonth() === monthIndex && d.getDate() === day) return d\r\n }\r\n }\r\n\r\n // Unix timestamp (milliseconds) as string\r\n const numMatch = trimmed.match(/^-?\\d+$/)\r\n if (numMatch) {\r\n const d = new Date(parseInt(numMatch[0], 10))\r\n if (!isNaN(d.getTime())) return d\r\n }\r\n\r\n // Fallback: let Date.parse try\r\n const fallback = new Date(trimmed)\r\n if (!isNaN(fallback.getTime())) return fallback\r\n\r\n throw new InvalidDateError(input)\r\n}\r\n\r\nfunction isValidDate(d: Date): boolean {\r\n return d instanceof Date && !isNaN(d.getTime())\r\n}\r\n\r\nconst MS_IN_SECOND = 1000\r\nconst MS_IN_MINUTE = 60 * MS_IN_SECOND\r\nconst MS_IN_HOUR = 60 * MS_IN_MINUTE\r\nconst MS_IN_DAY = 24 * MS_IN_HOUR\r\n\r\n/**\r\n * Computes the difference between two dates.\r\n *\r\n * @param date1 - Start date.\r\n * @param date2 - End date.\r\n * @returns An object with years, months, days, hours, minutes, seconds.\r\n * @throws {InvalidDateError} If either date is invalid.\r\n */\r\nexport function dateDiff(date1: Date, date2: Date): DateDiff {\r\n if (!isValidDate(date1) || !isValidDate(date2)) {\r\n throw new InvalidDateError('Invalid date provided to dateDiff')\r\n }\r\n\r\n let years = date2.getFullYear() - date1.getFullYear()\r\n let months = date2.getMonth() - date1.getMonth()\r\n let days = date2.getDate() - date1.getDate()\r\n\r\n if (days < 0) {\r\n months -= 1\r\n const prevMonth = new Date(date2.getFullYear(), date2.getMonth(), 0)\r\n days += prevMonth.getDate()\r\n }\r\n\r\n if (months < 0) {\r\n years -= 1\r\n months += 12\r\n }\r\n\r\n const msDiff = Math.abs(date2.getTime() - date1.getTime())\r\n const totalSeconds = Math.floor(msDiff / MS_IN_SECOND)\r\n const hours = Math.floor((msDiff % MS_IN_DAY) / MS_IN_HOUR)\r\n const minutes = Math.floor((msDiff % MS_IN_HOUR) / MS_IN_MINUTE)\r\n const seconds = totalSeconds % 60\r\n\r\n return { years, months, days, hours, minutes, seconds }\r\n}\r\n\r\n/**\r\n * Adds days to a date.\r\n *\r\n * @param date - The original date.\r\n * @param days - Number of days to add (negative to subtract).\r\n * @returns A new Date.\r\n * @throws {InvalidDateError} If the input date is invalid.\r\n */\r\nexport function addDays(date: Date, days: number): Date {\r\n if (!isValidDate(date)) throw new InvalidDateError(date)\r\n const result = new Date(date.getTime())\r\n result.setDate(result.getDate() + days)\r\n return result\r\n}\r\n\r\n/**\r\n * Adds months to a date. Handles month-end overflow (e.g., Jan 31 + 1 month\r\n * becomes Feb 28).\r\n *\r\n * @param date - The original date.\r\n * @param months - Number of months to add (negative to subtract).\r\n * @returns A new Date.\r\n * @throws {InvalidDateError} If the input date is invalid.\r\n */\r\nexport function addMonths(date: Date, months: number): Date {\r\n if (!isValidDate(date)) throw new InvalidDateError(date)\r\n const result = new Date(date.getTime())\r\n const targetMonth = result.getMonth() + months\r\n result.setMonth(targetMonth)\r\n\r\n if (result.getMonth() !== ((targetMonth % 12) + 12) % 12) {\r\n result.setDate(0)\r\n }\r\n\r\n return result\r\n}\r\n\r\n/**\r\n * Adds years to a date. Handles leap-year overflow (e.g., Feb 29 + 1 year\r\n * becomes Feb 28).\r\n *\r\n * @param date - The original date.\r\n * @param years - Number of years to add (negative to subtract).\r\n * @returns A new Date.\r\n * @throws {InvalidDateError} If the input date is invalid.\r\n */\r\nexport function addYears(date: Date, years: number): Date {\r\n if (!isValidDate(date)) throw new InvalidDateError(date)\r\n const result = new Date(date.getTime())\r\n const targetYear = result.getFullYear() + years\r\n result.setFullYear(targetYear)\r\n\r\n if (result.getFullYear() !== targetYear) {\r\n result.setDate(0)\r\n }\r\n\r\n return result\r\n}\r\n\r\n/**\r\n * Returns the start of the day (00:00:00.000) for the given date.\r\n *\r\n * @param date - The date.\r\n * @returns A new Date set to midnight.\r\n * @throws {InvalidDateError} If the input date is invalid.\r\n */\r\nexport function startOfDay(date: Date): Date {\r\n if (!isValidDate(date)) throw new InvalidDateError(date)\r\n return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0, 0)\r\n}\r\n\r\n/**\r\n * Returns the end of the day (23:59:59.999) for the given date.\r\n *\r\n * @param date - The date.\r\n * @returns A new Date set to the last millisecond of the day.\r\n * @throws {InvalidDateError} If the input date is invalid.\r\n */\r\nexport function endOfDay(date: Date): Date {\r\n if (!isValidDate(date)) throw new InvalidDateError(date)\r\n return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 23, 59, 59, 999)\r\n}\r\n\r\n/**\r\n * Returns the first moment of the month for the given date.\r\n *\r\n * @param date - The date.\r\n * @returns A new Date set to the start of the month.\r\n * @throws {InvalidDateError} If the input date is invalid.\r\n */\r\nexport function startOfMonth(date: Date): Date {\r\n if (!isValidDate(date)) throw new InvalidDateError(date)\r\n return new Date(date.getFullYear(), date.getMonth(), 1, 0, 0, 0, 0)\r\n}\r\n\r\n/**\r\n * Returns the last moment of the month for the given date.\r\n *\r\n * @param date - The date.\r\n * @returns A new Date set to the end of the month.\r\n * @throws {InvalidDateError} If the input date is invalid.\r\n */\r\nexport function endOfMonth(date: Date): Date {\r\n if (!isValidDate(date)) throw new InvalidDateError(date)\r\n return new Date(date.getFullYear(), date.getMonth() + 1, 0, 23, 59, 59, 999)\r\n}\r\n\r\n/**\r\n * Returns the first moment of the year for the given date.\r\n *\r\n * @param date - The date.\r\n * @returns A new Date set to Jan 1 00:00:00.000.\r\n * @throws {InvalidDateError} If the input date is invalid.\r\n */\r\nexport function startOfYear(date: Date): Date {\r\n if (!isValidDate(date)) throw new InvalidDateError(date)\r\n return new Date(date.getFullYear(), 0, 1, 0, 0, 0, 0)\r\n}\r\n\r\n/**\r\n * Returns the last moment of the year for the given date.\r\n *\r\n * @param date - The date.\r\n * @returns A new Date set to Dec 31 23:59:59.999.\r\n * @throws {InvalidDateError} If the input date is invalid.\r\n */\r\nexport function endOfYear(date: Date): Date {\r\n if (!isValidDate(date)) throw new InvalidDateError(date)\r\n return new Date(date.getFullYear(), 12, 0, 23, 59, 59, 999)\r\n}\r\n\r\n/**\r\n * Checks if the date falls on a weekend (Saturday or Sunday).\r\n *\r\n * @param date - The date to check.\r\n * @returns Whether the date is a weekend.\r\n * @throws {InvalidDateError} If the input date is invalid.\r\n */\r\nexport function isWeekend(date: Date): boolean {\r\n if (!isValidDate(date)) throw new InvalidDateError(date)\r\n const day = date.getDay()\r\n return day === 0 || day === 6\r\n}\r\n\r\n/**\r\n * Checks if a year is a leap year.\r\n *\r\n * @param year - The year to check.\r\n * @returns Whether the year is a leap year.\r\n */\r\nexport function isLeapYear(year: number): boolean {\r\n return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0\r\n}\r\n\r\n/**\r\n * Checks if `date1` is before `date2`.\r\n *\r\n * @param date1 - First date.\r\n * @param date2 - Second date.\r\n * @returns Whether `date1` is before `date2`.\r\n * @throws {InvalidDateError} If either date is invalid.\r\n */\r\nexport function isBefore(date1: Date, date2: Date): boolean {\r\n if (!isValidDate(date1) || !isValidDate(date2)) {\r\n throw new InvalidDateError('Invalid date provided to isBefore')\r\n }\r\n return date1.getTime() < date2.getTime()\r\n}\r\n\r\n/**\r\n * Checks if `date1` is after `date2`.\r\n *\r\n * @param date1 - First date.\r\n * @param date2 - Second date.\r\n * @returns Whether `date1` is after `date2`.\r\n * @throws {InvalidDateError} If either date is invalid.\r\n */\r\nexport function isAfter(date1: Date, date2: Date): boolean {\r\n if (!isValidDate(date1) || !isValidDate(date2)) {\r\n throw new InvalidDateError('Invalid date provided to isAfter')\r\n }\r\n return date1.getTime() > date2.getTime()\r\n}\r\n\r\n/**\r\n * Checks if a date is within the inclusive range [start, end].\r\n *\r\n * @param date - The date to check.\r\n * @param start - Start of the range.\r\n * @param end - End of the range.\r\n * @returns Whether the date is between start and end.\r\n * @throws {InvalidDateError} If any date is invalid.\r\n */\r\nexport function isBetween(date: Date, start: Date, end: Date): boolean {\r\n if (!isValidDate(date) || !isValidDate(start) || !isValidDate(end)) {\r\n throw new InvalidDateError('Invalid date provided to isBetween')\r\n }\r\n return date.getTime() >= start.getTime() && date.getTime() <= end.getTime()\r\n}\r\n\r\n/**\r\n * Checks if a date is a business day (Monday to Friday).\r\n *\r\n * @param date - The date to check.\r\n * @returns Whether the date is a business day.\r\n */\r\nexport function isBusinessDay(date: Date): boolean {\r\n return isValidDate(date) && !isWeekend(date)\r\n}\r\n\r\n/**\r\n * Adds business days (skipping weekends) to a date.\r\n *\r\n * @param date - The starting date.\r\n * @param days - Number of business days to add (negative to subtract).\r\n * @returns A new Date.\r\n * @throws {InvalidDateError} If the input date is invalid.\r\n */\r\nexport function addBusinessDays(date: Date, days: number): Date {\r\n if (!isValidDate(date)) throw new InvalidDateError(date)\r\n\r\n const result = new Date(date.getTime())\r\n let remaining = Math.abs(days)\r\n const step = days >= 0 ? 1 : -1\r\n\r\n while (remaining > 0) {\r\n result.setDate(result.getDate() + step)\r\n const day = result.getDay()\r\n if (day !== 0 && day !== 6) {\r\n remaining--\r\n }\r\n }\r\n\r\n return result\r\n}\r\n\r\n/**\r\n * Calculates age in years from a birth date.\r\n *\r\n * @param birthDate - The date of birth.\r\n * @returns The age in years.\r\n * @throws {InvalidDateError} If the birth date is invalid.\r\n */\r\nexport function calculateAge(birthDate: Date): number {\r\n if (!isValidDate(birthDate)) throw new InvalidDateError(birthDate)\r\n\r\n const today = new Date()\r\n let age = today.getFullYear() - birthDate.getFullYear()\r\n const monthDiff = today.getMonth() - birthDate.getMonth()\r\n\r\n if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) {\r\n age--\r\n }\r\n\r\n return age\r\n}\r\n\r\n// ─── Time Ago & Time Remaining ───────────────────────────────────────────────\r\n\r\ninterface LocaleLabels {\r\n years: { single: string; plural: string }\r\n months: { single: string; plural: string }\r\n weeks: { single: string; plural: string }\r\n days: { single: string; plural: string }\r\n hours: { single: string; plural: string }\r\n minutes: { single: string; plural: string }\r\n seconds: { single: string; plural: string }\r\n}\r\n\r\nconst LOCALE_LABELS: Record<string, LocaleLabels> = {\r\n id: {\r\n years: { single: 'tahun', plural: 'tahun' },\r\n months: { single: 'bulan', plural: 'bulan' },\r\n weeks: { single: 'minggu', plural: 'minggu' },\r\n days: { single: 'hari', plural: 'hari' },\r\n hours: { single: 'jam', plural: 'jam' },\r\n minutes: { single: 'menit', plural: 'menit' },\r\n seconds: { single: 'detik', plural: 'detik' },\r\n },\r\n en: {\r\n years: { single: 'year', plural: 'years' },\r\n months: { single: 'month', plural: 'months' },\r\n weeks: { single: 'week', plural: 'weeks' },\r\n days: { single: 'day', plural: 'days' },\r\n hours: { single: 'hour', plural: 'hours' },\r\n minutes: { single: 'minute', plural: 'minutes' },\r\n seconds: { single: 'second', plural: 'seconds' },\r\n },\r\n}\r\n\r\nfunction getSuffix(diffMs: number, kind: 'ago' | 'remaining', locale: string): string {\r\n if (diffMs < 0) {\r\n return locale === 'en' ? 'ago' : 'yang lalu'\r\n }\r\n if (kind === 'remaining') {\r\n return locale === 'en' ? 'remaining' : 'lagi'\r\n }\r\n return locale === 'en' ? 'ago' : 'yang lalu'\r\n}\r\n\r\nfunction formatRelativeTime(absDiffMs: number, suffix: string, locale: string): string {\r\n const labels = LOCALE_LABELS[locale] ?? LOCALE_LABELS.id!\r\n\r\n const seconds = Math.floor(absDiffMs / 1000)\r\n const minutes = Math.floor(seconds / 60)\r\n const hours = Math.floor(minutes / 60)\r\n const days = Math.floor(hours / 24)\r\n const weeks = Math.floor(days / 7)\r\n const months = Math.floor(days / 30.4375)\r\n const years = Math.floor(days / 365.25)\r\n\r\n let count: number\r\n let unit: keyof LocaleLabels\r\n\r\n if (years >= 1) { count = years; unit = 'years' }\r\n else if (months >= 1) { count = months; unit = 'months' }\r\n else if (weeks >= 1) { count = weeks; unit = 'weeks' }\r\n else if (days >= 1) { count = days; unit = 'days' }\r\n else if (hours >= 1) { count = hours; unit = 'hours' }\r\n else if (minutes >= 1) { count = minutes; unit = 'minutes' }\r\n else { count = Math.max(1, seconds); unit = 'seconds' }\r\n\r\n const label = count === 1 ? labels[unit].single : labels[unit].plural\r\n return `${count} ${label} ${suffix}`\r\n}\r\n\r\n/**\r\n * Returns a human-readable relative time string (e.g. \"5 menit yang lalu\").\r\n *\r\n * @param date - The past date.\r\n * @param options - Options with locale ('id' by default, 'en' supported).\r\n * @returns A relative time string.\r\n */\r\nexport function timeAgo(date: Date, options?: { locale?: string }): string {\r\n const diff = Date.now() - date.getTime()\r\n const locale = options?.locale ?? 'id'\r\n const suffix = getSuffix(diff, 'ago', locale)\r\n return formatRelativeTime(Math.abs(diff), suffix, locale)\r\n}\r\n\r\n/**\r\n * Shows the time remaining until a future date.\r\n *\r\n * @param target - The target future date.\r\n * @param options - Options with locale ('id' by default, 'en' supported).\r\n * @returns A relative time string.\r\n */\r\nexport function timeRemaining(target: Date, options?: { locale?: string }): string {\r\n const diff = target.getTime() - Date.now()\r\n const locale = options?.locale ?? 'id'\r\n const suffix = getSuffix(diff, 'remaining', locale)\r\n return formatRelativeTime(Math.abs(diff), suffix, locale)\r\n}\r\n\r\n// ─── Duration ────────────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Represents a duration split into calendar and time components.\r\n */\r\nexport interface Duration {\r\n years: number\r\n months: number\r\n days: number\r\n hours: number\r\n minutes: number\r\n seconds: number\r\n}\r\n\r\n/**\r\n * Formats a Duration object into a human-readable string.\r\n *\r\n * @example\r\n * formatDuration({ hours: 2, minutes: 30, seconds: 15 }) // \"2 jam 30 menit 15 detik\"\r\n * formatDuration({ hours: 2, minutes: 30 }, { locale: 'en' }) // \"2 hours 30 minutes\"\r\n *\r\n * @param duration - The duration to format.\r\n * @param options - Options with locale ('id' by default, 'en' supported).\r\n * @returns A formatted duration string.\r\n */\r\nexport function formatDuration(duration: Duration, options?: { locale?: string }): string {\r\n const locale = options?.locale ?? 'id'\r\n const labels = LOCALE_LABELS[locale] ?? LOCALE_LABELS.id!\r\n\r\n const parts: string[] = []\r\n const entries: [keyof Duration, number][] = [\r\n ['years', duration.years],\r\n ['months', duration.months],\r\n ['days', duration.days],\r\n ['hours', duration.hours],\r\n ['minutes', duration.minutes],\r\n ['seconds', duration.seconds],\r\n ]\r\n\r\n for (const [key, value] of entries) {\r\n if (value > 0) {\r\n const label = value === 1 ? labels[key].single : labels[key].plural\r\n parts.push(`${value} ${label}`)\r\n }\r\n }\r\n\r\n if (parts.length === 0) {\r\n const label = labels.seconds.plural\r\n return `0 ${label}`\r\n }\r\n\r\n return parts.join(' ')\r\n}\r\n\r\n// ─── Timezone Helpers ────────────────────────────────────────────────────────\r\n\r\n/** UTC+7 — Western Indonesia Time (WIB). */\r\nexport const TIMEZONE_WIB = 7\r\n\r\n/** UTC+8 — Central Indonesia Time (WITA). */\r\nexport const TIMEZONE_WITA = 8\r\n\r\n/** UTC+9 — Eastern Indonesia Time (WIT). */\r\nexport const TIMEZONE_WIT = 9\r\n\r\n/**\r\n * Converts a date to a specific timezone offset by returning a new Date whose\r\n * local-time getters (getHours, getMinutes etc.) reflect the target timezone.\r\n *\r\n * @param date - The source date.\r\n * @param offsetHours - The timezone offset in hours (e.g. 7 for WIB).\r\n * @returns A new Date adjusted to the target timezone.\r\n * @throws {InvalidDateError} If the input date is invalid.\r\n */\r\nexport function toTimezone(date: Date, offsetHours: number): Date {\r\n if (!isValidDate(date)) throw new InvalidDateError(date)\r\n const utcMs = date.getTime() + date.getTimezoneOffset() * 60000\r\n return new Date(utcMs + offsetHours * 3600000)\r\n}\r\n\r\n/**\r\n * Formats a date in a specific timezone using `formatDate` tokens.\r\n *\r\n * @param date - The source date.\r\n * @param format - The format string (see `formatDate` for supported tokens).\r\n * @param offsetHours - The timezone offset in hours.\r\n * @returns The formatted date string.\r\n */\r\nexport function formatInTimezone(date: Date, format: string, offsetHours: number): string {\r\n return formatDate(toTimezone(date, offsetHours), format)\r\n}\r\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/date/index.ts"],"sourcesContent":["/**\n * Error thrown when a date value is invalid.\n */\nexport class InvalidDateError extends Error {\n constructor(input: unknown) {\n super(`Invalid date: ${String(input)}`)\n this.name = 'InvalidDateError'\n }\n}\n\nexport interface DateDiff {\n years: number\n months: number\n days: number\n hours: number\n minutes: number\n seconds: number\n}\n\nconst MONTH_NAMES_SHORT = [\n 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',\n 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',\n] as const\n\nconst MONTH_NAMES_FULL = [\n 'January', 'February', 'March', 'April', 'May', 'June',\n 'July', 'August', 'September', 'October', 'November', 'December',\n] as const\n\nconst MONTH_MAP: Record<string, number> = {\n jan: 0, january: 0,\n feb: 1, february: 1,\n mar: 2, march: 2,\n apr: 3, april: 3,\n may: 4,\n jun: 5, june: 5,\n jul: 6, july: 6,\n aug: 7, august: 7,\n sep: 8, september: 8,\n oct: 9, october: 9,\n nov: 10, november: 10,\n dec: 11, december: 11,\n}\n\n/**\n * Formats a Date to a string using the given format pattern.\n *\n * Supported tokens:\n * - `YYYY` — 4-digit year\n * - `YY` — 2-digit year\n * - `MMMM` — full month name\n * - `MMM` — abbreviated month name\n * - `MM` — 2-digit month (01–12)\n * - `DD` — 2-digit day (01–31)\n * - `HH` — 2-digit hours (00–23)\n * - `mm` — 2-digit minutes\n * - `ss` — 2-digit seconds\n * - `SSS` — milliseconds\n *\n * @param date - The date to format.\n * @param format - The format string (default `'YYYY-MM-DD'`).\n * @returns The formatted date string.\n */\nexport function formatDate(date: Date, format: string = 'YYYY-MM-DD'): string {\n const year = date.getFullYear()\n const month = date.getMonth()\n const day = date.getDate()\n const hours = date.getHours()\n const minutes = date.getMinutes()\n const seconds = date.getSeconds()\n const ms = date.getMilliseconds()\n\n const pad = (n: number, len: number = 2): string => String(n).padStart(len, '0')\n\n return format\n .replace(/YYYY/g, String(year))\n .replace(/YY/g, String(year).slice(-2))\n .replace(/MMMM/g, MONTH_NAMES_FULL[month]!)\n .replace(/MMM/g, MONTH_NAMES_SHORT[month]!)\n .replace(/MM/g, pad(month + 1))\n .replace(/DD/g, pad(day))\n .replace(/HH/g, pad(hours))\n .replace(/mm/g, pad(minutes))\n .replace(/ss/g, pad(seconds))\n .replace(/SSS/g, pad(ms, 3))\n}\n\n/**\n * Parses a date from a string, number (timestamp in ms), or Date object.\n *\n * Supported string formats:\n * - ISO (`YYYY-MM-DD`, `YYYY-MM-DDTHH:mm:ss`)\n * - `DD/MM/YYYY` or `DD-MM-YYYY`\n * - `DD MMM YYYY` or `DD MMMM YYYY`\n * - Unix timestamp (milliseconds)\n *\n * @param input - The value to parse.\n * @returns A valid Date object.\n * @throws {InvalidDateError} If the input cannot be parsed.\n */\nexport function parseDate(input: string | number | Date): Date {\n if (input instanceof Date) {\n if (isNaN(input.getTime())) throw new InvalidDateError(input)\n return new Date(input.getTime())\n }\n\n if (typeof input === 'number') {\n const d = new Date(input)\n if (isNaN(d.getTime())) throw new InvalidDateError(input)\n return d\n }\n\n const trimmed = input.trim()\n\n // ISO format: YYYY-MM-DD or YYYY-MM-DDTHH:mm:ss\n const isoMatch = trimmed.match(/^(\\d{4})-(\\d{2})-(\\d{2})(?:T(\\d{2}):(\\d{2}):(\\d{2})(?:\\.(\\d+))?)?(?:Z|[+-]\\d{2}:?\\d{2})?$/)\n if (isoMatch) {\n const d = new Date(\n parseInt(isoMatch[1]!, 10),\n parseInt(isoMatch[2]!, 10) - 1,\n parseInt(isoMatch[3]!, 10),\n isoMatch[4] ? parseInt(isoMatch[4]!, 10) : 0,\n isoMatch[5] ? parseInt(isoMatch[5]!, 10) : 0,\n isoMatch[6] ? parseInt(isoMatch[6]!, 10) : 0,\n isoMatch[7] ? parseInt(isoMatch[7]!.padEnd(3, '0'), 10) : 0\n )\n if (!isNaN(d.getTime())) return d\n }\n\n // DD/MM/YYYY or DD-MM-YYYY\n const dmyMatch = trimmed.match(/^(\\d{1,2})[\\/-](\\d{1,2})[\\/-](\\d{4})$/)\n if (dmyMatch) {\n const year = parseInt(dmyMatch[3]!, 10)\n const month = parseInt(dmyMatch[2]!, 10) - 1\n const day = parseInt(dmyMatch[1]!, 10)\n const d = new Date(year, month, day)\n // Validate that the date didn't overflow (e.g. Feb 29 in non-leap year)\n if (!isNaN(d.getTime()) && d.getMonth() === month && d.getDate() === day) return d\n }\n\n // DD MMM YYYY or DD MMMM YYYY\n const textMatch = trimmed.match(/^(\\d{1,2})\\s+([a-zA-Z]+)\\s+(\\d{4})$/)\n if (textMatch) {\n const monthIndex = MONTH_MAP[textMatch[2]!.toLowerCase()]\n if (monthIndex !== undefined) {\n const year = parseInt(textMatch[3]!, 10)\n const day = parseInt(textMatch[1]!, 10)\n const d = new Date(year, monthIndex, day)\n if (!isNaN(d.getTime()) && d.getMonth() === monthIndex && d.getDate() === day) return d\n }\n }\n\n // Unix timestamp (milliseconds) as string\n const numMatch = trimmed.match(/^-?\\d+$/)\n if (numMatch) {\n const d = new Date(parseInt(numMatch[0], 10))\n if (!isNaN(d.getTime())) return d\n }\n\n // Fallback: let Date.parse try\n const fallback = new Date(trimmed)\n if (!isNaN(fallback.getTime())) return fallback\n\n throw new InvalidDateError(input)\n}\n\nfunction isValidDate(d: Date): boolean {\n return d instanceof Date && !isNaN(d.getTime())\n}\n\nconst MS_IN_SECOND = 1000\nconst MS_IN_MINUTE = 60 * MS_IN_SECOND\nconst MS_IN_HOUR = 60 * MS_IN_MINUTE\nconst MS_IN_DAY = 24 * MS_IN_HOUR\n\n/**\n * Computes the difference between two dates.\n *\n * @param date1 - Start date.\n * @param date2 - End date.\n * @returns An object with years, months, days, hours, minutes, seconds.\n * @throws {InvalidDateError} If either date is invalid.\n */\nexport function dateDiff(date1: Date, date2: Date): DateDiff {\n if (!isValidDate(date1) || !isValidDate(date2)) {\n throw new InvalidDateError('Invalid date provided to dateDiff')\n }\n\n let years = date2.getFullYear() - date1.getFullYear()\n let months = date2.getMonth() - date1.getMonth()\n let days = date2.getDate() - date1.getDate()\n\n if (days < 0) {\n months -= 1\n const prevMonth = new Date(date2.getFullYear(), date2.getMonth(), 0)\n days += prevMonth.getDate()\n }\n\n if (months < 0) {\n years -= 1\n months += 12\n }\n\n const msDiff = Math.abs(date2.getTime() - date1.getTime())\n const totalSeconds = Math.floor(msDiff / MS_IN_SECOND)\n const hours = Math.floor((msDiff % MS_IN_DAY) / MS_IN_HOUR)\n const minutes = Math.floor((msDiff % MS_IN_HOUR) / MS_IN_MINUTE)\n const seconds = totalSeconds % 60\n\n return { years, months, days, hours, minutes, seconds }\n}\n\n/**\n * Adds days to a date.\n *\n * @param date - The original date.\n * @param days - Number of days to add (negative to subtract).\n * @returns A new Date.\n * @throws {InvalidDateError} If the input date is invalid.\n */\nexport function addDays(date: Date, days: number): Date {\n if (!isValidDate(date)) throw new InvalidDateError(date)\n const result = new Date(date.getTime())\n result.setDate(result.getDate() + days)\n return result\n}\n\n/**\n * Adds months to a date. Handles month-end overflow (e.g., Jan 31 + 1 month\n * becomes Feb 28).\n *\n * @param date - The original date.\n * @param months - Number of months to add (negative to subtract).\n * @returns A new Date.\n * @throws {InvalidDateError} If the input date is invalid.\n */\nexport function addMonths(date: Date, months: number): Date {\n if (!isValidDate(date)) throw new InvalidDateError(date)\n const result = new Date(date.getTime())\n const targetMonth = result.getMonth() + months\n result.setMonth(targetMonth)\n\n if (result.getMonth() !== ((targetMonth % 12) + 12) % 12) {\n result.setDate(0)\n }\n\n return result\n}\n\n/**\n * Adds years to a date. Handles leap-year overflow (e.g., Feb 29 + 1 year\n * becomes Feb 28).\n *\n * @param date - The original date.\n * @param years - Number of years to add (negative to subtract).\n * @returns A new Date.\n * @throws {InvalidDateError} If the input date is invalid.\n */\nexport function addYears(date: Date, years: number): Date {\n if (!isValidDate(date)) throw new InvalidDateError(date)\n const result = new Date(date.getTime())\n const targetYear = result.getFullYear() + years\n result.setFullYear(targetYear)\n\n if (result.getFullYear() !== targetYear) {\n result.setDate(0)\n }\n\n return result\n}\n\n/**\n * Returns the start of the day (00:00:00.000) for the given date.\n *\n * @param date - The date.\n * @returns A new Date set to midnight.\n * @throws {InvalidDateError} If the input date is invalid.\n */\nexport function startOfDay(date: Date): Date {\n if (!isValidDate(date)) throw new InvalidDateError(date)\n return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0, 0)\n}\n\n/**\n * Returns the end of the day (23:59:59.999) for the given date.\n *\n * @param date - The date.\n * @returns A new Date set to the last millisecond of the day.\n * @throws {InvalidDateError} If the input date is invalid.\n */\nexport function endOfDay(date: Date): Date {\n if (!isValidDate(date)) throw new InvalidDateError(date)\n return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 23, 59, 59, 999)\n}\n\n/**\n * Returns the first moment of the month for the given date.\n *\n * @param date - The date.\n * @returns A new Date set to the start of the month.\n * @throws {InvalidDateError} If the input date is invalid.\n */\nexport function startOfMonth(date: Date): Date {\n if (!isValidDate(date)) throw new InvalidDateError(date)\n return new Date(date.getFullYear(), date.getMonth(), 1, 0, 0, 0, 0)\n}\n\n/**\n * Returns the last moment of the month for the given date.\n *\n * @param date - The date.\n * @returns A new Date set to the end of the month.\n * @throws {InvalidDateError} If the input date is invalid.\n */\nexport function endOfMonth(date: Date): Date {\n if (!isValidDate(date)) throw new InvalidDateError(date)\n return new Date(date.getFullYear(), date.getMonth() + 1, 0, 23, 59, 59, 999)\n}\n\n/**\n * Returns the first moment of the year for the given date.\n *\n * @param date - The date.\n * @returns A new Date set to Jan 1 00:00:00.000.\n * @throws {InvalidDateError} If the input date is invalid.\n */\nexport function startOfYear(date: Date): Date {\n if (!isValidDate(date)) throw new InvalidDateError(date)\n return new Date(date.getFullYear(), 0, 1, 0, 0, 0, 0)\n}\n\n/**\n * Returns the last moment of the year for the given date.\n *\n * @param date - The date.\n * @returns A new Date set to Dec 31 23:59:59.999.\n * @throws {InvalidDateError} If the input date is invalid.\n */\nexport function endOfYear(date: Date): Date {\n if (!isValidDate(date)) throw new InvalidDateError(date)\n return new Date(date.getFullYear(), 12, 0, 23, 59, 59, 999)\n}\n\n/**\n * Checks if the date falls on a weekend (Saturday or Sunday).\n *\n * @param date - The date to check.\n * @returns Whether the date is a weekend.\n * @throws {InvalidDateError} If the input date is invalid.\n */\nexport function isWeekend(date: Date): boolean {\n if (!isValidDate(date)) throw new InvalidDateError(date)\n const day = date.getDay()\n return day === 0 || day === 6\n}\n\n/**\n * Checks if a year is a leap year.\n *\n * @param year - The year to check.\n * @returns Whether the year is a leap year.\n */\nexport function isLeapYear(year: number): boolean {\n return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0\n}\n\n/**\n * Checks if `date1` is before `date2`.\n *\n * @param date1 - First date.\n * @param date2 - Second date.\n * @returns Whether `date1` is before `date2`.\n * @throws {InvalidDateError} If either date is invalid.\n */\nexport function isBefore(date1: Date, date2: Date): boolean {\n if (!isValidDate(date1) || !isValidDate(date2)) {\n throw new InvalidDateError('Invalid date provided to isBefore')\n }\n return date1.getTime() < date2.getTime()\n}\n\n/**\n * Checks if `date1` is after `date2`.\n *\n * @param date1 - First date.\n * @param date2 - Second date.\n * @returns Whether `date1` is after `date2`.\n * @throws {InvalidDateError} If either date is invalid.\n */\nexport function isAfter(date1: Date, date2: Date): boolean {\n if (!isValidDate(date1) || !isValidDate(date2)) {\n throw new InvalidDateError('Invalid date provided to isAfter')\n }\n return date1.getTime() > date2.getTime()\n}\n\n/**\n * Checks if a date is within the inclusive range [start, end].\n *\n * @param date - The date to check.\n * @param start - Start of the range.\n * @param end - End of the range.\n * @returns Whether the date is between start and end.\n * @throws {InvalidDateError} If any date is invalid.\n */\nexport function isBetween(date: Date, start: Date, end: Date): boolean {\n if (!isValidDate(date) || !isValidDate(start) || !isValidDate(end)) {\n throw new InvalidDateError('Invalid date provided to isBetween')\n }\n return date.getTime() >= start.getTime() && date.getTime() <= end.getTime()\n}\n\n/**\n * Checks if a date is a business day (Monday to Friday).\n *\n * @param date - The date to check.\n * @returns Whether the date is a business day.\n */\nexport function isBusinessDay(date: Date): boolean {\n return isValidDate(date) && !isWeekend(date)\n}\n\n/**\n * Adds business days (skipping weekends) to a date.\n *\n * @param date - The starting date.\n * @param days - Number of business days to add (negative to subtract).\n * @returns A new Date.\n * @throws {InvalidDateError} If the input date is invalid.\n */\nexport function addBusinessDays(date: Date, days: number): Date {\n if (!isValidDate(date)) throw new InvalidDateError(date)\n\n const result = new Date(date.getTime())\n let remaining = Math.abs(days)\n const step = days >= 0 ? 1 : -1\n\n while (remaining > 0) {\n result.setDate(result.getDate() + step)\n const day = result.getDay()\n if (day !== 0 && day !== 6) {\n remaining--\n }\n }\n\n return result\n}\n\n/**\n * Calculates age in years from a birth date.\n *\n * @param birthDate - The date of birth.\n * @returns The age in years.\n * @throws {InvalidDateError} If the birth date is invalid.\n */\nexport function calculateAge(birthDate: Date): number {\n if (!isValidDate(birthDate)) throw new InvalidDateError(birthDate)\n\n const today = new Date()\n let age = today.getFullYear() - birthDate.getFullYear()\n const monthDiff = today.getMonth() - birthDate.getMonth()\n\n if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) {\n age--\n }\n\n return age\n}\n\n// ─── Time Ago & Time Remaining ───────────────────────────────────────────────\n\ninterface LocaleLabels {\n years: { single: string; plural: string }\n months: { single: string; plural: string }\n weeks: { single: string; plural: string }\n days: { single: string; plural: string }\n hours: { single: string; plural: string }\n minutes: { single: string; plural: string }\n seconds: { single: string; plural: string }\n}\n\nconst LOCALE_LABELS: Record<string, LocaleLabels> = {\n id: {\n years: { single: 'tahun', plural: 'tahun' },\n months: { single: 'bulan', plural: 'bulan' },\n weeks: { single: 'minggu', plural: 'minggu' },\n days: { single: 'hari', plural: 'hari' },\n hours: { single: 'jam', plural: 'jam' },\n minutes: { single: 'menit', plural: 'menit' },\n seconds: { single: 'detik', plural: 'detik' },\n },\n en: {\n years: { single: 'year', plural: 'years' },\n months: { single: 'month', plural: 'months' },\n weeks: { single: 'week', plural: 'weeks' },\n days: { single: 'day', plural: 'days' },\n hours: { single: 'hour', plural: 'hours' },\n minutes: { single: 'minute', plural: 'minutes' },\n seconds: { single: 'second', plural: 'seconds' },\n },\n}\n\nfunction getSuffix(diffMs: number, kind: 'ago' | 'remaining', locale: string): string {\n if (diffMs < 0) {\n return locale === 'en' ? 'ago' : 'yang lalu'\n }\n if (kind === 'remaining') {\n return locale === 'en' ? 'remaining' : 'lagi'\n }\n return locale === 'en' ? 'ago' : 'yang lalu'\n}\n\nfunction formatRelativeTime(absDiffMs: number, suffix: string, locale: string): string {\n const labels = LOCALE_LABELS[locale] ?? LOCALE_LABELS.id!\n\n const seconds = Math.floor(absDiffMs / 1000)\n const minutes = Math.floor(seconds / 60)\n const hours = Math.floor(minutes / 60)\n const days = Math.floor(hours / 24)\n const weeks = Math.floor(days / 7)\n const months = Math.floor(days / 30.4375)\n const years = Math.floor(days / 365.25)\n\n let count: number\n let unit: keyof LocaleLabels\n\n if (years >= 1) { count = years; unit = 'years' }\n else if (months >= 1) { count = months; unit = 'months' }\n else if (weeks >= 1) { count = weeks; unit = 'weeks' }\n else if (days >= 1) { count = days; unit = 'days' }\n else if (hours >= 1) { count = hours; unit = 'hours' }\n else if (minutes >= 1) { count = minutes; unit = 'minutes' }\n else { count = Math.max(1, seconds); unit = 'seconds' }\n\n const label = count === 1 ? labels[unit].single : labels[unit].plural\n return `${count} ${label} ${suffix}`\n}\n\n/**\n * Returns a human-readable relative time string (e.g. \"5 menit yang lalu\").\n *\n * @param date - The past date.\n * @param options - Options with locale ('id' by default, 'en' supported).\n * @returns A relative time string.\n */\nexport function timeAgo(date: Date, options?: { locale?: string }): string {\n const diff = Date.now() - date.getTime()\n const locale = options?.locale ?? 'id'\n const suffix = getSuffix(diff, 'ago', locale)\n return formatRelativeTime(Math.abs(diff), suffix, locale)\n}\n\n/**\n * Shows the time remaining until a future date.\n *\n * @param target - The target future date.\n * @param options - Options with locale ('id' by default, 'en' supported).\n * @returns A relative time string.\n */\nexport function timeRemaining(target: Date, options?: { locale?: string }): string {\n const diff = target.getTime() - Date.now()\n const locale = options?.locale ?? 'id'\n const suffix = getSuffix(diff, 'remaining', locale)\n return formatRelativeTime(Math.abs(diff), suffix, locale)\n}\n\n// ─── Duration ────────────────────────────────────────────────────────────────\n\n/**\n * Represents a duration split into calendar and time components.\n */\nexport interface Duration {\n years: number\n months: number\n days: number\n hours: number\n minutes: number\n seconds: number\n}\n\n/**\n * Formats a Duration object into a human-readable string.\n *\n * @example\n * formatDuration({ hours: 2, minutes: 30, seconds: 15 }) // \"2 jam 30 menit 15 detik\"\n * formatDuration({ hours: 2, minutes: 30 }, { locale: 'en' }) // \"2 hours 30 minutes\"\n *\n * @param duration - The duration to format.\n * @param options - Options with locale ('id' by default, 'en' supported).\n * @returns A formatted duration string.\n */\nexport function formatDuration(duration: Duration, options?: { locale?: string }): string {\n const locale = options?.locale ?? 'id'\n const labels = LOCALE_LABELS[locale] ?? LOCALE_LABELS.id!\n\n const parts: string[] = []\n const entries: [keyof Duration, number][] = [\n ['years', duration.years],\n ['months', duration.months],\n ['days', duration.days],\n ['hours', duration.hours],\n ['minutes', duration.minutes],\n ['seconds', duration.seconds],\n ]\n\n for (const [key, value] of entries) {\n if (value > 0) {\n const label = value === 1 ? labels[key].single : labels[key].plural\n parts.push(`${value} ${label}`)\n }\n }\n\n if (parts.length === 0) {\n const label = labels.seconds.plural\n return `0 ${label}`\n }\n\n return parts.join(' ')\n}\n\n// ─── Timezone Helpers ────────────────────────────────────────────────────────\n\n/** UTC+7 — Western Indonesia Time (WIB). */\nexport const TIMEZONE_WIB = 7\n\n/** UTC+8 — Central Indonesia Time (WITA). */\nexport const TIMEZONE_WITA = 8\n\n/** UTC+9 — Eastern Indonesia Time (WIT). */\nexport const TIMEZONE_WIT = 9\n\n/**\n * Converts a date to a specific timezone offset by returning a new Date whose\n * local-time getters (getHours, getMinutes etc.) reflect the target timezone.\n *\n * @param date - The source date.\n * @param offsetHours - The timezone offset in hours (e.g. 7 for WIB).\n * @returns A new Date adjusted to the target timezone.\n * @throws {InvalidDateError} If the input date is invalid.\n */\nexport function toTimezone(date: Date, offsetHours: number): Date {\n if (!isValidDate(date)) throw new InvalidDateError(date)\n const utcMs = date.getTime() + date.getTimezoneOffset() * 60000\n return new Date(utcMs + offsetHours * 3600000)\n}\n\n/**\n * Formats a date in a specific timezone using `formatDate` tokens.\n *\n * @param date - The source date.\n * @param format - The format string (see `formatDate` for supported tokens).\n * @param offsetHours - The timezone offset in hours.\n * @returns The formatted date string.\n */\nexport function formatInTimezone(date: Date, format: string, offsetHours: number): string {\n return formatDate(toTimezone(date, offsetHours), format)\n}\n\n// ─── Comparison Helpers ──────────────────────────────────────────────────────\n\n/**\n * Checks if a date is today.\n *\n * @param date - The date to check.\n * @returns Whether the date is today.\n * @throws {InvalidDateError} If the input date is invalid.\n *\n * @example\n * isToday(new Date()) // true\n */\nexport function isToday(date: Date): boolean {\n if (!isValidDate(date)) throw new InvalidDateError(date)\n const now = new Date()\n return (\n date.getFullYear() === now.getFullYear() &&\n date.getMonth() === now.getMonth() &&\n date.getDate() === now.getDate()\n )\n}\n\n/**\n * Checks if a date is yesterday.\n *\n * @param date - The date to check.\n * @returns Whether the date is yesterday.\n * @throws {InvalidDateError} If the input date is invalid.\n *\n * @example\n * isYesterday(new Date(Date.now() - 86400000)) // true\n */\nexport function isYesterday(date: Date): boolean {\n if (!isValidDate(date)) throw new InvalidDateError(date)\n const yesterday = new Date()\n yesterday.setDate(yesterday.getDate() - 1)\n return (\n date.getFullYear() === yesterday.getFullYear() &&\n date.getMonth() === yesterday.getMonth() &&\n date.getDate() === yesterday.getDate()\n )\n}\n\n/**\n * Checks if a date is tomorrow.\n *\n * @param date - The date to check.\n * @returns Whether the date is tomorrow.\n * @throws {InvalidDateError} If the input date is invalid.\n *\n * @example\n * isTomorrow(new Date(Date.now() + 86400000)) // true\n */\nexport function isTomorrow(date: Date): boolean {\n if (!isValidDate(date)) throw new InvalidDateError(date)\n const tomorrow = new Date()\n tomorrow.setDate(tomorrow.getDate() + 1)\n return (\n date.getFullYear() === tomorrow.getFullYear() &&\n date.getMonth() === tomorrow.getMonth() &&\n date.getDate() === tomorrow.getDate()\n )\n}\n\n/**\n * Checks if a date is in the past (before now).\n *\n * @param date - The date to check.\n * @returns Whether the date is in the past.\n * @throws {InvalidDateError} If the input date is invalid.\n *\n * @example\n * isPast(new Date('2020-01-01')) // true\n */\nexport function isPast(date: Date): boolean {\n if (!isValidDate(date)) throw new InvalidDateError(date)\n return date.getTime() < Date.now()\n}\n\n/**\n * Checks if a date is in the future (after now).\n *\n * @param date - The date to check.\n * @returns Whether the date is in the future.\n * @throws {InvalidDateError} If the input date is invalid.\n *\n * @example\n * isFuture(new Date('2099-01-01')) // true\n */\nexport function isFuture(date: Date): boolean {\n if (!isValidDate(date)) throw new InvalidDateError(date)\n return date.getTime() > Date.now()\n}\n\n/**\n * Checks if two dates fall on the same calendar day.\n *\n * @param date1 - First date.\n * @param date2 - Second date.\n * @returns Whether the dates are the same day.\n * @throws {InvalidDateError} If either date is invalid.\n *\n * @example\n * isSameDay(new Date('2024-01-01'), new Date('2024-01-01')) // true\n */\nexport function isSameDay(date1: Date, date2: Date): boolean {\n if (!isValidDate(date1) || !isValidDate(date2)) {\n throw new InvalidDateError('Invalid date provided to isSameDay')\n }\n return (\n date1.getFullYear() === date2.getFullYear() &&\n date1.getMonth() === date2.getMonth() &&\n date1.getDate() === date2.getDate()\n )\n}\n\n/**\n * Returns the number of days in the month of the given date.\n *\n * @param date - The date.\n * @returns Number of days in the month (28–31).\n * @throws {InvalidDateError} If the input date is invalid.\n *\n * @example\n * daysInMonth(new Date('2024-02-01')) // 29 (leap year)\n */\nexport function daysInMonth(date: Date): number {\n if (!isValidDate(date)) throw new InvalidDateError(date)\n return new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate()\n}\n\n/**\n * Returns the day of the year (1–366).\n *\n * @param date - The date.\n * @returns Day of the year (1-indexed).\n * @throws {InvalidDateError} If the input date is invalid.\n *\n * @example\n * dayOfYear(new Date('2024-01-01')) // 1\n */\nexport function dayOfYear(date: Date): number {\n if (!isValidDate(date)) throw new InvalidDateError(date)\n const start = new Date(date.getFullYear(), 0, 0)\n return Math.floor((date.getTime() - start.getTime()) / MS_IN_DAY)\n}\n\n/**\n * Returns the ISO week number (1–53).\n *\n * The algorithm uses the Thursday of the same week as the reference\n * to determine which year the week belongs to, per ISO 8601.\n *\n * @param date - The date.\n * @returns The ISO week number.\n * @throws {InvalidDateError} If the input date is invalid.\n *\n * @example\n * weekOfYear(new Date('2024-01-01')) // 1\n */\nexport function weekOfYear(date: Date): number {\n if (!isValidDate(date)) throw new InvalidDateError(date)\n const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()))\n const dayNum = d.getUTCDay() || 7\n d.setUTCDate(d.getUTCDate() + 4 - dayNum)\n const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1))\n const weekNum = Math.ceil((((d.getTime() - yearStart.getTime()) / 86400000) + 1) / 7)\n return weekNum\n}\n\n/**\n * Returns the quarter of the year (1–4).\n *\n * @param date - The date.\n * @returns The quarter (1 for Jan–Mar, 2 for Apr–Jun, etc.).\n * @throws {InvalidDateError} If the input date is invalid.\n *\n * @example\n * quarter(new Date('2024-04-01')) // 2\n */\nexport function quarter(date: Date): number {\n if (!isValidDate(date)) throw new InvalidDateError(date)\n return Math.floor(date.getMonth() / 3) + 1\n}\n\n/**\n * Returns the latest (maximum) date from an array of dates.\n *\n * @param dates - Array of Date objects.\n * @returns The latest date.\n * @throws {Error} If the array is empty.\n * @throws {InvalidDateError} If any date is invalid.\n *\n * @example\n * maxDate([new Date('2024-01-01'), new Date('2025-01-01')]) // 2025-01-01\n */\nexport function maxDate(dates: Date[]): Date {\n if (dates.length === 0) throw new Error('maxDate requires at least one date')\n const ms = Math.max(...dates.map(d => {\n if (!isValidDate(d)) throw new InvalidDateError(d)\n return d.getTime()\n }))\n return new Date(ms)\n}\n\n/**\n * Returns the earliest (minimum) date from an array of dates.\n *\n * @param dates - Array of Date objects.\n * @returns The earliest date.\n * @throws {Error} If the array is empty.\n * @throws {InvalidDateError} If any date is invalid.\n *\n * @example\n * minDate([new Date('2024-01-01'), new Date('2025-01-01')]) // 2024-01-01\n */\nexport function minDate(dates: Date[]): Date {\n if (dates.length === 0) throw new Error('minDate requires at least one date')\n const ms = Math.min(...dates.map(d => {\n if (!isValidDate(d)) throw new InvalidDateError(d)\n return d.getTime()\n }))\n return new Date(ms)\n}\n\n// ─── Weekday Helpers ─────────────────────────────────────────────────────────\n\nfunction getNextWeekday(date: Date, targetDay: number): Date {\n if (!isValidDate(date)) throw new InvalidDateError(date)\n const result = new Date(date)\n const currentDay = result.getDay()\n let diff = targetDay - currentDay\n if (diff <= 0) diff += 7\n result.setDate(result.getDate() + diff)\n return result\n}\n\nfunction getLastWeekday(date: Date, targetDay: number): Date {\n if (!isValidDate(date)) throw new InvalidDateError(date)\n const result = new Date(date)\n const currentDay = result.getDay()\n let diff = currentDay - targetDay\n if (diff <= 0) diff += 7\n result.setDate(result.getDate() - diff)\n return result\n}\n\n/**\n * Returns the next Monday from the given date.\n *\n * @param date - Reference date.\n * @returns The next Monday.\n * @throws {InvalidDateError} If the input date is invalid.\n *\n * @example\n * nextMonday(new Date('2024-01-01')) // 2024-01-08 (Monday)\n */\nexport function nextMonday(date: Date): Date { return getNextWeekday(date, 1) }\n\n/**\n * Returns the next Tuesday from the given date.\n *\n * @param date - Reference date.\n * @returns The next Tuesday.\n * @throws {InvalidDateError} If the input date is invalid.\n *\n * @example\n * nextTuesday(new Date('2024-01-01')) // 2024-01-02 (Tuesday)\n */\nexport function nextTuesday(date: Date): Date { return getNextWeekday(date, 2) }\n\n/**\n * Returns the next Wednesday from the given date.\n *\n * @param date - Reference date.\n * @returns The next Wednesday.\n * @throws {InvalidDateError} If the input date is invalid.\n */\nexport function nextWednesday(date: Date): Date { return getNextWeekday(date, 3) }\n\n/**\n * Returns the next Thursday from the given date.\n *\n * @param date - Reference date.\n * @returns The next Thursday.\n * @throws {InvalidDateError} If the input date is invalid.\n */\nexport function nextThursday(date: Date): Date { return getNextWeekday(date, 4) }\n\n/**\n * Returns the next Friday from the given date.\n *\n * @param date - Reference date.\n * @returns The next Friday.\n * @throws {InvalidDateError} If the input date is invalid.\n */\nexport function nextFriday(date: Date): Date { return getNextWeekday(date, 5) }\n\n/**\n * Returns the next Saturday from the given date.\n *\n * @param date - Reference date.\n * @returns The next Saturday.\n * @throws {InvalidDateError} If the input date is invalid.\n */\nexport function nextSaturday(date: Date): Date { return getNextWeekday(date, 6) }\n\n/**\n * Returns the next Sunday from the given date.\n *\n * @param date - Reference date.\n * @returns The next Sunday.\n * @throws {InvalidDateError} If the input date is invalid.\n */\nexport function nextSunday(date: Date): Date { return getNextWeekday(date, 0) }\n\n/**\n * Returns the last (previous) Monday from the given date.\n *\n * @param date - Reference date.\n * @returns The last Monday.\n * @throws {InvalidDateError} If the input date is invalid.\n *\n * @example\n * lastMonday(new Date('2024-01-03')) // 2024-01-01 (Monday)\n */\nexport function lastMonday(date: Date): Date { return getLastWeekday(date, 1) }\n\n/**\n * Returns the last (previous) Tuesday from the given date.\n *\n * @param date - Reference date.\n * @returns The last Tuesday.\n * @throws {InvalidDateError} If the input date is invalid.\n */\nexport function lastTuesday(date: Date): Date { return getLastWeekday(date, 2) }\n\n/**\n * Returns the last (previous) Wednesday from the given date.\n *\n * @param date - Reference date.\n * @returns The last Wednesday.\n * @throws {InvalidDateError} If the input date is invalid.\n */\nexport function lastWednesday(date: Date): Date { return getLastWeekday(date, 3) }\n\n/**\n * Returns the last (previous) Thursday from the given date.\n *\n * @param date - Reference date.\n * @returns The last Thursday.\n * @throws {InvalidDateError} If the input date is invalid.\n */\nexport function lastThursday(date: Date): Date { return getLastWeekday(date, 4) }\n\n/**\n * Returns the last (previous) Friday from the given date.\n *\n * @param date - Reference date.\n * @returns The last Friday.\n * @throws {InvalidDateError} If the input date is invalid.\n *\n * @example\n * lastFriday(new Date('2024-01-03')) // 2023-12-29 (Friday)\n */\nexport function lastFriday(date: Date): Date { return getLastWeekday(date, 5) }\n\n/**\n * Returns the last (previous) Saturday from the given date.\n *\n * @param date - Reference date.\n * @returns The last Saturday.\n * @throws {InvalidDateError} If the input date is invalid.\n */\nexport function lastSaturday(date: Date): Date { return getLastWeekday(date, 6) }\n\n/**\n * Returns the last (previous) Sunday from the given date.\n *\n * @param date - Reference date.\n * @returns The last Sunday.\n * @throws {InvalidDateError} If the input date is invalid.\n */\nexport function lastSunday(date: Date): Date { return getLastWeekday(date, 0) }\n\n// ─── Duration Parsing ────────────────────────────────────────────────────────\n\n/**\n * Parses a human-readable duration string into milliseconds.\n *\n * Supported units:\n * - `w` — weeks\n * - `d` — days\n * - `h` — hours\n * - `m` — minutes\n * - `s` — seconds\n *\n * @param input - Duration string (e.g. `\"1h30m\"`, `\"2d\"`, `\"1w2d6h\"`).\n * @returns Total milliseconds.\n *\n * @example\n * parseDuration('1h30m') // 5400000\n * parseDuration('2d') // 172800000\n * parseDuration('1w') // 604800000\n */\nexport function parseDuration(input: string): number {\n const regex = /(\\d+)\\s*([wdhms])/g\n let ms = 0\n let match: RegExpExecArray | null\n while ((match = regex.exec(input)) !== null) {\n const val = parseInt(match[1]!, 10)\n switch (match[2]) {\n case 'w': ms += val * 7 * MS_IN_DAY; break\n case 'd': ms += val * MS_IN_DAY; break\n case 'h': ms += val * MS_IN_HOUR; break\n case 'm': ms += val * MS_IN_MINUTE; break\n case 's': ms += val * MS_IN_SECOND; break\n }\n }\n return ms\n}\n\n// ─── Indonesian Holidays ─────────────────────────────────────────────────────\n\ninterface HolidayEntry {\n name: string\n month: number\n day: number\n}\n\nconst INDONESIAN_FIXED_HOLIDAYS: HolidayEntry[] = [\n { name: 'New Year', month: 0, day: 1 },\n { name: 'Labor Day', month: 4, day: 1 },\n { name: 'Pancasila Day', month: 5, day: 1 },\n { name: 'Independence Day', month: 7, day: 17 },\n { name: 'National Awakening Day', month: 4, day: 20 },\n { name: 'National Heroes Day', month: 10, day: 10 },\n { name: 'Christmas', month: 11, day: 25 },\n]\n\nfunction computeEaster(year: number): Date {\n const a = year % 19\n const b = Math.floor(year / 100)\n const c = year % 100\n const d = Math.floor(b / 4)\n const e = b % 4\n const f = Math.floor((b + 8) / 25)\n const g = Math.floor((b - f + 1) / 3)\n const h = (19 * a + b - d - g + 15) % 30\n const i = Math.floor(c / 4)\n const k = c % 4\n const l = (32 + 2 * e + 2 * i - h - k) % 7\n const m = Math.floor((a + 11 * h + 22 * l) / 451)\n const month = Math.floor((h + l - 7 * m + 114) / 31)\n const day = ((h + l - 7 * m + 114) % 31) + 1\n return new Date(year, month - 1, day)\n}\n\nconst CHINESE_NEW_YEAR: Record<number, { month: number; day: number }> = {\n 2024: { month: 1, day: 10 },\n 2025: { month: 0, day: 29 },\n 2026: { month: 1, day: 17 },\n 2027: { month: 1, day: 6 },\n 2028: { month: 0, day: 26 },\n 2029: { month: 1, day: 13 },\n 2030: { month: 2, day: 3 },\n}\n\nconst NYEPI: Record<number, { month: number; day: number }> = {\n 2024: { month: 2, day: 11 },\n 2025: { month: 2, day: 29 },\n 2026: { month: 2, day: 19 },\n 2027: { month: 2, day: 7 },\n 2028: { month: 2, day: 26 },\n 2029: { month: 2, day: 15 },\n 2030: { month: 2, day: 5 },\n}\n\nconst VESAK: Record<number, { month: number; day: number }> = {\n 2024: { month: 4, day: 23 },\n 2025: { month: 4, day: 12 },\n 2026: { month: 4, day: 31 },\n 2027: { month: 4, day: 20 },\n 2028: { month: 4, day: 9 },\n 2029: { month: 4, day: 28 },\n 2030: { month: 4, day: 18 },\n}\n\nconst EID_AL_FITR: Record<number, Array<{ month: number; day: number }>> = {\n 2024: [{ month: 3, day: 10 }, { month: 3, day: 11 }],\n 2025: [{ month: 2, day: 31 }, { month: 3, day: 1 }],\n 2026: [{ month: 2, day: 21 }, { month: 2, day: 22 }],\n 2027: [{ month: 2, day: 10 }, { month: 2, day: 11 }],\n 2028: [{ month: 2, day: 28 }, { month: 2, day: 29 }],\n 2029: [{ month: 2, day: 17 }, { month: 2, day: 18 }],\n 2030: [{ month: 2, day: 7 }, { month: 2, day: 8 }],\n}\n\nconst EID_AL_ADHA: Record<number, { month: number; day: number }> = {\n 2024: { month: 5, day: 17 },\n 2025: { month: 5, day: 7 },\n 2026: { month: 4, day: 27 },\n 2027: { month: 4, day: 17 },\n 2028: { month: 5, day: 5 },\n 2029: { month: 4, day: 25 },\n 2030: { month: 4, day: 15 },\n}\n\nconst ISLAMIC_NEW_YEAR: Record<number, { month: number; day: number }> = {\n 2024: { month: 6, day: 7 },\n 2025: { month: 5, day: 27 },\n 2026: { month: 5, day: 16 },\n 2027: { month: 5, day: 6 },\n 2028: { month: 6, day: 24 },\n 2029: { month: 6, day: 13 },\n 2030: { month: 6, day: 3 },\n}\n\nconst PROPHETS_BIRTHDAY: Record<number, { month: number; day: number }> = {\n 2024: { month: 8, day: 16 },\n 2025: { month: 8, day: 5 },\n 2026: { month: 7, day: 26 },\n 2027: { month: 7, day: 16 },\n 2028: { month: 8, day: 3 },\n 2029: { month: 7, day: 23 },\n 2030: { month: 7, day: 13 },\n}\n\nconst ISRA_MIRAJ: Record<number, { month: number; day: number }> = {\n 2024: { month: 1, day: 8 },\n 2025: { month: 0, day: 28 },\n 2026: { month: 0, day: 17 },\n 2027: { month: 0, day: 6 },\n 2028: { month: 0, day: 26 },\n 2029: { month: 1, day: 14 },\n 2030: { month: 1, day: 3 },\n}\n\nfunction addHolidayEntry(\n entries: HolidayEntry[],\n name: string,\n month: number,\n day: number,\n): void {\n entries.push({ name, month, day })\n}\n\nfunction getIndonesianHolidaysForYear(year: number): HolidayEntry[] {\n const holidays: HolidayEntry[] = [...INDONESIAN_FIXED_HOLIDAYS]\n\n // Easter-based holidays (computed)\n const easter = computeEaster(year)\n addHolidayEntry(holidays, 'Good Friday', easter.getMonth(), easter.getDate() - 2)\n addHolidayEntry(holidays, 'Easter', easter.getMonth(), easter.getDate())\n\n // Ascension = Easter + 39 days\n const ascension = new Date(easter)\n ascension.setDate(ascension.getDate() + 39)\n addHolidayEntry(holidays, 'Ascension of Jesus Christ', ascension.getMonth(), ascension.getDate())\n\n // Lookup-based movable holidays\n const cny = CHINESE_NEW_YEAR[year]\n if (cny) addHolidayEntry(holidays, 'Chinese New Year', cny.month, cny.day)\n\n const nyepi = NYEPI[year]\n if (nyepi) addHolidayEntry(holidays, 'Nyepi (Day of Silence)', nyepi.month, nyepi.day)\n\n const vesak = VESAK[year]\n if (vesak) addHolidayEntry(holidays, 'Vesak (Buddha\\'s Birthday)', vesak.month, vesak.day)\n\n const eidDays = EID_AL_FITR[year]\n if (eidDays) {\n eidDays.forEach((entry, idx) => {\n addHolidayEntry(holidays, idx === 0 ? 'Eid al-Fitr' : 'Eid al-Fitr (Day 2)', entry.month, entry.day)\n })\n }\n\n const eidAdha = EID_AL_ADHA[year]\n if (eidAdha) addHolidayEntry(holidays, 'Eid al-Adha', eidAdha.month, eidAdha.day)\n\n const islNewYear = ISLAMIC_NEW_YEAR[year]\n if (islNewYear) addHolidayEntry(holidays, 'Islamic New Year', islNewYear.month, islNewYear.day)\n\n const prophetBday = PROPHETS_BIRTHDAY[year]\n if (prophetBday) addHolidayEntry(holidays, 'Prophet Muhammad\\'s Birthday', prophetBday.month, prophetBday.day)\n\n const isra = ISRA_MIRAJ[year]\n if (isra) addHolidayEntry(holidays, 'Isra\\' Mi\\'raj (Ascension of Prophet Muhammad)', isra.month, isra.day)\n\n return holidays\n}\n\n/**\n * Checks if a date is an Indonesian public holiday.\n *\n * Includes fixed-date holidays (New Year, Labor Day, Pancasila Day,\n * Independence Day, National Awakening Day, National Heroes Day, Christmas),\n * Easter-based holidays (Good Friday, Easter, Ascension), and lookup-based\n * movable holidays (Chinese New Year, Nyepi, Vesak, Eid al-Fitr,\n * Eid al-Adha, Islamic New Year, Prophet's Birthday, Isra' Mi'raj).\n *\n * Movable holidays (Chinese New Year, Nyepi, Vesak, Islamic holidays) are\n * precomputed for years 2024–2030. Dates outside this range may return\n * `false` for those holidays.\n *\n * @param date - The date to check.\n * @returns Whether the date is an Indonesian public holiday.\n * @throws {InvalidDateError} If the input date is invalid.\n *\n * @example\n * isHolidayIndonesia(new Date('2024-08-17')) // true (Independence Day)\n * isHolidayIndonesia(new Date('2024-12-25')) // true (Christmas)\n */\nexport function isHolidayIndonesia(date: Date): boolean {\n if (!isValidDate(date)) throw new InvalidDateError(date)\n\n const year = date.getFullYear()\n const holidays = getIndonesianHolidaysForYear(year)\n\n for (const h of holidays) {\n if (h.month === date.getMonth() && h.day === date.getDate()) {\n return true\n }\n }\n\n return false\n}\n\n/**\n * Returns the name(s) of Indonesian public holidays for a given date, or an\n * empty array if the date is not a holiday.\n *\n * @param date - The date to check.\n * @returns Array of holiday names.\n * @throws {InvalidDateError} If the input date is invalid.\n *\n * @example\n * getIndonesianHolidayNames(new Date('2024-08-17')) // ['Independence Day']\n */\nexport function getIndonesianHolidayNames(date: Date): string[] {\n if (!isValidDate(date)) throw new InvalidDateError(date)\n\n const year = date.getFullYear()\n const holidays = getIndonesianHolidaysForYear(year)\n const names: string[] = []\n\n for (const h of holidays) {\n if (h.month === date.getMonth() && h.day === date.getDate()) {\n names.push(h.name)\n }\n }\n\n return names\n}\n"],"mappings":"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","names":[]}
package/dist/index.d.ts CHANGED
@@ -13,7 +13,7 @@ export { generateReport } from './dep-exray/reporter/index.js';
13
13
  export { analyzeUsage } from './dep-exray/analyzer/index.js';
14
14
  export { DependencyInfo, ReplacementSuggestion, ScanResult, ScannerConfig, SecurityIssue } from './dep-exray/types.js';
15
15
  export { KNOWN_CVES, KNOWN_MAPPINGS } from './dep-exray/known-mappings.js';
16
- export { NIKInfo, isEmail, isKodepos, isNIK, isNPWP, isNoRekening, isPhone, isPlatNomor, isURL, parseNIK } from './validation/index.js';
16
+ export { N as NIKInfo, i as isEmail, a as isKodepos, b as isNIK, c as isNPWP, d as isNoRekening, e as isPhone, f as isPlatNomor, g as isURL, p as parseNIK } from './isNoRekening-CHSpgD4P.js';
17
17
  export { ErrorCode, MultiError, TypedError, collectErrors, createError, isTypedError } from './error/index.js';
18
18
  export { L as LogLevel, a as Logger, T as Transport, c as consoleTransport, b as createBufferedTransport, d as createConsoleTransport, e as createFileTransport, f as createJsonTransport, l as logger } from './index-BgG21uJC.js';
19
19
  export { contrastRatio, darken, hexToRgb, lighten, meetsWCAG, rgbToHex } from './color/index.js';