@typescript-calendar-lib/core 0.5.3 → 0.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +146 -3
- package/dist/index.js +69 -24
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Shared, framework-agnostic calendar utilities: date math, locale data, and grid building. Zero runtime dependencies.
|
|
4
4
|
|
|
5
|
-
> **Tip:** You normally don't need `core` directly
|
|
5
|
+
> **Tip:** You normally don't need `core` directly. The `cli`, `react`, `svelte`, and `tui` packages build on `core`, but each exposes only its own surface — reach for `core` directly when you want the date math, locale tables, or grid builder itself.
|
|
6
6
|
|
|
7
7
|
## Installation
|
|
8
8
|
|
|
@@ -10,8 +10,6 @@ Shared, framework-agnostic calendar utilities: date math, locale data, and grid
|
|
|
10
10
|
pnpm add @typescript-calendar-lib/core
|
|
11
11
|
# or
|
|
12
12
|
npm install @typescript-calendar-lib/core
|
|
13
|
-
# or
|
|
14
|
-
bun add @typescript-calendar-lib/core
|
|
15
13
|
```
|
|
16
14
|
|
|
17
15
|
## Types
|
|
@@ -45,6 +43,7 @@ interface CalendarOptions {
|
|
|
45
43
|
year: number;
|
|
46
44
|
month: number; // 1-indexed (1–12)
|
|
47
45
|
locale?: Locale; // default: "en"
|
|
46
|
+
holidayLocale?: Locale; // default: "ja" (see Holidays)
|
|
48
47
|
weekStart?: WeekStart; // default: "sunday"
|
|
49
48
|
highlight?: Date; // date to highlight (e.g. today)
|
|
50
49
|
highlightStyle?: HighlightStyle; // default: "bracket"
|
|
@@ -61,6 +60,7 @@ Same as `CalendarOptions` minus `month` — renders a full year:
|
|
|
61
60
|
interface CalendarYearOptions {
|
|
62
61
|
year: number;
|
|
63
62
|
locale?: Locale;
|
|
63
|
+
holidayLocale?: Locale; // default: "ja"
|
|
64
64
|
weekStart?: WeekStart;
|
|
65
65
|
highlight?: Date;
|
|
66
66
|
highlightStyle?: HighlightStyle;
|
|
@@ -78,6 +78,7 @@ interface CalendarRangeOptions {
|
|
|
78
78
|
from: Date;
|
|
79
79
|
to: Date;
|
|
80
80
|
locale?: Locale;
|
|
81
|
+
holidayLocale?: Locale; // default: "ja"
|
|
81
82
|
weekStart?: WeekStart;
|
|
82
83
|
highlight?: Date;
|
|
83
84
|
highlightStyle?: HighlightStyle;
|
|
@@ -90,6 +91,35 @@ interface CalendarRangeOptions {
|
|
|
90
91
|
|
|
91
92
|
Same as `CalendarOptions` minus `year`/`month`. Used by the low-level `renderMonth` helper.
|
|
92
93
|
|
|
94
|
+
### `CalendarCellState`
|
|
95
|
+
|
|
96
|
+
Flags computed by `getCalendarCellState` for a single day cell:
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
interface CalendarCellState {
|
|
100
|
+
isWeekend: boolean; // Saturday or Sunday
|
|
101
|
+
isHoliday: boolean; // holiday per `holidayLocale` (default "ja")
|
|
102
|
+
isToday: boolean; // matches `today`
|
|
103
|
+
isHighlight: boolean; // matches `highlight`
|
|
104
|
+
isInRange: boolean; // within `range` (inclusive)
|
|
105
|
+
isDisabled: boolean; // matches `isDateDisabled`
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### `LocaleData`
|
|
110
|
+
|
|
111
|
+
The shape of the per-locale data held in `LOCALES`:
|
|
112
|
+
|
|
113
|
+
```ts
|
|
114
|
+
interface LocaleData {
|
|
115
|
+
months: readonly string[];
|
|
116
|
+
weekdays: readonly string[];
|
|
117
|
+
weekdaysShort: readonly string[];
|
|
118
|
+
weekdaysMonday: readonly string[];
|
|
119
|
+
weekdaysMondayShort: readonly string[];
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
93
123
|
## Constants
|
|
94
124
|
|
|
95
125
|
### `LOCALES`
|
|
@@ -104,6 +134,12 @@ Contains month names, weekday headers, and short weekday headers for each locale
|
|
|
104
134
|
|
|
105
135
|
The supported year range (`1` / `9999`). Values outside this range are rejected by validation.
|
|
106
136
|
|
|
137
|
+
### `HOLIDAY_MIN_YEAR` / `HOLIDAY_MAX_YEAR`
|
|
138
|
+
|
|
139
|
+
The year range for which holiday rules are implemented (`1949` / `2100`). Outside that
|
|
140
|
+
range the holiday functions report "no holiday" rather than throwing — see
|
|
141
|
+
[Holidays](#holidays).
|
|
142
|
+
|
|
107
143
|
## Functions
|
|
108
144
|
|
|
109
145
|
### `getMonthName(locale, month): string`
|
|
@@ -133,6 +169,15 @@ getLocaleData("en").weekdays; // ["Sun", "Mon", ..., "Sat"]
|
|
|
133
169
|
getLocaleData("ja").weekdaysMonday; // ["月", "火", ..., "日"]
|
|
134
170
|
```
|
|
135
171
|
|
|
172
|
+
### `getLocaleData(locale): LocaleData`
|
|
173
|
+
|
|
174
|
+
Returns the raw locale data (`months`, `weekdays`, `weekdaysShort`, plus the Monday-start rotations `weekdaysMonday` and `weekdaysMondayShort`). Throws `RangeError` for an unknown locale.
|
|
175
|
+
|
|
176
|
+
```ts
|
|
177
|
+
getLocaleData("en").weekdays; // ["Sun", "Mon", ..., "Sat"]
|
|
178
|
+
getLocaleData("ja").weekdaysMonday; // ["月", "火", ..., "日"]
|
|
179
|
+
```
|
|
180
|
+
|
|
136
181
|
### `buildMonthGrid(year, month, weekStart): (number | null)[][]`
|
|
137
182
|
|
|
138
183
|
Builds a 6×7 grid of day numbers (`1`–`31`) with `null` for empty cells. The grid is always 6 rows tall for stable layouts:
|
|
@@ -193,6 +238,54 @@ Creates a local `Date` at `00:00:00` without the `new Date(year, ...)` 1900-inte
|
|
|
193
238
|
|
|
194
239
|
Throws `RangeError` when `date` is not a `Date` instance or is an `Invalid Date`.
|
|
195
240
|
|
|
241
|
+
### `getCalendarCellState(date, options?): CalendarCellState`
|
|
242
|
+
|
|
243
|
+
Computes the display state of a single day cell (weekend, holiday, today, highlight, in-range, disabled) — the shared predicate every package uses to style and gate cells:
|
|
244
|
+
|
|
245
|
+
```ts
|
|
246
|
+
const state = getCalendarCellState(new Date(2026, 8, 6), {
|
|
247
|
+
today: new Date(2026, 8, 6),
|
|
248
|
+
highlight: new Date(2026, 8, 6),
|
|
249
|
+
range: { from: new Date(2026, 8, 1), to: new Date(2026, 8, 10) },
|
|
250
|
+
});
|
|
251
|
+
// { isWeekend: true, isHoliday: false, isToday: true, isHighlight: true, isInRange: true, isDisabled: false }
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
Options (all optional) mirror the per-locale calendar options: `today`, `highlight`, `range`, `isDateDisabled`, and `holidayLocale`. Pass `isDateDisabled` to mark specific dates as non-selectable — it is called once per cell with the cell's `Date`; returning `true` sets `isDisabled` (this is what the `tui`, `cli`, `react`, and `svelte` packages use to block selection/cursor movement):
|
|
255
|
+
|
|
256
|
+
```ts
|
|
257
|
+
const state = getCalendarCellState(new Date(2026, 8, 15), {
|
|
258
|
+
isDateDisabled: (date) => date.getDay() === 0, // disable Sundays
|
|
259
|
+
});
|
|
260
|
+
// state.isDisabled === true
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
With no options every flag is `false` except `isWeekend` (derived from the date) and `isHoliday` (derived from `holidayLocale`). Throws `RangeError` when `date` is invalid.
|
|
264
|
+
|
|
265
|
+
### `isLeapYear(year): boolean`
|
|
266
|
+
|
|
267
|
+
Returns `true` for Gregorian leap years (divisible by 4, except by 100 unless also by 400):
|
|
268
|
+
|
|
269
|
+
```ts
|
|
270
|
+
isLeapYear(2024); // true
|
|
271
|
+
isLeapYear(1900); // false
|
|
272
|
+
isLeapYear(2000); // true
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
Works for years `1`–`99` too (no 1900-interpretation). Throws `RangeError` for out-of-range or non-integer years.
|
|
276
|
+
|
|
277
|
+
### `daysInMonth(year, month): number`
|
|
278
|
+
|
|
279
|
+
Returns the number of days in the month (`28`–`31`):
|
|
280
|
+
|
|
281
|
+
```ts
|
|
282
|
+
daysInMonth(2026, 2); // 28
|
|
283
|
+
daysInMonth(2024, 2); // 29 (leap year)
|
|
284
|
+
daysInMonth(2026, 4); // 30
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
Throws `RangeError` for invalid `year`/`month`.
|
|
288
|
+
|
|
196
289
|
#### Arithmetic
|
|
197
290
|
|
|
198
291
|
### `addDays(date, amount): Date`
|
|
@@ -346,6 +439,49 @@ formatDate(date, "yyyy年M月d日", "ja"); // "2026年9月25日"
|
|
|
346
439
|
|
|
347
440
|
> **Note:** all of the above validate their inputs and throw `RangeError` on invalid values: dates are checked with `assertValidDate`, `add*` amounts must be integers, and `weekStart` must be `"sunday" | "monday"`.
|
|
348
441
|
|
|
442
|
+
|
|
443
|
+
## Holidays
|
|
444
|
+
|
|
445
|
+
`core` ships a complete Japanese holiday table — fixed-date holidays, happy-Monday
|
|
446
|
+
rules, and the equinox-based `春分の日` / `秋分の日` approximations — plus the
|
|
447
|
+
2019/2020/2021 reforms and the pre-1973 fixed-date rules.
|
|
448
|
+
|
|
449
|
+
```ts
|
|
450
|
+
import { getHolidayName, isHoliday } from "@typescript-calendar-lib/core";
|
|
451
|
+
|
|
452
|
+
isHoliday(new Date(2026, 4, 4)); // true
|
|
453
|
+
getHolidayName(new Date(2026, 4, 4)); // "みどりの日"
|
|
454
|
+
isHoliday(new Date(2026, 4, 6)); // true
|
|
455
|
+
getHolidayName(new Date(2026, 4, 6)); // "振替休日" (happy-Monday rule)
|
|
456
|
+
isHoliday(new Date(2026, 8, 22)); // true
|
|
457
|
+
getHolidayName(new Date(2026, 8, 22)); // "国民の休日"
|
|
458
|
+
isHoliday(new Date(2026, 8, 24)); // false
|
|
459
|
+
getHolidayName(new Date(2026, 8, 24)); // undefined
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
> **Note:** `holidayLocale` defaults to `"ja"` — *independently of `locale`*. Calling
|
|
463
|
+
> `isHoliday(date)` with no arguments answers the **Japanese** calendar question, so an
|
|
464
|
+
> `locale: "en"` calendar still flags Japanese holidays. Pass `holidayLocale` explicitly
|
|
465
|
+
> if that is not what you want.
|
|
466
|
+
|
|
467
|
+
Rules are implemented for `HOLIDAY_MIN_YEAR` (`1949`) through `HOLIDAY_MAX_YEAR`
|
|
468
|
+
(`2100`). Outside that window the functions report "no holiday" rather than throwing.
|
|
469
|
+
Only `"ja"` has a rule table today: any other `holidayLocale` behaves as "no holidays",
|
|
470
|
+
which lets a caller opt out explicitly instead of relying on the default.
|
|
471
|
+
|
|
472
|
+
### Business days
|
|
473
|
+
|
|
474
|
+
```ts
|
|
475
|
+
import { addBusinessDays, diffInBusinessDays, isBusinessDay } from "@typescript-calendar-lib/core";
|
|
476
|
+
|
|
477
|
+
isBusinessDay(new Date(2026, 8, 5)); // false — Saturday
|
|
478
|
+
addBusinessDays(new Date(2026, 8, 4), 1); // Mon Sep 7 2026
|
|
479
|
+
diffInBusinessDays(new Date(2026, 8, 4), new Date(2026, 8, 7)); // 1
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
A business day is a day that is neither a weekend nor a holiday under `holidayLocale`.
|
|
483
|
+
All three take an optional trailing `holidayLocale`.
|
|
484
|
+
|
|
349
485
|
## Input validation
|
|
350
486
|
|
|
351
487
|
All functions validate their inputs and throw `RangeError` on invalid values instead of silently producing wrong results:
|
|
@@ -379,9 +515,12 @@ import type {
|
|
|
379
515
|
|
|
380
516
|
// Values
|
|
381
517
|
import {
|
|
518
|
+
HOLIDAY_MAX_YEAR,
|
|
519
|
+
HOLIDAY_MIN_YEAR,
|
|
382
520
|
LOCALES,
|
|
383
521
|
MAX_YEAR,
|
|
384
522
|
MIN_YEAR,
|
|
523
|
+
addBusinessDays,
|
|
385
524
|
addDays,
|
|
386
525
|
addMonths,
|
|
387
526
|
addWeeks,
|
|
@@ -391,6 +530,7 @@ import {
|
|
|
391
530
|
clampDate,
|
|
392
531
|
createDate,
|
|
393
532
|
daysInMonth,
|
|
533
|
+
diffInBusinessDays,
|
|
394
534
|
diffInCalendarDays,
|
|
395
535
|
diffInCalendarMonths,
|
|
396
536
|
diffInCalendarYears,
|
|
@@ -402,6 +542,7 @@ import {
|
|
|
402
542
|
formatDate,
|
|
403
543
|
getCalendarCellState,
|
|
404
544
|
getDayOfYear,
|
|
545
|
+
getHolidayName,
|
|
405
546
|
getISOWeek,
|
|
406
547
|
getLocaleData,
|
|
407
548
|
getMonthName,
|
|
@@ -410,7 +551,9 @@ import {
|
|
|
410
551
|
getWeekdayHeaders,
|
|
411
552
|
isAfter,
|
|
412
553
|
isBefore,
|
|
554
|
+
isBusinessDay,
|
|
413
555
|
isDateInRange,
|
|
556
|
+
isHoliday,
|
|
414
557
|
isLeapYear,
|
|
415
558
|
isSameDay,
|
|
416
559
|
isSameMonth,
|
package/dist/index.js
CHANGED
|
@@ -480,15 +480,45 @@ function formatDate(date, pattern, locale = "en") {
|
|
|
480
480
|
const HOLIDAY_MIN_YEAR = 1949;
|
|
481
481
|
/** 祝日が計算できる年範囲(秋分の日の近似式が有効な上限。実用上十分) */
|
|
482
482
|
const HOLIDAY_MAX_YEAR = 2100;
|
|
483
|
-
/** 1
|
|
484
|
-
const ONE_OFF_HOLIDAYS =
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
483
|
+
/** 1回限りの祝日(皇室行事・改元に伴う法律で定められたもの) */
|
|
484
|
+
const ONE_OFF_HOLIDAYS = [
|
|
485
|
+
{
|
|
486
|
+
year: 1959,
|
|
487
|
+
month: 4,
|
|
488
|
+
day: 10,
|
|
489
|
+
name: "皇太子明仁親王の結婚の儀"
|
|
490
|
+
},
|
|
491
|
+
{
|
|
492
|
+
year: 1989,
|
|
493
|
+
month: 2,
|
|
494
|
+
day: 24,
|
|
495
|
+
name: "昭和天皇の大喪の礼"
|
|
496
|
+
},
|
|
497
|
+
{
|
|
498
|
+
year: 1990,
|
|
499
|
+
month: 11,
|
|
500
|
+
day: 12,
|
|
501
|
+
name: "即位の礼正殿の儀"
|
|
502
|
+
},
|
|
503
|
+
{
|
|
504
|
+
year: 1993,
|
|
505
|
+
month: 6,
|
|
506
|
+
day: 9,
|
|
507
|
+
name: "皇太子徳仁親王の結婚の儀"
|
|
508
|
+
},
|
|
509
|
+
{
|
|
510
|
+
year: 2019,
|
|
511
|
+
month: 5,
|
|
512
|
+
day: 1,
|
|
513
|
+
name: "天皇即位の日"
|
|
514
|
+
},
|
|
515
|
+
{
|
|
516
|
+
year: 2019,
|
|
517
|
+
month: 10,
|
|
518
|
+
day: 22,
|
|
519
|
+
name: "即位礼正殿の儀"
|
|
520
|
+
}
|
|
521
|
+
];
|
|
492
522
|
/** 年月日の曜日(0=日曜) */
|
|
493
523
|
function dayOfWeek(year, month, day) {
|
|
494
524
|
return createDate(year, month - 1, day).getDay();
|
|
@@ -555,10 +585,7 @@ function holidaysOfYear(year) {
|
|
|
555
585
|
}
|
|
556
586
|
if (year >= 1949) add(11, 3, "文化の日");
|
|
557
587
|
if (year >= 1949) add(11, 23, "勤労感謝の日");
|
|
558
|
-
for (const
|
|
559
|
-
const [y, m, d] = key.split("-").map(Number);
|
|
560
|
-
if (y === year) add(m, d, name);
|
|
561
|
-
}
|
|
588
|
+
for (const { year: y, month: m, day: d, name } of ONE_OFF_HOLIDAYS) if (y === year) add(m, d, name);
|
|
562
589
|
const inList = (month, day) => list.some((h) => h.month === month && h.day === day);
|
|
563
590
|
if (year >= 1973) {
|
|
564
591
|
const substituteFrom = createDate(1973, 3, 12).getTime();
|
|
@@ -588,32 +615,50 @@ function holidaysOfYear(year) {
|
|
|
588
615
|
}
|
|
589
616
|
return list;
|
|
590
617
|
}
|
|
618
|
+
/**
|
|
619
|
+
* 祝日一覧に月・日のインデックスを張る。
|
|
620
|
+
*/
|
|
621
|
+
function toIndex(list) {
|
|
622
|
+
const byMonth = /* @__PURE__ */ new Map();
|
|
623
|
+
for (const h of list) {
|
|
624
|
+
let days = byMonth.get(h.month);
|
|
625
|
+
if (days === void 0) {
|
|
626
|
+
days = /* @__PURE__ */ new Map();
|
|
627
|
+
byMonth.set(h.month, days);
|
|
628
|
+
}
|
|
629
|
+
days.set(h.day, h.name);
|
|
630
|
+
}
|
|
631
|
+
return {
|
|
632
|
+
list,
|
|
633
|
+
byMonth
|
|
634
|
+
};
|
|
635
|
+
}
|
|
591
636
|
/** 年の計算結果キャッシュ(同じ年を何度も参照する描画用途のため) */
|
|
592
637
|
const holidayCache = /* @__PURE__ */ new Map();
|
|
593
|
-
/**
|
|
594
|
-
function
|
|
638
|
+
/** 祝日インデックスを取得する。対象外ロケール・範囲外の年は null */
|
|
639
|
+
function holidayIndexOf(date, locale) {
|
|
595
640
|
if (locale !== "ja") return null;
|
|
596
641
|
const year = date.getFullYear();
|
|
597
642
|
if (year < 1949 || year > 2100) return null;
|
|
598
643
|
const cached = holidayCache.get(year);
|
|
599
644
|
if (cached !== void 0) return cached;
|
|
600
|
-
const
|
|
601
|
-
holidayCache.set(year,
|
|
602
|
-
return
|
|
645
|
+
const index = toIndex(holidaysOfYear(year));
|
|
646
|
+
holidayCache.set(year, index);
|
|
647
|
+
return index;
|
|
603
648
|
}
|
|
604
649
|
/** 日付が祝日(日本の国民の祝日・振替休日・国民の休日)か判定する。対象外ロケール/年は false */
|
|
605
650
|
function isHoliday(date, locale = "ja") {
|
|
606
651
|
assertValidDate(date);
|
|
607
|
-
const
|
|
608
|
-
if (
|
|
609
|
-
return
|
|
652
|
+
const index = holidayIndexOf(date, locale);
|
|
653
|
+
if (index === null) return false;
|
|
654
|
+
return index.byMonth.get(date.getMonth() + 1)?.get(date.getDate()) !== void 0;
|
|
610
655
|
}
|
|
611
656
|
/** 日付の祝日名を返す。祝日でない・対象外ロケール/年は undefined */
|
|
612
657
|
function getHolidayName(date, locale = "ja") {
|
|
613
658
|
assertValidDate(date);
|
|
614
|
-
const
|
|
615
|
-
if (
|
|
616
|
-
return
|
|
659
|
+
const index = holidayIndexOf(date, locale);
|
|
660
|
+
if (index === null) return void 0;
|
|
661
|
+
return index.byMonth.get(date.getMonth() + 1)?.get(date.getDate());
|
|
617
662
|
}
|
|
618
663
|
/** 日付が営業日(平日かつ祝日でない)か判定する */
|
|
619
664
|
function isBusinessDay(date, locale = "ja") {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/validation.ts","../src/locale.ts","../src/date-math.ts","../src/holidays.ts","../src/utils.ts"],"sourcesContent":["// ─── 入力検証 ─────────────────────────────────────────────\n\n/** サポートする年の最小値(JS Date は 0-99 を 1900+年 と解釈するため 1 から) */\nexport const MIN_YEAR = 1;\n/** サポートする年の最大値 */\nexport const MAX_YEAR = 9999;\n\n/** 値が min-max の整数であることを検証する(不正なら RangeError) */\nfunction assertIntegerInRange(\n name: string,\n value: number,\n min: number,\n max: number,\n): void {\n if (!Number.isInteger(value) || value < min || value > max) {\n throw new RangeError(\n `Invalid ${name}: ${value} (expected an integer between ${min} and ${max})`,\n );\n }\n}\n\n/** 年が 1-9999 の整数であることを検証する */\nexport function assertValidYear(year: number): void {\n assertIntegerInRange(\"year\", year, MIN_YEAR, MAX_YEAR);\n}\n\n/** 月が 1-12 の整数であることを検証する */\nexport function assertValidMonth(month: number): void {\n assertIntegerInRange(\"month\", month, 1, 12);\n}\n\n/** 年の組み合わせ(year と month)を検証する */\nexport function assertValidYearMonth(year: number, month: number): void {\n assertValidYear(year);\n assertValidMonth(month);\n}\n\n/** 週の開始曜日を検証する */\nexport function assertValidWeekStart(weekStart: string): void {\n if (weekStart !== \"sunday\" && weekStart !== \"monday\") {\n throw new RangeError(\n `Invalid weekStart: \"${weekStart}\" (expected \"sunday\" or \"monday\")`,\n );\n }\n}\n\n/** Date が有効(Invalid Date でない)ことを検証する */\nexport function assertValidDate(date: Date): void {\n if (!(date instanceof Date) || Number.isNaN(date.getTime())) {\n throw new RangeError(`Invalid Date: ${String(date)}`);\n }\n}\n\n/**\n * ローカルの指定日 00:00:00 を生成する。\n * `new Date(year, ...)` は year 0-99 を 1900+year と解釈するため、\n * setFullYear を使って year 0-99 も正しく扱えるようにする。\n *\n * - year は 1-9999、monthIndex は 0-12、day は 0-31 の整数である必要がある(それ以外は RangeError)\n * - monthIndex 12 は翌年1月(`new Date` と同じロールオーバー。lastDayOfMonth が 12月の月末取得に使う)\n * - day 0 は前月の月末(`new Date` と同じ規則)\n * - day がその月の日数を超える場合は翌月にロールする(`new Date` と同じ挙動)\n */\nexport function createDate(\n year: number,\n monthIndex: number,\n day: number,\n): Date {\n assertValidYear(year);\n assertIntegerInRange(\"monthIndex\", monthIndex, 0, 12);\n assertIntegerInRange(\"day\", day, 0, 31);\n const date = new Date(0);\n date.setHours(0, 0, 0, 0);\n date.setFullYear(year, monthIndex, day);\n return date;\n}\n","import type { Locale, WeekStart } from \"./types.ts\";\nimport { assertValidMonth, assertValidWeekStart } from \"./validation.ts\";\n\nexport interface LocaleData {\n months: readonly string[];\n weekdays: readonly string[];\n weekdaysShort: readonly string[];\n weekdaysMonday: readonly string[];\n weekdaysMondayShort: readonly string[];\n}\n\n/** 月曜始まりの配列は日曜始まりの配列を前ローテーションして生成する */\nfunction makeLocale(\n months: readonly string[],\n weekdays: readonly string[],\n weekdaysShort: readonly string[] = weekdays,\n): LocaleData {\n const rotate = (arr: readonly string[]) => [...arr.slice(1), arr[0]!];\n return {\n months,\n weekdays,\n weekdaysShort,\n weekdaysMonday: rotate(weekdays),\n weekdaysMondayShort: rotate(weekdaysShort),\n };\n}\n\nexport const LOCALES: Record<Locale, LocaleData> = {\n en: makeLocale(\n [\n \"January\",\n \"February\",\n \"March\",\n \"April\",\n \"May\",\n \"June\",\n \"July\",\n \"August\",\n \"September\",\n \"October\",\n \"November\",\n \"December\",\n ],\n [\"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\"],\n [\"Su\", \"Mo\", \"Tu\", \"We\", \"Th\", \"Fr\", \"Sa\"],\n ),\n ja: makeLocale(\n [\n \"1月\",\n \"2月\",\n \"3月\",\n \"4月\",\n \"5月\",\n \"6月\",\n \"7月\",\n \"8月\",\n \"9月\",\n \"10月\",\n \"11月\",\n \"12月\",\n ],\n [\"日\", \"月\", \"火\", \"水\", \"木\", \"金\", \"土\"],\n ),\n es: makeLocale(\n [\n \"enero\",\n \"febrero\",\n \"marzo\",\n \"abril\",\n \"mayo\",\n \"junio\",\n \"julio\",\n \"agosto\",\n \"septiembre\",\n \"octubre\",\n \"noviembre\",\n \"diciembre\",\n ],\n [\"dom\", \"lun\", \"mar\", \"mié\", \"jue\", \"vie\", \"sáb\"],\n [\"do\", \"lu\", \"ma\", \"mi\", \"ju\", \"vi\", \"sá\"],\n ),\n de: makeLocale(\n [\n \"Januar\",\n \"Februar\",\n \"März\",\n \"April\",\n \"Mai\",\n \"Juni\",\n \"Juli\",\n \"August\",\n \"September\",\n \"Oktober\",\n \"November\",\n \"Dezember\",\n ],\n [\"So\", \"Mo\", \"Di\", \"Mi\", \"Do\", \"Fr\", \"Sa\"],\n ),\n fr: makeLocale(\n [\n \"janvier\",\n \"février\",\n \"mars\",\n \"avril\",\n \"mai\",\n \"juin\",\n \"juillet\",\n \"août\",\n \"septembre\",\n \"octobre\",\n \"novembre\",\n \"décembre\",\n ],\n [\"dim.\", \"lun.\", \"mar.\", \"mer.\", \"jeu.\", \"ven.\", \"sam.\"],\n [\"di\", \"lu\", \"ma\", \"me\", \"je\", \"ve\", \"sa\"],\n ),\n ko: makeLocale(\n [\n \"1월\",\n \"2월\",\n \"3월\",\n \"4월\",\n \"5월\",\n \"6월\",\n \"7월\",\n \"8월\",\n \"9월\",\n \"10월\",\n \"11월\",\n \"12월\",\n ],\n [\"일\", \"월\", \"화\", \"수\", \"목\", \"금\", \"토\"],\n ),\n zh: makeLocale(\n [\n \"一月\",\n \"二月\",\n \"三月\",\n \"四月\",\n \"五月\",\n \"六月\",\n \"七月\",\n \"八月\",\n \"九月\",\n \"十月\",\n \"十一月\",\n \"十二月\",\n ],\n [\"日\", \"一\", \"二\", \"三\", \"四\", \"五\", \"六\"],\n ),\n};\n\n/** ロケールデータを取得する(未知のロケールは RangeError) */\nexport function getLocaleData(locale: Locale): LocaleData {\n const data = LOCALES[locale];\n if (data === undefined) {\n throw new RangeError(`Invalid locale: \"${locale}\"`);\n }\n return data;\n}\n\nexport function getWeekdayHeaders(\n locale: Locale,\n weekStart: WeekStart,\n): readonly string[] {\n assertValidWeekStart(weekStart);\n const data = getLocaleData(locale);\n return weekStart === \"monday\" ? data.weekdaysMonday : data.weekdays;\n}\n\nexport function getMonthName(locale: Locale, month: number): string {\n assertValidMonth(month);\n const data = getLocaleData(locale);\n return data.months[month - 1]!;\n}\n","import { getLocaleData, getMonthName } from \"./locale.ts\";\nimport type { Locale, WeekStart } from \"./types.ts\";\nimport {\n assertValidDate,\n assertValidWeekStart,\n createDate,\n} from \"./validation.ts\";\n\n// ─── 日付演算 ─────────────────────────────────────────────\n\n/** 加算量が整数であることを検証する */\nfunction assertAmount(amount: number): void {\n if (!Number.isInteger(amount)) {\n throw new RangeError(`Invalid amount: ${amount} (expected an integer)`);\n }\n}\n\n/**\n * 日付に日数を加算する(負数で減算)。時刻は保持される。\n * `setDate` ベースの暦日加算のため DST 遷移でも 1 日ずれない。\n * 入力 Date は変更されず、新しい Date を返す。\n */\nexport function addDays(date: Date, amount: number): Date {\n assertValidDate(date);\n assertAmount(amount);\n const result = new Date(date.getTime());\n result.setDate(result.getDate() + amount);\n return result;\n}\n\n/** 日付に週数を加算する(負数で減算)。addDays(date, amount * 7) と同じ */\nexport function addWeeks(date: Date, amount: number): Date {\n return addDays(date, amount * 7);\n}\n\n/**\n * 日付に月数を加算する(負数で減算)。時刻は保持される。\n * 月中旬の日付は月を跨いでも同じ日付を保つ(例: 1月15日 + 1ヶ月 = 2月15日)。\n * 移動先の月に存在しない日付は月末に丸められる\n * (例: 1月31日 + 1ヶ月 = 2月28日/29日、1月30日 + 1ヶ月 = 2月28日/29日)。\n */\nexport function addMonths(date: Date, amount: number): Date {\n assertValidDate(date);\n assertAmount(amount);\n const result = startOfDay(date);\n const targetDay = date.getDate();\n result.setDate(1);\n result.setMonth(result.getMonth() + amount);\n const lastDay = daysInMonthOf(result);\n result.setDate(Math.min(targetDay, lastDay));\n // 時刻を復元する\n result.setHours(\n date.getHours(),\n date.getMinutes(),\n date.getSeconds(),\n date.getMilliseconds(),\n );\n return result;\n}\n\n/** 日付に年数を加算する(負数で減算)。うるう日の 2月29日は 2月28日に丸められる */\nexport function addYears(date: Date, amount: number): Date {\n return addMonths(date, amount * 12);\n}\n\n/** 月の日数(1-31)を返す(Date 基準) */\nfunction daysInMonthOf(date: Date): number {\n return new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate();\n}\n\n// ─── 期間の境界 ───────────────────────────────────────────\n\n/** その日の 00:00:00.000 を返す */\nexport function startOfDay(date: Date): Date {\n assertValidDate(date);\n return createDate(date.getFullYear(), date.getMonth(), date.getDate());\n}\n\n/** その日の 23:59:59.999 を返す */\nexport function endOfDay(date: Date): Date {\n const result = startOfDay(date);\n result.setHours(23, 59, 59, 999);\n return result;\n}\n\n/** 日付を含む週の初日(weekStart 曜日)の 00:00:00.000 を返す */\nexport function startOfWeek(date: Date, weekStart: WeekStart = \"sunday\"): Date {\n assertValidDate(date);\n assertValidWeekStart(weekStart);\n const day = startOfDay(date);\n const offset = weekStart === \"sunday\" ? day.getDay() : (day.getDay() + 6) % 7;\n return addDays(day, -offset);\n}\n\n/** 日付を含む週の最終日の 23:59:59.999 を返す(週末を含む範囲に便利) */\nexport function endOfWeek(date: Date, weekStart: WeekStart = \"sunday\"): Date {\n return endOfDay(addDays(startOfWeek(date, weekStart), 6));\n}\n\n/** 日付を含む月の初日の 00:00:00.000 を返す */\nexport function startOfMonth(date: Date): Date {\n assertValidDate(date);\n return createDate(date.getFullYear(), date.getMonth(), 1);\n}\n\n/** 日付を含む月の最終日の 23:59:59.999 を返す */\nexport function endOfMonth(date: Date): Date {\n return endOfDay(createDate(date.getFullYear(), date.getMonth() + 1, 0));\n}\n\n/** 日付を含む年の初日(1月1日)の 00:00:00.000 を返す */\nexport function startOfYear(date: Date): Date {\n assertValidDate(date);\n return createDate(date.getFullYear(), 0, 1);\n}\n\n/** 日付を含む年の最終日の 23:59:59.999 を返す */\nexport function endOfYear(date: Date): Date {\n return endOfDay(createDate(date.getFullYear(), 12, 0));\n}\n\n// ─── 差(暦日ベース) ─────────────────────────────────────\n\n/** 日付の「日」部分を UTC 日数(epoch からの日数)に正規化する。DST や year 0-99 の影響を受けない */\nfunction toUtcDays(date: Date): number {\n const utc = new Date(0);\n utc.setUTCFullYear(date.getFullYear(), date.getMonth(), date.getDate());\n return utc.getTime() / 86_400_000;\n}\n\n/**\n * 2つの日付の間の暦日数(to - from)を返す。マイナスもありうる。\n * 時刻は無視され、DST 遷移があっても 1 日単位の差は正しい。\n */\nexport function diffInCalendarDays(from: Date, to: Date): number {\n assertValidDate(from);\n assertValidDate(to);\n return toUtcDays(to) - toUtcDays(from);\n}\n\n/** 2つの日付の間の暦月数(to - from)を返す。マイナスもありうる */\nexport function diffInCalendarMonths(from: Date, to: Date): number {\n assertValidDate(from);\n assertValidDate(to);\n return (\n (to.getFullYear() - from.getFullYear()) * 12 +\n (to.getMonth() - from.getMonth())\n );\n}\n\n/** 2つの日付の間の暦年数(to - from)を返す。マイナスもありうる */\nexport function diffInCalendarYears(from: Date, to: Date): number {\n assertValidDate(from);\n assertValidDate(to);\n return to.getFullYear() - from.getFullYear();\n}\n\n// ─── 比較 ─────────────────────────────────────────────────\n\n/** date が other より前(厳密に時刻が小さい)か */\nexport function isBefore(date: Date, other: Date): boolean {\n assertValidDate(date);\n assertValidDate(other);\n return date.getTime() < other.getTime();\n}\n\n/** date が other より後(厳密に時刻が大きい)か */\nexport function isAfter(date: Date, other: Date): boolean {\n assertValidDate(date);\n assertValidDate(other);\n return date.getTime() > other.getTime();\n}\n\n/** 同じ年月か(日は無視) */\nexport function isSameMonth(a: Date, b: Date): boolean {\n assertValidDate(a);\n assertValidDate(b);\n return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth();\n}\n\n/** 同じ年か(月・日は無視) */\nexport function isSameYear(a: Date, b: Date): boolean {\n assertValidDate(a);\n assertValidDate(b);\n return a.getFullYear() === b.getFullYear();\n}\n\n/** 週末(土曜 or 日曜)か */\nexport function isWeekend(date: Date): boolean {\n assertValidDate(date);\n const day = date.getDay();\n return day === 0 || day === 6;\n}\n\n// ─── 年・週の位置 ─────────────────────────────────────────\n\n/** ISO 8601 の週番号(1-53)を返す。第1週は最初の木曜日を含む週 */\nexport function getISOWeek(date: Date): number {\n assertValidDate(date);\n const day = startOfDay(date);\n const weekday = (day.getDay() + 6) % 7; // 月=0 ... 日=6\n // 今週の木曜日(ISO 年の基準。月曜〜日曜のどれを取っても同じ週番号になる)\n const thursday = addDays(day, 3 - weekday);\n const jan1 = createDate(thursday.getFullYear(), 0, 1);\n const jan1Weekday = (jan1.getDay() + 6) % 7;\n const firstThursday = addDays(jan1, (3 - jan1Weekday + 7) % 7);\n return Math.floor(diffInCalendarDays(firstThursday, thursday) / 7) + 1;\n}\n\n/**\n * 年始(1月1日)を含む週を第1週とする週番号を返す。\n * 1月1日より前の週の末日(例: 日曜始まりの 1月1日が土曜のとき)は前年の第52週/第53週になる。\n * 北米のカレンダー(cal -w 相当)で使われる規則。\n */\nexport function getWeekOfYear(\n date: Date,\n weekStart: WeekStart = \"sunday\",\n): number {\n assertValidDate(date);\n assertValidWeekStart(weekStart);\n const day = startOfDay(date);\n const jan1 = createDate(day.getFullYear(), 0, 1);\n const weekStartJan1 = startOfWeek(jan1, weekStart);\n return Math.floor(diffInCalendarDays(weekStartJan1, day) / 7) + 1;\n}\n\n/** 年の通算日(1月1日 = 1、12月31日 = 365/366)を返す */\nexport function getDayOfYear(date: Date): number {\n assertValidDate(date);\n return diffInCalendarDays(startOfYear(date), date) + 1;\n}\n\n// ─── その他 ───────────────────────────────────────────────\n\n/** 日付を [min, max] の範囲内にクランプする。範囲外なら min/max を、範囲内なら元の Date を返す */\nexport function clampDate(date: Date, min: Date, max: Date): Date {\n assertValidDate(date);\n assertValidDate(min);\n assertValidDate(max);\n if (date.getTime() < min.getTime()) return min;\n if (date.getTime() > max.getTime()) return max;\n return date;\n}\n\nconst TOKEN_RE = /yyyy|MMMM|EEE|yy|MM|dd|M|d/g;\n\n/**\n * パターン文字列に従って日付をフォーマットする。\n *\n * 対応トークン:\n * - `yyyy` — 4桁の年(例: 2026)\n * - `yy` — 西暦下2桁(例: 26)\n * - `MMMM` — フル月名(ロケール依存。例: September / 9月)\n * - `MM` — 0埋め2桁の月(01-12)\n * - `M` — 月(1-12)\n * - `dd` — 0埋め2桁の日(01-31)\n * - `d` — 日(1-31)\n * - `EEE` — 曜日の短縮名(ロケール依存。例: Fri / 金)\n *\n * トークン以外の文字はそのまま出力される。\n *\n * ```ts\n * formatDate(date, \"yyyy-MM-dd\"); // \"2026-09-25\"\n * formatDate(date, \"MMMM d, yyyy (EEE)\"); // \"September 25, 2026 (Fri)\"\n * formatDate(date, \"yyyy年M月d日\", \"ja\"); // \"2026年9月25日\"\n * ```\n */\nexport function formatDate(\n date: Date,\n pattern: string,\n locale: Locale = \"en\",\n): string {\n assertValidDate(date);\n const data = getLocaleData(locale);\n return pattern.replace(TOKEN_RE, (token) => {\n switch (token) {\n case \"yyyy\":\n return String(date.getFullYear()).padStart(4, \"0\");\n case \"yy\":\n return String(date.getFullYear() % 100).padStart(2, \"0\");\n case \"MMMM\":\n return getMonthName(locale, date.getMonth() + 1);\n case \"MM\":\n return String(date.getMonth() + 1).padStart(2, \"0\");\n case \"M\":\n return String(date.getMonth() + 1);\n case \"dd\":\n return String(date.getDate()).padStart(2, \"0\");\n case \"d\":\n return String(date.getDate());\n case \"EEE\":\n return data.weekdays[date.getDay()]!;\n default:\n return token;\n }\n });\n}\n","import { addDays } from \"./date-math.ts\";\nimport type { Locale } from \"./types.ts\";\nimport { assertValidDate, createDate } from \"./validation.ts\";\n\n// ─── 日本の祝日 ───────────────────────────────────────────\n\n/**\n * 祝日データを持つロケール。現在は日本語(日本の国民の祝日)のみ。\n * その他のロケールは「祝日なし」として扱われる(isHoliday は常に false)。\n */\nexport type HolidayLocale = \"ja\";\n\n/** 祝日が計算できる年範囲(1949 年以降の現行祝日法制に基づく) */\nexport const HOLIDAY_MIN_YEAR = 1949;\n\n/** 祝日が計算できる年範囲(秋分の日の近似式が有効な上限。実用上十分) */\nexport const HOLIDAY_MAX_YEAR = 2100;\n\n/** 1回限りの祝日(皇室行事・改元に伴う法律で定められたもの): \"YYYY-MM-DD\" → 名称 */\nconst ONE_OFF_HOLIDAYS: Readonly<Record<string, string>> = {\n \"1959-04-10\": \"皇太子明仁親王の結婚の儀\",\n \"1989-02-24\": \"昭和天皇の大喪の礼\",\n \"1990-11-12\": \"即位の礼正殿の儀\",\n \"1993-06-09\": \"皇太子徳仁親王の結婚の儀\",\n \"2019-05-01\": \"天皇即位の日\",\n \"2019-10-22\": \"即位礼正殿の儀\",\n};\n\n/** 年の祝日一覧の1件(month は 1-12) */\ninterface YearHoliday {\n month: number;\n day: number;\n name: string;\n}\n\n/** 年月日の曜日(0=日曜) */\nfunction dayOfWeek(year: number, month: number, day: number): number {\n return createDate(year, month - 1, day).getDay();\n}\n\n/**\n * 国民の祝日に関する法律と特例法に基づき、年の祝日一覧を規則から算出する。\n *\n * 計算順: ①祝日(固定日・第n月曜・春分/秋分)→ ②特例の祝日 → ③振替休日\n * (1973年以降、祝日が日曜のとき直後の祝日でない日)→ ④国民の休日\n * (1986年以降、祝日(日曜を除く)に挟まれた平日)。\n * 祝日の名称は「元日」「成人の日」など法律上の名称、「振替休日」「国民の休日」はそのままの名称。\n * 2020/2021 年の東京五輪特例(海の日・山の日・スポーツの日の振替)も反映する。\n * 秋分の日・春分の日は天文学的な秋分/春分の日付(1851〜2099 年で有効な近似式)で算出する。\n */\nfunction holidaysOfYear(year: number): YearHoliday[] {\n const list: YearHoliday[] = [];\n const add = (month: number, day: number, name: string): void => {\n list.push({ month, day, name });\n };\n /** 指定月の第 n 曜日(weekday: 0=日曜 .. 6=土曜)の日付を返す */\n const nthWeekday = (weekday: number, n: number, month: number): number => {\n const first = createDate(year, month - 1, 1);\n const offset = (weekday - first.getDay() + 7) % 7;\n return 1 + offset + (n - 1) * 7;\n };\n const monday = (n: number, month: number): number => nthWeekday(1, n, month);\n const springEquinox = Math.floor(\n 20.8431 + 0.242194 * (year - 1980) - Math.floor((year - 1980) / 4),\n );\n const fallEquinox = Math.floor(\n 23.2488 + 0.242194 * (year - 1980) - Math.floor((year - 1980) / 4),\n );\n\n // ── ① 国民の祝日(法律上の規則) ──\n if (year >= 1949) add(1, 1, \"元日\");\n if (year >= 1949) {\n // 成人の日: 2000年以降は1月第2月曜\n add(1, year <= 1999 ? 15 : monday(2, 1), \"成人の日\");\n }\n if (year >= 1967) add(2, 11, \"建国記念の日\");\n if (year >= 1949) {\n // 天皇誕生日: 4/29(〜1988)→ 12/23(1989-2018)→ 2019年はなし → 2/23(2020-)\n if (year <= 1988) {\n add(4, 29, \"天皇誕生日\");\n } else if (year <= 2018) {\n add(12, 23, \"天皇誕生日\");\n } else if (year >= 2020) {\n add(2, 23, \"天皇誕生日\");\n }\n }\n if (year >= 2007) add(4, 29, \"昭和の日\");\n if (year >= 1949) add(5, 3, \"憲法記念日\");\n if (year >= 1989 && year <= 2006) add(4, 29, \"みどりの日\");\n if (year >= 2007) add(5, 4, \"みどりの日\");\n if (year >= 1949) add(5, 5, \"こどもの日\");\n if (year >= 1996) {\n // 海の日: 7/20(〜2002)→ 第3月曜(2003-)。2020/2021 は東京五輪特例\n if (year <= 2002) {\n add(7, 20, \"海の日\");\n } else if (year === 2020) {\n add(7, 23, \"海の日\");\n } else if (year === 2021) {\n add(7, 22, \"海の日\");\n } else {\n add(7, monday(3, 7), \"海の日\");\n }\n }\n if (year >= 2016) {\n // 山の日: 8/11。2020/2021 は東京五輪特例\n if (year === 2020) {\n add(8, 10, \"山の日\");\n } else if (year === 2021) {\n add(8, 8, \"山の日\");\n } else {\n add(8, 11, \"山の日\");\n }\n }\n if (year >= 1949) add(3, springEquinox, \"春分の日\");\n if (year >= 1966) {\n // 敬老の日: 9/15(〜2002)→ 第3月曜(2003-)\n add(9, year <= 2002 ? 15 : monday(3, 9), \"敬老の日\");\n }\n if (year >= 1949) add(9, fallEquinox, \"秋分の日\");\n if (year >= 1966) {\n // 体育の日: 10/10(〜1999)→ 第2月曜(2000-2019)→ スポーツの日(2020-)。\n // 2020/2021 は東京五輪特例\n if (year <= 1999) {\n add(10, 10, \"体育の日\");\n } else if (year <= 2019) {\n add(10, monday(2, 10), \"体育の日\");\n } else if (year === 2020) {\n add(7, 24, \"スポーツの日\");\n } else if (year === 2021) {\n add(7, 23, \"スポーツの日\");\n } else {\n add(10, monday(2, 10), \"スポーツの日\");\n }\n }\n if (year >= 1949) add(11, 3, \"文化の日\");\n if (year >= 1949) add(11, 23, \"勤労感謝の日\");\n\n // ── ② 特例の祝日 ──\n for (const [key, name] of Object.entries(ONE_OFF_HOLIDAYS)) {\n const [y, m, d] = key.split(\"-\").map(Number);\n if (y === year) add(m! as number, d! as number, name);\n }\n\n const inList = (month: number, day: number): boolean =>\n list.some((h) => h.month === month && h.day === day);\n\n // ── ③ 振替休日(1973年の法改正により同年4月12日から施行): 祝日が日曜に当たるとき、直後の祝日でない日を休日とする ──\n if (year >= 1973) {\n const substituteFrom = createDate(1973, 3, 12).getTime(); // 制度施行日 1973-04-12\n for (const h of [...list]) {\n if (dayOfWeek(year, h.month, h.day) !== 0) continue;\n const base = createDate(year, h.month - 1, h.day);\n if (base.getTime() < substituteFrom) continue;\n for (let i = 1; i <= 7; i++) {\n const next = addDays(base, i);\n if (!inList(next.getMonth() + 1, next.getDate())) {\n add(next.getMonth() + 1, next.getDate(), \"振替休日\");\n break;\n }\n }\n }\n }\n\n // ── ④ 国民の休日(1986年の法改正以降): 祝日(日曜を除く)に挟まれた平日を休日とする ──\n if (year >= 1986) {\n for (let month = 1; month <= 12; month++) {\n const days = createDate(year, month, 0).getDate();\n for (let day = 1; day <= days; day++) {\n if (inList(month, day)) continue;\n const date = createDate(year, month - 1, day);\n if (date.getDay() === 0) continue;\n const prev = addDays(date, -1);\n const next = addDays(date, 1);\n if (\n inList(prev.getMonth() + 1, prev.getDate()) &&\n inList(next.getMonth() + 1, next.getDate())\n ) {\n add(month, day, \"国民の休日\");\n }\n }\n }\n }\n\n return list;\n}\n\n/** 年の計算結果キャッシュ(同じ年を何度も参照する描画用途のため) */\nconst holidayCache = new Map<number, YearHoliday[]>();\n\n/** 祝日一覧を取得する。対象外ロケール・範囲外の年は null */\nfunction holidaysOf(date: Date, locale: Locale): YearHoliday[] | null {\n if (locale !== \"ja\") return null;\n const year = date.getFullYear();\n if (year < HOLIDAY_MIN_YEAR || year > HOLIDAY_MAX_YEAR) return null;\n const cached = holidayCache.get(year);\n if (cached !== undefined) return cached;\n const list = holidaysOfYear(year);\n holidayCache.set(year, list);\n return list;\n}\n\n/** 日付が祝日(日本の国民の祝日・振替休日・国民の休日)か判定する。対象外ロケール/年は false */\nexport function isHoliday(date: Date, locale: Locale = \"ja\"): boolean {\n assertValidDate(date);\n const list = holidaysOf(date, locale);\n if (list === null) return false;\n return list.some(\n (h) => h.month === date.getMonth() + 1 && h.day === date.getDate(),\n );\n}\n\n/** 日付の祝日名を返す。祝日でない・対象外ロケール/年は undefined */\nexport function getHolidayName(\n date: Date,\n locale: Locale = \"ja\",\n): string | undefined {\n assertValidDate(date);\n const list = holidaysOf(date, locale);\n if (list === null) return undefined;\n return list.find(\n (h) => h.month === date.getMonth() + 1 && h.day === date.getDate(),\n )?.name;\n}\n\n// ─── 営業日 ───────────────────────────────────────────────\n\n/** 日付が営業日(平日かつ祝日でない)か判定する */\nexport function isBusinessDay(date: Date, locale: Locale = \"ja\"): boolean {\n assertValidDate(date);\n if (date.getDay() === 0 || date.getDay() === 6) return false;\n return !isHoliday(date, locale);\n}\n\n/** 加算する営業日数が整数であることを検証する */\nfunction assertBusinessAmount(amount: number): void {\n if (!Number.isInteger(amount)) {\n throw new RangeError(`Invalid amount: ${amount} (expected an integer)`);\n }\n}\n\n/**\n * 日付に営業日数を加算する(負数で減算)。土日・祝日はスキップされる。\n * 加算の起点は date そのもの(date 自体は数えない)。date === 戻り値になるのは amount = 0 のとき。\n * 例: 2026-05-01(金)に 1 を足すと 2026-05-07(木)になる(5/3-5/6 が祝日)。\n */\nexport function addBusinessDays(\n date: Date,\n amount: number,\n locale: Locale = \"ja\",\n): Date {\n assertValidDate(date);\n assertBusinessAmount(amount);\n const result = new Date(date.getTime());\n const step = amount >= 0 ? 1 : -1;\n let remaining = Math.abs(amount);\n while (remaining > 0) {\n result.setDate(result.getDate() + step);\n if (isBusinessDay(result, locale)) remaining--;\n }\n return result;\n}\n\n/**\n * 2つの日付の間の営業日数(to - from 方向)を返す。マイナスもありうる。\n * from 自身は数えず、to は数える。例: 月曜→火曜 = 1、金曜→翌月曜 = 1(土日はスキップ)。\n * `addBusinessDays(from, n) === to` と `diffInBusinessDays(from, to) === n` は同値。\n */\nexport function diffInBusinessDays(\n from: Date,\n to: Date,\n locale: Locale = \"ja\",\n): number {\n assertValidDate(from);\n assertValidDate(to);\n const sign = to.getTime() >= from.getTime() ? 1 : -1;\n const cursor = new Date(from.getTime());\n let count = 0;\n for (;;) {\n cursor.setDate(cursor.getDate() + sign);\n if (\n sign > 0\n ? cursor.getTime() > to.getTime()\n : cursor.getTime() < to.getTime()\n ) {\n break;\n }\n if (isBusinessDay(cursor, locale)) count++;\n }\n return count * sign;\n}\n","import { isHoliday } from \"./holidays.ts\";\nimport type { Locale, WeekStart } from \"./types.ts\";\nimport {\n assertValidDate,\n assertValidWeekStart,\n assertValidYear,\n assertValidYearMonth,\n createDate,\n} from \"./validation.ts\";\n\nexport interface CalendarCellState {\n isWeekend: boolean;\n /** 祝日かどうか(holidayLocale に従って判定。指定なしは \"ja\") */\n isHoliday: boolean;\n isToday: boolean;\n isHighlight: boolean;\n isInRange: boolean;\n isDisabled: boolean;\n}\n\n/** 日付範囲(from <= to) */\nexport interface DateRange {\n from: Date;\n to: Date;\n}\n\n/**\n * 2つの日付を from <= to の順にソートした範囲を返す。\n * どちらかが null なら undefined(範囲なし)。\n */\nexport function sortRange(\n a: Date | null,\n b: Date | null,\n): DateRange | undefined {\n if (a === null || b === null) return undefined;\n return a.getTime() <= b.getTime() ? { from: a, to: b } : { from: b, to: a };\n}\n\n/** 月初日(1日)を返す */\nexport function firstDayOfMonth(year: number, month: number): Date {\n assertValidYearMonth(year, month);\n return createDate(year, month - 1, 1);\n}\n\n/** 月末日を返す */\nexport function lastDayOfMonth(year: number, month: number): Date {\n assertValidYearMonth(year, month);\n return createDate(year, month, 0);\n}\n\n/**\n * 月の日付グリッドを生成する(6行×7列)\n * 各セルは日数(1-31)または null(空欄)\n */\nexport function buildMonthGrid(\n year: number,\n month: number,\n weekStart: WeekStart,\n): (number | null)[][] {\n assertValidYearMonth(year, month);\n assertValidWeekStart(weekStart);\n\n const daysInMonth = lastDayOfMonth(year, month).getDate();\n let skip = firstDayOfMonth(year, month).getDay();\n if (weekStart === \"monday\") {\n skip = (skip + 6) % 7;\n }\n\n const grid: (number | null)[][] = [];\n let day = 1;\n for (let week = 0; week < 6; week++) {\n const row: (number | null)[] = [];\n for (let col = 0; col < 7; col++) {\n if (day > daysInMonth || (week === 0 && col < skip)) {\n row.push(null);\n } else {\n row.push(day++);\n }\n }\n grid.push(row);\n }\n return grid;\n}\n\n/** 範囲(from/to)が有効であることを検証する */\nfunction assertValidRange(from: Date, to: Date): void {\n assertValidDate(from);\n assertValidDate(to);\n if (from.getTime() > to.getTime()) {\n throw new RangeError(\"Invalid range: from must not be after to\");\n }\n}\n\n/** 日付が範囲内に含まれるか */\nexport function isDateInRange(\n date: Date,\n range?: { from: Date; to: Date },\n): boolean {\n if (!range) return false;\n assertValidRange(range.from, range.to);\n assertValidDate(date);\n const time = date.getTime();\n return time >= range.from.getTime() && time <= range.to.getTime();\n}\n\n/** 日付が今日と一致するか(日付のみ比較) */\nexport function isSameDay(a: Date, b: Date): boolean {\n assertValidDate(a);\n assertValidDate(b);\n return (\n a.getFullYear() === b.getFullYear() &&\n a.getMonth() === b.getMonth() &&\n a.getDate() === b.getDate()\n );\n}\n\n/** 日付セルの表示状態を計算する */\nexport function getCalendarCellState(\n date: Date,\n options: {\n today?: Date;\n highlight?: Date;\n range?: { from: Date; to: Date };\n isDateDisabled?: (date: Date) => boolean;\n /** 祝日判定に使うロケール。省略時は \"ja\"(isHoliday のデフォルト) */\n holidayLocale?: Locale;\n } = {},\n): CalendarCellState {\n assertValidDate(date);\n return {\n isWeekend: date.getDay() === 0 || date.getDay() === 6,\n isHoliday: isHoliday(date, options.holidayLocale),\n isToday: options.today !== undefined && isSameDay(date, options.today),\n isHighlight:\n options.highlight !== undefined && isSameDay(date, options.highlight),\n isInRange:\n options.range !== undefined && isDateInRange(date, options.range),\n isDisabled: options.isDateDisabled?.(date) ?? false,\n };\n}\n\n/** 日付が範囲の開始年から終了年までの月リストを返す */\nexport function getMonthRange(\n from: Date,\n to: Date,\n): { year: number; month: number }[] {\n assertValidRange(from, to);\n const start = from.getFullYear() * 12 + from.getMonth();\n const end = to.getFullYear() * 12 + to.getMonth();\n return Array.from({ length: end - start + 1 }, (_, i) => {\n const n = start + i;\n return { year: Math.floor(n / 12), month: (n % 12) + 1 };\n });\n}\n\n/** グレゴリオ暦のうるう年判定(4で割れるが100では割れない、または400で割れる) */\nexport function isLeapYear(year: number): boolean {\n assertValidYear(year);\n return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;\n}\n\n/** 月の日数(1-31)を返す */\nexport function daysInMonth(year: number, month: number): number {\n assertValidYearMonth(year, month);\n return lastDayOfMonth(year, month).getDate();\n}\n"],"mappings":";;AAGA,MAAa,WAAW;;AAExB,MAAa,WAAW;;AAGxB,SAAS,qBACP,MACA,OACA,KACA,KACM;CACN,IAAI,CAAC,OAAO,UAAU,KAAK,KAAK,QAAQ,OAAO,QAAQ,KACrD,MAAM,IAAI,WACR,WAAW,KAAK,IAAI,MAAM,gCAAgC,IAAI,OAAO,IAAI,EAC3E;AAEJ;;AAGA,SAAgB,gBAAgB,MAAoB;CAClD,qBAAqB,QAAQ,MAAA,GAAgB,QAAQ;AACvD;;AAGA,SAAgB,iBAAiB,OAAqB;CACpD,qBAAqB,SAAS,OAAO,GAAG,EAAE;AAC5C;;AAGA,SAAgB,qBAAqB,MAAc,OAAqB;CACtE,gBAAgB,IAAI;CACpB,iBAAiB,KAAK;AACxB;;AAGA,SAAgB,qBAAqB,WAAyB;CAC5D,IAAI,cAAc,YAAY,cAAc,UAC1C,MAAM,IAAI,WACR,uBAAuB,UAAU,kCACnC;AAEJ;;AAGA,SAAgB,gBAAgB,MAAkB;CAChD,IAAI,EAAE,gBAAgB,SAAS,OAAO,MAAM,KAAK,QAAQ,CAAC,GACxD,MAAM,IAAI,WAAW,iBAAiB,OAAO,IAAI,GAAG;AAExD;;;;;;;;;;;AAYA,SAAgB,WACd,MACA,YACA,KACM;CACN,gBAAgB,IAAI;CACpB,qBAAqB,cAAc,YAAY,GAAG,EAAE;CACpD,qBAAqB,OAAO,KAAK,GAAG,EAAE;CACtC,MAAM,uBAAO,IAAI,KAAK,CAAC;CACvB,KAAK,SAAS,GAAG,GAAG,GAAG,CAAC;CACxB,KAAK,YAAY,MAAM,YAAY,GAAG;CACtC,OAAO;AACT;;;;AC/DA,SAAS,WACP,QACA,UACA,gBAAmC,UACvB;CACZ,MAAM,UAAU,QAA2B,CAAC,GAAG,IAAI,MAAM,CAAC,GAAG,IAAI,EAAG;CACpE,OAAO;EACL;EACA;EACA;EACA,gBAAgB,OAAO,QAAQ;EAC/B,qBAAqB,OAAO,aAAa;CAC3C;AACF;AAEA,MAAa,UAAsC;CACjD,IAAI,WACF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,GACA;EAAC;EAAO;EAAO;EAAO;EAAO;EAAO;EAAO;CAAK,GAChD;EAAC;EAAM;EAAM;EAAM;EAAM;EAAM;EAAM;CAAI,CAC3C;CACA,IAAI,WACF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,GACA;EAAC;EAAK;EAAK;EAAK;EAAK;EAAK;EAAK;CAAG,CACpC;CACA,IAAI,WACF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,GACA;EAAC;EAAO;EAAO;EAAO;EAAO;EAAO;EAAO;CAAK,GAChD;EAAC;EAAM;EAAM;EAAM;EAAM;EAAM;EAAM;CAAI,CAC3C;CACA,IAAI,WACF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,GACA;EAAC;EAAM;EAAM;EAAM;EAAM;EAAM;EAAM;CAAI,CAC3C;CACA,IAAI,WACF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,GACA;EAAC;EAAQ;EAAQ;EAAQ;EAAQ;EAAQ;EAAQ;CAAM,GACvD;EAAC;EAAM;EAAM;EAAM;EAAM;EAAM;EAAM;CAAI,CAC3C;CACA,IAAI,WACF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,GACA;EAAC;EAAK;EAAK;EAAK;EAAK;EAAK;EAAK;CAAG,CACpC;CACA,IAAI,WACF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,GACA;EAAC;EAAK;EAAK;EAAK;EAAK;EAAK;EAAK;CAAG,CACpC;AACF;;AAGA,SAAgB,cAAc,QAA4B;CACxD,MAAM,OAAO,QAAQ;CACrB,IAAI,SAAS,KAAA,GACX,MAAM,IAAI,WAAW,oBAAoB,OAAO,EAAE;CAEpD,OAAO;AACT;AAEA,SAAgB,kBACd,QACA,WACmB;CACnB,qBAAqB,SAAS;CAC9B,MAAM,OAAO,cAAc,MAAM;CACjC,OAAO,cAAc,WAAW,KAAK,iBAAiB,KAAK;AAC7D;AAEA,SAAgB,aAAa,QAAgB,OAAuB;CAClE,iBAAiB,KAAK;CAEtB,OADa,cAAc,MACjB,CAAC,CAAC,OAAO,QAAQ;AAC7B;;;;ACnKA,SAAS,aAAa,QAAsB;CAC1C,IAAI,CAAC,OAAO,UAAU,MAAM,GAC1B,MAAM,IAAI,WAAW,mBAAmB,OAAO,uBAAuB;AAE1E;;;;;;AAOA,SAAgB,QAAQ,MAAY,QAAsB;CACxD,gBAAgB,IAAI;CACpB,aAAa,MAAM;CACnB,MAAM,SAAS,IAAI,KAAK,KAAK,QAAQ,CAAC;CACtC,OAAO,QAAQ,OAAO,QAAQ,IAAI,MAAM;CACxC,OAAO;AACT;;AAGA,SAAgB,SAAS,MAAY,QAAsB;CACzD,OAAO,QAAQ,MAAM,SAAS,CAAC;AACjC;;;;;;;AAQA,SAAgB,UAAU,MAAY,QAAsB;CAC1D,gBAAgB,IAAI;CACpB,aAAa,MAAM;CACnB,MAAM,SAAS,WAAW,IAAI;CAC9B,MAAM,YAAY,KAAK,QAAQ;CAC/B,OAAO,QAAQ,CAAC;CAChB,OAAO,SAAS,OAAO,SAAS,IAAI,MAAM;CAC1C,MAAM,UAAU,cAAc,MAAM;CACpC,OAAO,QAAQ,KAAK,IAAI,WAAW,OAAO,CAAC;CAE3C,OAAO,SACL,KAAK,SAAS,GACd,KAAK,WAAW,GAChB,KAAK,WAAW,GAChB,KAAK,gBAAgB,CACvB;CACA,OAAO;AACT;;AAGA,SAAgB,SAAS,MAAY,QAAsB;CACzD,OAAO,UAAU,MAAM,SAAS,EAAE;AACpC;;AAGA,SAAS,cAAc,MAAoB;CACzC,OAAO,IAAI,KAAK,KAAK,YAAY,GAAG,KAAK,SAAS,IAAI,GAAG,CAAC,CAAC,CAAC,QAAQ;AACtE;;AAKA,SAAgB,WAAW,MAAkB;CAC3C,gBAAgB,IAAI;CACpB,OAAO,WAAW,KAAK,YAAY,GAAG,KAAK,SAAS,GAAG,KAAK,QAAQ,CAAC;AACvE;;AAGA,SAAgB,SAAS,MAAkB;CACzC,MAAM,SAAS,WAAW,IAAI;CAC9B,OAAO,SAAS,IAAI,IAAI,IAAI,GAAG;CAC/B,OAAO;AACT;;AAGA,SAAgB,YAAY,MAAY,YAAuB,UAAgB;CAC7E,gBAAgB,IAAI;CACpB,qBAAqB,SAAS;CAC9B,MAAM,MAAM,WAAW,IAAI;CAE3B,OAAO,QAAQ,KAAK,EADL,cAAc,WAAW,IAAI,OAAO,KAAK,IAAI,OAAO,IAAI,KAAK,EACjD;AAC7B;;AAGA,SAAgB,UAAU,MAAY,YAAuB,UAAgB;CAC3E,OAAO,SAAS,QAAQ,YAAY,MAAM,SAAS,GAAG,CAAC,CAAC;AAC1D;;AAGA,SAAgB,aAAa,MAAkB;CAC7C,gBAAgB,IAAI;CACpB,OAAO,WAAW,KAAK,YAAY,GAAG,KAAK,SAAS,GAAG,CAAC;AAC1D;;AAGA,SAAgB,WAAW,MAAkB;CAC3C,OAAO,SAAS,WAAW,KAAK,YAAY,GAAG,KAAK,SAAS,IAAI,GAAG,CAAC,CAAC;AACxE;;AAGA,SAAgB,YAAY,MAAkB;CAC5C,gBAAgB,IAAI;CACpB,OAAO,WAAW,KAAK,YAAY,GAAG,GAAG,CAAC;AAC5C;;AAGA,SAAgB,UAAU,MAAkB;CAC1C,OAAO,SAAS,WAAW,KAAK,YAAY,GAAG,IAAI,CAAC,CAAC;AACvD;;AAKA,SAAS,UAAU,MAAoB;CACrC,MAAM,sBAAM,IAAI,KAAK,CAAC;CACtB,IAAI,eAAe,KAAK,YAAY,GAAG,KAAK,SAAS,GAAG,KAAK,QAAQ,CAAC;CACtE,OAAO,IAAI,QAAQ,IAAI;AACzB;;;;;AAMA,SAAgB,mBAAmB,MAAY,IAAkB;CAC/D,gBAAgB,IAAI;CACpB,gBAAgB,EAAE;CAClB,OAAO,UAAU,EAAE,IAAI,UAAU,IAAI;AACvC;;AAGA,SAAgB,qBAAqB,MAAY,IAAkB;CACjE,gBAAgB,IAAI;CACpB,gBAAgB,EAAE;CAClB,QACG,GAAG,YAAY,IAAI,KAAK,YAAY,KAAK,MACzC,GAAG,SAAS,IAAI,KAAK,SAAS;AAEnC;;AAGA,SAAgB,oBAAoB,MAAY,IAAkB;CAChE,gBAAgB,IAAI;CACpB,gBAAgB,EAAE;CAClB,OAAO,GAAG,YAAY,IAAI,KAAK,YAAY;AAC7C;;AAKA,SAAgB,SAAS,MAAY,OAAsB;CACzD,gBAAgB,IAAI;CACpB,gBAAgB,KAAK;CACrB,OAAO,KAAK,QAAQ,IAAI,MAAM,QAAQ;AACxC;;AAGA,SAAgB,QAAQ,MAAY,OAAsB;CACxD,gBAAgB,IAAI;CACpB,gBAAgB,KAAK;CACrB,OAAO,KAAK,QAAQ,IAAI,MAAM,QAAQ;AACxC;;AAGA,SAAgB,YAAY,GAAS,GAAkB;CACrD,gBAAgB,CAAC;CACjB,gBAAgB,CAAC;CACjB,OAAO,EAAE,YAAY,MAAM,EAAE,YAAY,KAAK,EAAE,SAAS,MAAM,EAAE,SAAS;AAC5E;;AAGA,SAAgB,WAAW,GAAS,GAAkB;CACpD,gBAAgB,CAAC;CACjB,gBAAgB,CAAC;CACjB,OAAO,EAAE,YAAY,MAAM,EAAE,YAAY;AAC3C;;AAGA,SAAgB,UAAU,MAAqB;CAC7C,gBAAgB,IAAI;CACpB,MAAM,MAAM,KAAK,OAAO;CACxB,OAAO,QAAQ,KAAK,QAAQ;AAC9B;;AAKA,SAAgB,WAAW,MAAoB;CAC7C,gBAAgB,IAAI;CACpB,MAAM,MAAM,WAAW,IAAI;CAG3B,MAAM,WAAW,QAAQ,KAAK,KAFb,IAAI,OAAO,IAAI,KAAK,CAEI;CACzC,MAAM,OAAO,WAAW,SAAS,YAAY,GAAG,GAAG,CAAC;CAEpD,MAAM,gBAAgB,QAAQ,OAAO,KADhB,KAAK,OAAO,IAAI,KAAK,IACa,KAAK,CAAC;CAC7D,OAAO,KAAK,MAAM,mBAAmB,eAAe,QAAQ,IAAI,CAAC,IAAI;AACvE;;;;;;AAOA,SAAgB,cACd,MACA,YAAuB,UACf;CACR,gBAAgB,IAAI;CACpB,qBAAqB,SAAS;CAC9B,MAAM,MAAM,WAAW,IAAI;CAE3B,MAAM,gBAAgB,YADT,WAAW,IAAI,YAAY,GAAG,GAAG,CACT,GAAG,SAAS;CACjD,OAAO,KAAK,MAAM,mBAAmB,eAAe,GAAG,IAAI,CAAC,IAAI;AAClE;;AAGA,SAAgB,aAAa,MAAoB;CAC/C,gBAAgB,IAAI;CACpB,OAAO,mBAAmB,YAAY,IAAI,GAAG,IAAI,IAAI;AACvD;;AAKA,SAAgB,UAAU,MAAY,KAAW,KAAiB;CAChE,gBAAgB,IAAI;CACpB,gBAAgB,GAAG;CACnB,gBAAgB,GAAG;CACnB,IAAI,KAAK,QAAQ,IAAI,IAAI,QAAQ,GAAG,OAAO;CAC3C,IAAI,KAAK,QAAQ,IAAI,IAAI,QAAQ,GAAG,OAAO;CAC3C,OAAO;AACT;AAEA,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;AAuBjB,SAAgB,WACd,MACA,SACA,SAAiB,MACT;CACR,gBAAgB,IAAI;CACpB,MAAM,OAAO,cAAc,MAAM;CACjC,OAAO,QAAQ,QAAQ,WAAW,UAAU;EAC1C,QAAQ,OAAR;GACE,KAAK,QACH,OAAO,OAAO,KAAK,YAAY,CAAC,CAAC,CAAC,SAAS,GAAG,GAAG;GACnD,KAAK,MACH,OAAO,OAAO,KAAK,YAAY,IAAI,GAAG,CAAC,CAAC,SAAS,GAAG,GAAG;GACzD,KAAK,QACH,OAAO,aAAa,QAAQ,KAAK,SAAS,IAAI,CAAC;GACjD,KAAK,MACH,OAAO,OAAO,KAAK,SAAS,IAAI,CAAC,CAAC,CAAC,SAAS,GAAG,GAAG;GACpD,KAAK,KACH,OAAO,OAAO,KAAK,SAAS,IAAI,CAAC;GACnC,KAAK,MACH,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,GAAG,GAAG;GAC/C,KAAK,KACH,OAAO,OAAO,KAAK,QAAQ,CAAC;GAC9B,KAAK,OACH,OAAO,KAAK,SAAS,KAAK,OAAO;GACnC,SACE,OAAO;EACX;CACF,CAAC;AACH;;;;AC3RA,MAAa,mBAAmB;;AAGhC,MAAa,mBAAmB;;AAGhC,MAAM,mBAAqD;CACzD,cAAc;CACd,cAAc;CACd,cAAc;CACd,cAAc;CACd,cAAc;CACd,cAAc;AAChB;;AAUA,SAAS,UAAU,MAAc,OAAe,KAAqB;CACnE,OAAO,WAAW,MAAM,QAAQ,GAAG,GAAG,CAAC,CAAC,OAAO;AACjD;;;;;;;;;;;AAYA,SAAS,eAAe,MAA6B;CACnD,MAAM,OAAsB,CAAC;CAC7B,MAAM,OAAO,OAAe,KAAa,SAAuB;EAC9D,KAAK,KAAK;GAAE;GAAO;GAAK;EAAK,CAAC;CAChC;;CAEA,MAAM,cAAc,SAAiB,GAAW,UAA0B;EAGxE,OAAO,KADS,UADF,WAAW,MAAM,QAAQ,GAAG,CACZ,CAAC,CAAC,OAAO,IAAI,KAAK,KAC3B,IAAI,KAAK;CAChC;CACA,MAAM,UAAU,GAAW,UAA0B,WAAW,GAAG,GAAG,KAAK;CAC3E,MAAM,gBAAgB,KAAK,MACzB,UAAU,WAAY,OAAO,QAAQ,KAAK,OAAO,OAAO,QAAQ,CAAC,CACnE;CACA,MAAM,cAAc,KAAK,MACvB,UAAU,WAAY,OAAO,QAAQ,KAAK,OAAO,OAAO,QAAQ,CAAC,CACnE;CAGA,IAAI,QAAQ,MAAM,IAAI,GAAG,GAAG,IAAI;CAChC,IAAI,QAAQ,MAEV,IAAI,GAAG,QAAQ,OAAO,KAAK,OAAO,GAAG,CAAC,GAAG,MAAM;CAEjD,IAAI,QAAQ,MAAM,IAAI,GAAG,IAAI,QAAQ;CACrC,IAAI,QAAQ,MAAM;EAEhB,IAAI,QAAQ,MACV,IAAI,GAAG,IAAI,OAAO;OACb,IAAI,QAAQ,MACjB,IAAI,IAAI,IAAI,OAAO;OACd,IAAI,QAAQ,MACjB,IAAI,GAAG,IAAI,OAAO;CAEtB;CACA,IAAI,QAAQ,MAAM,IAAI,GAAG,IAAI,MAAM;CACnC,IAAI,QAAQ,MAAM,IAAI,GAAG,GAAG,OAAO;CACnC,IAAI,QAAQ,QAAQ,QAAQ,MAAM,IAAI,GAAG,IAAI,OAAO;CACpD,IAAI,QAAQ,MAAM,IAAI,GAAG,GAAG,OAAO;CACnC,IAAI,QAAQ,MAAM,IAAI,GAAG,GAAG,OAAO;CACnC,IAAI,QAAQ,MAAM;EAEhB,IAAI,QAAQ,MACV,IAAI,GAAG,IAAI,KAAK;OACX,IAAI,SAAS,MAClB,IAAI,GAAG,IAAI,KAAK;OACX,IAAI,SAAS,MAClB,IAAI,GAAG,IAAI,KAAK;OAEhB,IAAI,GAAG,OAAO,GAAG,CAAC,GAAG,KAAK;CAE9B;CACA,IAAI,QAAQ,MAAM;EAEhB,IAAI,SAAS,MACX,IAAI,GAAG,IAAI,KAAK;OACX,IAAI,SAAS,MAClB,IAAI,GAAG,GAAG,KAAK;OAEf,IAAI,GAAG,IAAI,KAAK;CAEpB;CACA,IAAI,QAAQ,MAAM,IAAI,GAAG,eAAe,MAAM;CAC9C,IAAI,QAAQ,MAEV,IAAI,GAAG,QAAQ,OAAO,KAAK,OAAO,GAAG,CAAC,GAAG,MAAM;CAEjD,IAAI,QAAQ,MAAM,IAAI,GAAG,aAAa,MAAM;CAC5C,IAAI,QAAQ,MAAM;EAGhB,IAAI,QAAQ,MACV,IAAI,IAAI,IAAI,MAAM;OACb,IAAI,QAAQ,MACjB,IAAI,IAAI,OAAO,GAAG,EAAE,GAAG,MAAM;OACxB,IAAI,SAAS,MAClB,IAAI,GAAG,IAAI,QAAQ;OACd,IAAI,SAAS,MAClB,IAAI,GAAG,IAAI,QAAQ;OAEnB,IAAI,IAAI,OAAO,GAAG,EAAE,GAAG,QAAQ;CAEnC;CACA,IAAI,QAAQ,MAAM,IAAI,IAAI,GAAG,MAAM;CACnC,IAAI,QAAQ,MAAM,IAAI,IAAI,IAAI,QAAQ;CAGtC,KAAK,MAAM,CAAC,KAAK,SAAS,OAAO,QAAQ,gBAAgB,GAAG;EAC1D,MAAM,CAAC,GAAG,GAAG,KAAK,IAAI,MAAM,GAAG,CAAC,CAAC,IAAI,MAAM;EAC3C,IAAI,MAAM,MAAM,IAAI,GAAc,GAAc,IAAI;CACtD;CAEA,MAAM,UAAU,OAAe,QAC7B,KAAK,MAAM,MAAM,EAAE,UAAU,SAAS,EAAE,QAAQ,GAAG;CAGrD,IAAI,QAAQ,MAAM;EAChB,MAAM,iBAAiB,WAAW,MAAM,GAAG,EAAE,CAAC,CAAC,QAAQ;EACvD,KAAK,MAAM,KAAK,CAAC,GAAG,IAAI,GAAG;GACzB,IAAI,UAAU,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,GAAG;GAC3C,MAAM,OAAO,WAAW,MAAM,EAAE,QAAQ,GAAG,EAAE,GAAG;GAChD,IAAI,KAAK,QAAQ,IAAI,gBAAgB;GACrC,KAAK,IAAI,IAAI,GAAG,KAAK,GAAG,KAAK;IAC3B,MAAM,OAAO,QAAQ,MAAM,CAAC;IAC5B,IAAI,CAAC,OAAO,KAAK,SAAS,IAAI,GAAG,KAAK,QAAQ,CAAC,GAAG;KAChD,IAAI,KAAK,SAAS,IAAI,GAAG,KAAK,QAAQ,GAAG,MAAM;KAC/C;IACF;GACF;EACF;CACF;CAGA,IAAI,QAAQ,MACV,KAAK,IAAI,QAAQ,GAAG,SAAS,IAAI,SAAS;EACxC,MAAM,OAAO,WAAW,MAAM,OAAO,CAAC,CAAC,CAAC,QAAQ;EAChD,KAAK,IAAI,MAAM,GAAG,OAAO,MAAM,OAAO;GACpC,IAAI,OAAO,OAAO,GAAG,GAAG;GACxB,MAAM,OAAO,WAAW,MAAM,QAAQ,GAAG,GAAG;GAC5C,IAAI,KAAK,OAAO,MAAM,GAAG;GACzB,MAAM,OAAO,QAAQ,MAAM,EAAE;GAC7B,MAAM,OAAO,QAAQ,MAAM,CAAC;GAC5B,IACE,OAAO,KAAK,SAAS,IAAI,GAAG,KAAK,QAAQ,CAAC,KAC1C,OAAO,KAAK,SAAS,IAAI,GAAG,KAAK,QAAQ,CAAC,GAE1C,IAAI,OAAO,KAAK,OAAO;EAE3B;CACF;CAGF,OAAO;AACT;;AAGA,MAAM,+BAAe,IAAI,IAA2B;;AAGpD,SAAS,WAAW,MAAY,QAAsC;CACpE,IAAI,WAAW,MAAM,OAAO;CAC5B,MAAM,OAAO,KAAK,YAAY;CAC9B,IAAI,OAAA,QAA2B,OAAA,MAAyB,OAAO;CAC/D,MAAM,SAAS,aAAa,IAAI,IAAI;CACpC,IAAI,WAAW,KAAA,GAAW,OAAO;CACjC,MAAM,OAAO,eAAe,IAAI;CAChC,aAAa,IAAI,MAAM,IAAI;CAC3B,OAAO;AACT;;AAGA,SAAgB,UAAU,MAAY,SAAiB,MAAe;CACpE,gBAAgB,IAAI;CACpB,MAAM,OAAO,WAAW,MAAM,MAAM;CACpC,IAAI,SAAS,MAAM,OAAO;CAC1B,OAAO,KAAK,MACT,MAAM,EAAE,UAAU,KAAK,SAAS,IAAI,KAAK,EAAE,QAAQ,KAAK,QAAQ,CACnE;AACF;;AAGA,SAAgB,eACd,MACA,SAAiB,MACG;CACpB,gBAAgB,IAAI;CACpB,MAAM,OAAO,WAAW,MAAM,MAAM;CACpC,IAAI,SAAS,MAAM,OAAO,KAAA;CAC1B,OAAO,KAAK,MACT,MAAM,EAAE,UAAU,KAAK,SAAS,IAAI,KAAK,EAAE,QAAQ,KAAK,QAAQ,CACnE,CAAC,EAAE;AACL;;AAKA,SAAgB,cAAc,MAAY,SAAiB,MAAe;CACxE,gBAAgB,IAAI;CACpB,IAAI,KAAK,OAAO,MAAM,KAAK,KAAK,OAAO,MAAM,GAAG,OAAO;CACvD,OAAO,CAAC,UAAU,MAAM,MAAM;AAChC;;AAGA,SAAS,qBAAqB,QAAsB;CAClD,IAAI,CAAC,OAAO,UAAU,MAAM,GAC1B,MAAM,IAAI,WAAW,mBAAmB,OAAO,uBAAuB;AAE1E;;;;;;AAOA,SAAgB,gBACd,MACA,QACA,SAAiB,MACX;CACN,gBAAgB,IAAI;CACpB,qBAAqB,MAAM;CAC3B,MAAM,SAAS,IAAI,KAAK,KAAK,QAAQ,CAAC;CACtC,MAAM,OAAO,UAAU,IAAI,IAAI;CAC/B,IAAI,YAAY,KAAK,IAAI,MAAM;CAC/B,OAAO,YAAY,GAAG;EACpB,OAAO,QAAQ,OAAO,QAAQ,IAAI,IAAI;EACtC,IAAI,cAAc,QAAQ,MAAM,GAAG;CACrC;CACA,OAAO;AACT;;;;;;AAOA,SAAgB,mBACd,MACA,IACA,SAAiB,MACT;CACR,gBAAgB,IAAI;CACpB,gBAAgB,EAAE;CAClB,MAAM,OAAO,GAAG,QAAQ,KAAK,KAAK,QAAQ,IAAI,IAAI;CAClD,MAAM,SAAS,IAAI,KAAK,KAAK,QAAQ,CAAC;CACtC,IAAI,QAAQ;CACZ,SAAS;EACP,OAAO,QAAQ,OAAO,QAAQ,IAAI,IAAI;EACtC,IACE,OAAO,IACH,OAAO,QAAQ,IAAI,GAAG,QAAQ,IAC9B,OAAO,QAAQ,IAAI,GAAG,QAAQ,GAElC;EAEF,IAAI,cAAc,QAAQ,MAAM,GAAG;CACrC;CACA,OAAO,QAAQ;AACjB;;;;;;;ACnQA,SAAgB,UACd,GACA,GACuB;CACvB,IAAI,MAAM,QAAQ,MAAM,MAAM,OAAO,KAAA;CACrC,OAAO,EAAE,QAAQ,KAAK,EAAE,QAAQ,IAAI;EAAE,MAAM;EAAG,IAAI;CAAE,IAAI;EAAE,MAAM;EAAG,IAAI;CAAE;AAC5E;;AAGA,SAAgB,gBAAgB,MAAc,OAAqB;CACjE,qBAAqB,MAAM,KAAK;CAChC,OAAO,WAAW,MAAM,QAAQ,GAAG,CAAC;AACtC;;AAGA,SAAgB,eAAe,MAAc,OAAqB;CAChE,qBAAqB,MAAM,KAAK;CAChC,OAAO,WAAW,MAAM,OAAO,CAAC;AAClC;;;;;AAMA,SAAgB,eACd,MACA,OACA,WACqB;CACrB,qBAAqB,MAAM,KAAK;CAChC,qBAAqB,SAAS;CAE9B,MAAM,cAAc,eAAe,MAAM,KAAK,CAAC,CAAC,QAAQ;CACxD,IAAI,OAAO,gBAAgB,MAAM,KAAK,CAAC,CAAC,OAAO;CAC/C,IAAI,cAAc,UAChB,QAAQ,OAAO,KAAK;CAGtB,MAAM,OAA4B,CAAC;CACnC,IAAI,MAAM;CACV,KAAK,IAAI,OAAO,GAAG,OAAO,GAAG,QAAQ;EACnC,MAAM,MAAyB,CAAC;EAChC,KAAK,IAAI,MAAM,GAAG,MAAM,GAAG,OACzB,IAAI,MAAM,eAAgB,SAAS,KAAK,MAAM,MAC5C,IAAI,KAAK,IAAI;OAEb,IAAI,KAAK,KAAK;EAGlB,KAAK,KAAK,GAAG;CACf;CACA,OAAO;AACT;;AAGA,SAAS,iBAAiB,MAAY,IAAgB;CACpD,gBAAgB,IAAI;CACpB,gBAAgB,EAAE;CAClB,IAAI,KAAK,QAAQ,IAAI,GAAG,QAAQ,GAC9B,MAAM,IAAI,WAAW,0CAA0C;AAEnE;;AAGA,SAAgB,cACd,MACA,OACS;CACT,IAAI,CAAC,OAAO,OAAO;CACnB,iBAAiB,MAAM,MAAM,MAAM,EAAE;CACrC,gBAAgB,IAAI;CACpB,MAAM,OAAO,KAAK,QAAQ;CAC1B,OAAO,QAAQ,MAAM,KAAK,QAAQ,KAAK,QAAQ,MAAM,GAAG,QAAQ;AAClE;;AAGA,SAAgB,UAAU,GAAS,GAAkB;CACnD,gBAAgB,CAAC;CACjB,gBAAgB,CAAC;CACjB,OACE,EAAE,YAAY,MAAM,EAAE,YAAY,KAClC,EAAE,SAAS,MAAM,EAAE,SAAS,KAC5B,EAAE,QAAQ,MAAM,EAAE,QAAQ;AAE9B;;AAGA,SAAgB,qBACd,MACA,UAOI,CAAC,GACc;CACnB,gBAAgB,IAAI;CACpB,OAAO;EACL,WAAW,KAAK,OAAO,MAAM,KAAK,KAAK,OAAO,MAAM;EACpD,WAAW,UAAU,MAAM,QAAQ,aAAa;EAChD,SAAS,QAAQ,UAAU,KAAA,KAAa,UAAU,MAAM,QAAQ,KAAK;EACrE,aACE,QAAQ,cAAc,KAAA,KAAa,UAAU,MAAM,QAAQ,SAAS;EACtE,WACE,QAAQ,UAAU,KAAA,KAAa,cAAc,MAAM,QAAQ,KAAK;EAClE,YAAY,QAAQ,iBAAiB,IAAI,KAAK;CAChD;AACF;;AAGA,SAAgB,cACd,MACA,IACmC;CACnC,iBAAiB,MAAM,EAAE;CACzB,MAAM,QAAQ,KAAK,YAAY,IAAI,KAAK,KAAK,SAAS;CACtD,MAAM,MAAM,GAAG,YAAY,IAAI,KAAK,GAAG,SAAS;CAChD,OAAO,MAAM,KAAK,EAAE,QAAQ,MAAM,QAAQ,EAAE,IAAI,GAAG,MAAM;EACvD,MAAM,IAAI,QAAQ;EAClB,OAAO;GAAE,MAAM,KAAK,MAAM,IAAI,EAAE;GAAG,OAAQ,IAAI,KAAM;EAAE;CACzD,CAAC;AACH;;AAGA,SAAgB,WAAW,MAAuB;CAChD,gBAAgB,IAAI;CACpB,OAAQ,OAAO,MAAM,KAAK,OAAO,QAAQ,KAAM,OAAO,QAAQ;AAChE;;AAGA,SAAgB,YAAY,MAAc,OAAuB;CAC/D,qBAAqB,MAAM,KAAK;CAChC,OAAO,eAAe,MAAM,KAAK,CAAC,CAAC,QAAQ;AAC7C"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/validation.ts","../src/locale.ts","../src/date-math.ts","../src/holidays.ts","../src/utils.ts"],"sourcesContent":["// ─── 入力検証 ─────────────────────────────────────────────\n\n/** サポートする年の最小値(JS Date は 0-99 を 1900+年 と解釈するため 1 から) */\nexport const MIN_YEAR = 1;\n/** サポートする年の最大値 */\nexport const MAX_YEAR = 9999;\n\n/** 値が min-max の整数であることを検証する(不正なら RangeError) */\nfunction assertIntegerInRange(\n name: string,\n value: number,\n min: number,\n max: number,\n): void {\n if (!Number.isInteger(value) || value < min || value > max) {\n throw new RangeError(\n `Invalid ${name}: ${value} (expected an integer between ${min} and ${max})`,\n );\n }\n}\n\n/** 年が 1-9999 の整数であることを検証する */\nexport function assertValidYear(year: number): void {\n assertIntegerInRange(\"year\", year, MIN_YEAR, MAX_YEAR);\n}\n\n/** 月が 1-12 の整数であることを検証する */\nexport function assertValidMonth(month: number): void {\n assertIntegerInRange(\"month\", month, 1, 12);\n}\n\n/** 年の組み合わせ(year と month)を検証する */\nexport function assertValidYearMonth(year: number, month: number): void {\n assertValidYear(year);\n assertValidMonth(month);\n}\n\n/** 週の開始曜日を検証する */\nexport function assertValidWeekStart(weekStart: string): void {\n if (weekStart !== \"sunday\" && weekStart !== \"monday\") {\n throw new RangeError(\n `Invalid weekStart: \"${weekStart}\" (expected \"sunday\" or \"monday\")`,\n );\n }\n}\n\n/** Date が有効(Invalid Date でない)ことを検証する */\nexport function assertValidDate(date: Date): void {\n if (!(date instanceof Date) || Number.isNaN(date.getTime())) {\n throw new RangeError(`Invalid Date: ${String(date)}`);\n }\n}\n\n/**\n * ローカルの指定日 00:00:00 を生成する。\n * `new Date(year, ...)` は year 0-99 を 1900+year と解釈するため、\n * setFullYear を使って year 0-99 も正しく扱えるようにする。\n *\n * - year は 1-9999、monthIndex は 0-12、day は 0-31 の整数である必要がある(それ以外は RangeError)\n * - monthIndex 12 は翌年1月(`new Date` と同じロールオーバー。lastDayOfMonth が 12月の月末取得に使う)\n * - day 0 は前月の月末(`new Date` と同じ規則)\n * - day がその月の日数を超える場合は翌月にロールする(`new Date` と同じ挙動)\n */\nexport function createDate(\n year: number,\n monthIndex: number,\n day: number,\n): Date {\n assertValidYear(year);\n assertIntegerInRange(\"monthIndex\", monthIndex, 0, 12);\n assertIntegerInRange(\"day\", day, 0, 31);\n const date = new Date(0);\n date.setHours(0, 0, 0, 0);\n date.setFullYear(year, monthIndex, day);\n return date;\n}\n","import type { Locale, WeekStart } from \"./types.ts\";\nimport { assertValidMonth, assertValidWeekStart } from \"./validation.ts\";\n\nexport interface LocaleData {\n months: readonly string[];\n weekdays: readonly string[];\n weekdaysShort: readonly string[];\n weekdaysMonday: readonly string[];\n weekdaysMondayShort: readonly string[];\n}\n\n/** 月曜始まりの配列は日曜始まりの配列を前ローテーションして生成する */\nfunction makeLocale(\n months: readonly string[],\n weekdays: readonly string[],\n weekdaysShort: readonly string[] = weekdays,\n): LocaleData {\n const rotate = (arr: readonly string[]) => [...arr.slice(1), arr[0]!];\n return {\n months,\n weekdays,\n weekdaysShort,\n weekdaysMonday: rotate(weekdays),\n weekdaysMondayShort: rotate(weekdaysShort),\n };\n}\n\nexport const LOCALES: Record<Locale, LocaleData> = {\n en: makeLocale(\n [\n \"January\",\n \"February\",\n \"March\",\n \"April\",\n \"May\",\n \"June\",\n \"July\",\n \"August\",\n \"September\",\n \"October\",\n \"November\",\n \"December\",\n ],\n [\"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\"],\n [\"Su\", \"Mo\", \"Tu\", \"We\", \"Th\", \"Fr\", \"Sa\"],\n ),\n ja: makeLocale(\n [\n \"1月\",\n \"2月\",\n \"3月\",\n \"4月\",\n \"5月\",\n \"6月\",\n \"7月\",\n \"8月\",\n \"9月\",\n \"10月\",\n \"11月\",\n \"12月\",\n ],\n [\"日\", \"月\", \"火\", \"水\", \"木\", \"金\", \"土\"],\n ),\n es: makeLocale(\n [\n \"enero\",\n \"febrero\",\n \"marzo\",\n \"abril\",\n \"mayo\",\n \"junio\",\n \"julio\",\n \"agosto\",\n \"septiembre\",\n \"octubre\",\n \"noviembre\",\n \"diciembre\",\n ],\n [\"dom\", \"lun\", \"mar\", \"mié\", \"jue\", \"vie\", \"sáb\"],\n [\"do\", \"lu\", \"ma\", \"mi\", \"ju\", \"vi\", \"sá\"],\n ),\n de: makeLocale(\n [\n \"Januar\",\n \"Februar\",\n \"März\",\n \"April\",\n \"Mai\",\n \"Juni\",\n \"Juli\",\n \"August\",\n \"September\",\n \"Oktober\",\n \"November\",\n \"Dezember\",\n ],\n [\"So\", \"Mo\", \"Di\", \"Mi\", \"Do\", \"Fr\", \"Sa\"],\n ),\n fr: makeLocale(\n [\n \"janvier\",\n \"février\",\n \"mars\",\n \"avril\",\n \"mai\",\n \"juin\",\n \"juillet\",\n \"août\",\n \"septembre\",\n \"octobre\",\n \"novembre\",\n \"décembre\",\n ],\n [\"dim.\", \"lun.\", \"mar.\", \"mer.\", \"jeu.\", \"ven.\", \"sam.\"],\n [\"di\", \"lu\", \"ma\", \"me\", \"je\", \"ve\", \"sa\"],\n ),\n ko: makeLocale(\n [\n \"1월\",\n \"2월\",\n \"3월\",\n \"4월\",\n \"5월\",\n \"6월\",\n \"7월\",\n \"8월\",\n \"9월\",\n \"10월\",\n \"11월\",\n \"12월\",\n ],\n [\"일\", \"월\", \"화\", \"수\", \"목\", \"금\", \"토\"],\n ),\n zh: makeLocale(\n [\n \"一月\",\n \"二月\",\n \"三月\",\n \"四月\",\n \"五月\",\n \"六月\",\n \"七月\",\n \"八月\",\n \"九月\",\n \"十月\",\n \"十一月\",\n \"十二月\",\n ],\n [\"日\", \"一\", \"二\", \"三\", \"四\", \"五\", \"六\"],\n ),\n};\n\n/** ロケールデータを取得する(未知のロケールは RangeError) */\nexport function getLocaleData(locale: Locale): LocaleData {\n const data = LOCALES[locale];\n if (data === undefined) {\n throw new RangeError(`Invalid locale: \"${locale}\"`);\n }\n return data;\n}\n\nexport function getWeekdayHeaders(\n locale: Locale,\n weekStart: WeekStart,\n): readonly string[] {\n assertValidWeekStart(weekStart);\n const data = getLocaleData(locale);\n return weekStart === \"monday\" ? data.weekdaysMonday : data.weekdays;\n}\n\nexport function getMonthName(locale: Locale, month: number): string {\n assertValidMonth(month);\n const data = getLocaleData(locale);\n return data.months[month - 1]!;\n}\n","import { getLocaleData, getMonthName } from \"./locale.ts\";\nimport type { Locale, WeekStart } from \"./types.ts\";\nimport {\n assertValidDate,\n assertValidWeekStart,\n createDate,\n} from \"./validation.ts\";\n\n// ─── 日付演算 ─────────────────────────────────────────────\n\n/** 加算量が整数であることを検証する */\nfunction assertAmount(amount: number): void {\n if (!Number.isInteger(amount)) {\n throw new RangeError(`Invalid amount: ${amount} (expected an integer)`);\n }\n}\n\n/**\n * 日付に日数を加算する(負数で減算)。時刻は保持される。\n * `setDate` ベースの暦日加算のため DST 遷移でも 1 日ずれない。\n * 入力 Date は変更されず、新しい Date を返す。\n */\nexport function addDays(date: Date, amount: number): Date {\n assertValidDate(date);\n assertAmount(amount);\n const result = new Date(date.getTime());\n result.setDate(result.getDate() + amount);\n return result;\n}\n\n/** 日付に週数を加算する(負数で減算)。addDays(date, amount * 7) と同じ */\nexport function addWeeks(date: Date, amount: number): Date {\n return addDays(date, amount * 7);\n}\n\n/**\n * 日付に月数を加算する(負数で減算)。時刻は保持される。\n * 月中旬の日付は月を跨いでも同じ日付を保つ(例: 1月15日 + 1ヶ月 = 2月15日)。\n * 移動先の月に存在しない日付は月末に丸められる\n * (例: 1月31日 + 1ヶ月 = 2月28日/29日、1月30日 + 1ヶ月 = 2月28日/29日)。\n */\nexport function addMonths(date: Date, amount: number): Date {\n assertValidDate(date);\n assertAmount(amount);\n const result = startOfDay(date);\n const targetDay = date.getDate();\n result.setDate(1);\n result.setMonth(result.getMonth() + amount);\n const lastDay = daysInMonthOf(result);\n result.setDate(Math.min(targetDay, lastDay));\n // 時刻を復元する\n result.setHours(\n date.getHours(),\n date.getMinutes(),\n date.getSeconds(),\n date.getMilliseconds(),\n );\n return result;\n}\n\n/** 日付に年数を加算する(負数で減算)。うるう日の 2月29日は 2月28日に丸められる */\nexport function addYears(date: Date, amount: number): Date {\n return addMonths(date, amount * 12);\n}\n\n/** 月の日数(1-31)を返す(Date 基準) */\nfunction daysInMonthOf(date: Date): number {\n return new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate();\n}\n\n// ─── 期間の境界 ───────────────────────────────────────────\n\n/** その日の 00:00:00.000 を返す */\nexport function startOfDay(date: Date): Date {\n assertValidDate(date);\n return createDate(date.getFullYear(), date.getMonth(), date.getDate());\n}\n\n/** その日の 23:59:59.999 を返す */\nexport function endOfDay(date: Date): Date {\n const result = startOfDay(date);\n result.setHours(23, 59, 59, 999);\n return result;\n}\n\n/** 日付を含む週の初日(weekStart 曜日)の 00:00:00.000 を返す */\nexport function startOfWeek(date: Date, weekStart: WeekStart = \"sunday\"): Date {\n assertValidDate(date);\n assertValidWeekStart(weekStart);\n const day = startOfDay(date);\n const offset = weekStart === \"sunday\" ? day.getDay() : (day.getDay() + 6) % 7;\n return addDays(day, -offset);\n}\n\n/** 日付を含む週の最終日の 23:59:59.999 を返す(週末を含む範囲に便利) */\nexport function endOfWeek(date: Date, weekStart: WeekStart = \"sunday\"): Date {\n return endOfDay(addDays(startOfWeek(date, weekStart), 6));\n}\n\n/** 日付を含む月の初日の 00:00:00.000 を返す */\nexport function startOfMonth(date: Date): Date {\n assertValidDate(date);\n return createDate(date.getFullYear(), date.getMonth(), 1);\n}\n\n/** 日付を含む月の最終日の 23:59:59.999 を返す */\nexport function endOfMonth(date: Date): Date {\n return endOfDay(createDate(date.getFullYear(), date.getMonth() + 1, 0));\n}\n\n/** 日付を含む年の初日(1月1日)の 00:00:00.000 を返す */\nexport function startOfYear(date: Date): Date {\n assertValidDate(date);\n return createDate(date.getFullYear(), 0, 1);\n}\n\n/** 日付を含む年の最終日の 23:59:59.999 を返す */\nexport function endOfYear(date: Date): Date {\n return endOfDay(createDate(date.getFullYear(), 12, 0));\n}\n\n// ─── 差(暦日ベース) ─────────────────────────────────────\n\n/** 日付の「日」部分を UTC 日数(epoch からの日数)に正規化する。DST や year 0-99 の影響を受けない */\nfunction toUtcDays(date: Date): number {\n const utc = new Date(0);\n utc.setUTCFullYear(date.getFullYear(), date.getMonth(), date.getDate());\n return utc.getTime() / 86_400_000;\n}\n\n/**\n * 2つの日付の間の暦日数(to - from)を返す。マイナスもありうる。\n * 時刻は無視され、DST 遷移があっても 1 日単位の差は正しい。\n */\nexport function diffInCalendarDays(from: Date, to: Date): number {\n assertValidDate(from);\n assertValidDate(to);\n return toUtcDays(to) - toUtcDays(from);\n}\n\n/** 2つの日付の間の暦月数(to - from)を返す。マイナスもありうる */\nexport function diffInCalendarMonths(from: Date, to: Date): number {\n assertValidDate(from);\n assertValidDate(to);\n return (\n (to.getFullYear() - from.getFullYear()) * 12 +\n (to.getMonth() - from.getMonth())\n );\n}\n\n/** 2つの日付の間の暦年数(to - from)を返す。マイナスもありうる */\nexport function diffInCalendarYears(from: Date, to: Date): number {\n assertValidDate(from);\n assertValidDate(to);\n return to.getFullYear() - from.getFullYear();\n}\n\n// ─── 比較 ─────────────────────────────────────────────────\n\n/** date が other より前(厳密に時刻が小さい)か */\nexport function isBefore(date: Date, other: Date): boolean {\n assertValidDate(date);\n assertValidDate(other);\n return date.getTime() < other.getTime();\n}\n\n/** date が other より後(厳密に時刻が大きい)か */\nexport function isAfter(date: Date, other: Date): boolean {\n assertValidDate(date);\n assertValidDate(other);\n return date.getTime() > other.getTime();\n}\n\n/** 同じ年月か(日は無視) */\nexport function isSameMonth(a: Date, b: Date): boolean {\n assertValidDate(a);\n assertValidDate(b);\n return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth();\n}\n\n/** 同じ年か(月・日は無視) */\nexport function isSameYear(a: Date, b: Date): boolean {\n assertValidDate(a);\n assertValidDate(b);\n return a.getFullYear() === b.getFullYear();\n}\n\n/** 週末(土曜 or 日曜)か */\nexport function isWeekend(date: Date): boolean {\n assertValidDate(date);\n const day = date.getDay();\n return day === 0 || day === 6;\n}\n\n// ─── 年・週の位置 ─────────────────────────────────────────\n\n/** ISO 8601 の週番号(1-53)を返す。第1週は最初の木曜日を含む週 */\nexport function getISOWeek(date: Date): number {\n assertValidDate(date);\n const day = startOfDay(date);\n const weekday = (day.getDay() + 6) % 7; // 月=0 ... 日=6\n // 今週の木曜日(ISO 年の基準。月曜〜日曜のどれを取っても同じ週番号になる)\n const thursday = addDays(day, 3 - weekday);\n const jan1 = createDate(thursday.getFullYear(), 0, 1);\n const jan1Weekday = (jan1.getDay() + 6) % 7;\n const firstThursday = addDays(jan1, (3 - jan1Weekday + 7) % 7);\n return Math.floor(diffInCalendarDays(firstThursday, thursday) / 7) + 1;\n}\n\n/**\n * 年始(1月1日)を含む週を第1週とする週番号を返す。\n * 1月1日より前の週の末日(例: 日曜始まりの 1月1日が土曜のとき)は前年の第52週/第53週になる。\n * 北米のカレンダー(cal -w 相当)で使われる規則。\n */\nexport function getWeekOfYear(\n date: Date,\n weekStart: WeekStart = \"sunday\",\n): number {\n assertValidDate(date);\n assertValidWeekStart(weekStart);\n const day = startOfDay(date);\n const jan1 = createDate(day.getFullYear(), 0, 1);\n const weekStartJan1 = startOfWeek(jan1, weekStart);\n return Math.floor(diffInCalendarDays(weekStartJan1, day) / 7) + 1;\n}\n\n/** 年の通算日(1月1日 = 1、12月31日 = 365/366)を返す */\nexport function getDayOfYear(date: Date): number {\n assertValidDate(date);\n return diffInCalendarDays(startOfYear(date), date) + 1;\n}\n\n// ─── その他 ───────────────────────────────────────────────\n\n/** 日付を [min, max] の範囲内にクランプする。範囲外なら min/max を、範囲内なら元の Date を返す */\nexport function clampDate(date: Date, min: Date, max: Date): Date {\n assertValidDate(date);\n assertValidDate(min);\n assertValidDate(max);\n if (date.getTime() < min.getTime()) return min;\n if (date.getTime() > max.getTime()) return max;\n return date;\n}\n\nconst TOKEN_RE = /yyyy|MMMM|EEE|yy|MM|dd|M|d/g;\n\n/**\n * パターン文字列に従って日付をフォーマットする。\n *\n * 対応トークン:\n * - `yyyy` — 4桁の年(例: 2026)\n * - `yy` — 西暦下2桁(例: 26)\n * - `MMMM` — フル月名(ロケール依存。例: September / 9月)\n * - `MM` — 0埋め2桁の月(01-12)\n * - `M` — 月(1-12)\n * - `dd` — 0埋め2桁の日(01-31)\n * - `d` — 日(1-31)\n * - `EEE` — 曜日の短縮名(ロケール依存。例: Fri / 金)\n *\n * トークン以外の文字はそのまま出力される。\n *\n * ```ts\n * formatDate(date, \"yyyy-MM-dd\"); // \"2026-09-25\"\n * formatDate(date, \"MMMM d, yyyy (EEE)\"); // \"September 25, 2026 (Fri)\"\n * formatDate(date, \"yyyy年M月d日\", \"ja\"); // \"2026年9月25日\"\n * ```\n */\nexport function formatDate(\n date: Date,\n pattern: string,\n locale: Locale = \"en\",\n): string {\n assertValidDate(date);\n const data = getLocaleData(locale);\n return pattern.replace(TOKEN_RE, (token) => {\n switch (token) {\n case \"yyyy\":\n return String(date.getFullYear()).padStart(4, \"0\");\n case \"yy\":\n return String(date.getFullYear() % 100).padStart(2, \"0\");\n case \"MMMM\":\n return getMonthName(locale, date.getMonth() + 1);\n case \"MM\":\n return String(date.getMonth() + 1).padStart(2, \"0\");\n case \"M\":\n return String(date.getMonth() + 1);\n case \"dd\":\n return String(date.getDate()).padStart(2, \"0\");\n case \"d\":\n return String(date.getDate());\n case \"EEE\":\n return data.weekdays[date.getDay()]!;\n default:\n return token;\n }\n });\n}\n","import { addDays } from \"./date-math.ts\";\nimport type { Locale } from \"./types.ts\";\nimport { assertValidDate, createDate } from \"./validation.ts\";\n\n// ─── 日本の祝日 ───────────────────────────────────────────\n\n/**\n * 祝日データを持つロケール。現在は日本語(日本の国民の祝日)のみ。\n * その他のロケールは「祝日なし」として扱われる(isHoliday は常に false)。\n */\nexport type HolidayLocale = \"ja\";\n\n/** 祝日が計算できる年範囲(1949 年以降の現行祝日法制に基づく) */\nexport const HOLIDAY_MIN_YEAR = 1949;\n\n/** 祝日が計算できる年範囲(秋分の日の近似式が有効な上限。実用上十分) */\nexport const HOLIDAY_MAX_YEAR = 2100;\n\n/** 1回限りの祝日(皇室行事・改元に伴う法律で定められたもの) */\nconst ONE_OFF_HOLIDAYS: readonly YearHolidayWithYear[] = [\n { year: 1959, month: 4, day: 10, name: \"皇太子明仁親王の結婚の儀\" },\n { year: 1989, month: 2, day: 24, name: \"昭和天皇の大喪の礼\" },\n { year: 1990, month: 11, day: 12, name: \"即位の礼正殿の儀\" },\n { year: 1993, month: 6, day: 9, name: \"皇太子徳仁親王の結婚の儀\" },\n { year: 2019, month: 5, day: 1, name: \"天皇即位の日\" },\n { year: 2019, month: 10, day: 22, name: \"即位礼正殿の儀\" },\n];\n\n/** 年の祝日一覧の1件(month は 1-12) */\ninterface YearHoliday {\n month: number;\n day: number;\n name: string;\n}\n\n/** 祝日一覧の1件に発生日(year)を添えたもの。一覧データの定義に使う */\ninterface YearHolidayWithYear extends YearHoliday {\n year: number;\n}\n\n/** 年月日の曜日(0=日曜) */\nfunction dayOfWeek(year: number, month: number, day: number): number {\n return createDate(year, month - 1, day).getDay();\n}\n\n/**\n * 国民の祝日に関する法律と特例法に基づき、年の祝日一覧を規則から算出する。\n *\n * 計算順: ①祝日(固定日・第n月曜・春分/秋分)→ ②特例の祝日 → ③振替休日\n * (1973年以降、祝日が日曜のとき直後の祝日でない日)→ ④国民の休日\n * (1986年以降、祝日(日曜を除く)に挟まれた平日)。\n * 祝日の名称は「元日」「成人の日」など法律上の名称、「振替休日」「国民の休日」はそのままの名称。\n * 2020/2021 年の東京五輪特例(海の日・山の日・スポーツの日の振替)も反映する。\n * 秋分の日・春分の日は天文学的な秋分/春分の日付(1851〜2099 年で有効な近似式)で算出する。\n */\nfunction holidaysOfYear(year: number): YearHoliday[] {\n const list: YearHoliday[] = [];\n const add = (month: number, day: number, name: string): void => {\n list.push({ month, day, name });\n };\n /** 指定月の第 n 曜日(weekday: 0=日曜 .. 6=土曜)の日付を返す */\n const nthWeekday = (weekday: number, n: number, month: number): number => {\n const first = createDate(year, month - 1, 1);\n const offset = (weekday - first.getDay() + 7) % 7;\n return 1 + offset + (n - 1) * 7;\n };\n const monday = (n: number, month: number): number => nthWeekday(1, n, month);\n const springEquinox = Math.floor(\n 20.8431 + 0.242194 * (year - 1980) - Math.floor((year - 1980) / 4),\n );\n const fallEquinox = Math.floor(\n 23.2488 + 0.242194 * (year - 1980) - Math.floor((year - 1980) / 4),\n );\n\n // ── ① 国民の祝日(法律上の規則) ──\n if (year >= 1949) add(1, 1, \"元日\");\n if (year >= 1949) {\n // 成人の日: 2000年以降は1月第2月曜\n add(1, year <= 1999 ? 15 : monday(2, 1), \"成人の日\");\n }\n if (year >= 1967) add(2, 11, \"建国記念の日\");\n if (year >= 1949) {\n // 天皇誕生日: 4/29(〜1988)→ 12/23(1989-2018)→ 2019年はなし → 2/23(2020-)\n if (year <= 1988) {\n add(4, 29, \"天皇誕生日\");\n } else if (year <= 2018) {\n add(12, 23, \"天皇誕生日\");\n } else if (year >= 2020) {\n add(2, 23, \"天皇誕生日\");\n }\n }\n if (year >= 2007) add(4, 29, \"昭和の日\");\n if (year >= 1949) add(5, 3, \"憲法記念日\");\n if (year >= 1989 && year <= 2006) add(4, 29, \"みどりの日\");\n if (year >= 2007) add(5, 4, \"みどりの日\");\n if (year >= 1949) add(5, 5, \"こどもの日\");\n if (year >= 1996) {\n // 海の日: 7/20(〜2002)→ 第3月曜(2003-)。2020/2021 は東京五輪特例\n if (year <= 2002) {\n add(7, 20, \"海の日\");\n } else if (year === 2020) {\n add(7, 23, \"海の日\");\n } else if (year === 2021) {\n add(7, 22, \"海の日\");\n } else {\n add(7, monday(3, 7), \"海の日\");\n }\n }\n if (year >= 2016) {\n // 山の日: 8/11。2020/2021 は東京五輪特例\n if (year === 2020) {\n add(8, 10, \"山の日\");\n } else if (year === 2021) {\n add(8, 8, \"山の日\");\n } else {\n add(8, 11, \"山の日\");\n }\n }\n if (year >= 1949) add(3, springEquinox, \"春分の日\");\n if (year >= 1966) {\n // 敬老の日: 9/15(〜2002)→ 第3月曜(2003-)\n add(9, year <= 2002 ? 15 : monday(3, 9), \"敬老の日\");\n }\n if (year >= 1949) add(9, fallEquinox, \"秋分の日\");\n if (year >= 1966) {\n // 体育の日: 10/10(〜1999)→ 第2月曜(2000-2019)→ スポーツの日(2020-)。\n // 2020/2021 は東京五輪特例\n if (year <= 1999) {\n add(10, 10, \"体育の日\");\n } else if (year <= 2019) {\n add(10, monday(2, 10), \"体育の日\");\n } else if (year === 2020) {\n add(7, 24, \"スポーツの日\");\n } else if (year === 2021) {\n add(7, 23, \"スポーツの日\");\n } else {\n add(10, monday(2, 10), \"スポーツの日\");\n }\n }\n if (year >= 1949) add(11, 3, \"文化の日\");\n if (year >= 1949) add(11, 23, \"勤労感謝の日\");\n\n // ── ② 特例の祝日 ──\n for (const { year: y, month: m, day: d, name } of ONE_OFF_HOLIDAYS) {\n if (y === year) add(m, d, name);\n }\n\n const inList = (month: number, day: number): boolean =>\n list.some((h) => h.month === month && h.day === day);\n\n // ── ③ 振替休日(1973年の法改正により同年4月12日から施行): 祝日が日曜に当たるとき、直後の祝日でない日を休日とする ──\n if (year >= 1973) {\n const substituteFrom = createDate(1973, 3, 12).getTime(); // 制度施行日 1973-04-12\n for (const h of [...list]) {\n if (dayOfWeek(year, h.month, h.day) !== 0) continue;\n const base = createDate(year, h.month - 1, h.day);\n if (base.getTime() < substituteFrom) continue;\n for (let i = 1; i <= 7; i++) {\n const next = addDays(base, i);\n if (!inList(next.getMonth() + 1, next.getDate())) {\n add(next.getMonth() + 1, next.getDate(), \"振替休日\");\n break;\n }\n }\n }\n }\n\n // ── ④ 国民の休日(1986年の法改正以降): 祝日(日曜を除く)に挟まれた平日を休日とする ──\n if (year >= 1986) {\n for (let month = 1; month <= 12; month++) {\n const days = createDate(year, month, 0).getDate();\n for (let day = 1; day <= days; day++) {\n if (inList(month, day)) continue;\n const date = createDate(year, month - 1, day);\n if (date.getDay() === 0) continue;\n const prev = addDays(date, -1);\n const next = addDays(date, 1);\n if (\n inList(prev.getMonth() + 1, prev.getDate()) &&\n inList(next.getMonth() + 1, next.getDate())\n ) {\n add(month, day, \"国民の休日\");\n }\n }\n }\n }\n\n return list;\n}\n\n/** 年の祝日一覧と検索用インデックス。キャッシュして描画ごとの参照を高速化する */\ninterface HolidayIndex {\n /** 祝日一覧(算出順) */\n list: YearHoliday[];\n /** 月ごとの day → 名称インデックス。祝日判定は参照1回で済む */\n byMonth: Map<number, Map<number, string>>;\n}\n\n/**\n * 祝日一覧に月・日のインデックスを張る。\n */\nfunction toIndex(list: YearHoliday[]): HolidayIndex {\n const byMonth = new Map<number, Map<number, string>>();\n for (const h of list) {\n let days = byMonth.get(h.month);\n if (days === undefined) {\n days = new Map<number, string>();\n byMonth.set(h.month, days);\n }\n days.set(h.day, h.name);\n }\n return { list, byMonth };\n}\n\n/** 年の計算結果キャッシュ(同じ年を何度も参照する描画用途のため) */\nconst holidayCache = new Map<number, HolidayIndex>();\n\n/** 祝日インデックスを取得する。対象外ロケール・範囲外の年は null */\nfunction holidayIndexOf(date: Date, locale: Locale): HolidayIndex | null {\n if (locale !== \"ja\") return null;\n const year = date.getFullYear();\n if (year < HOLIDAY_MIN_YEAR || year > HOLIDAY_MAX_YEAR) return null;\n const cached = holidayCache.get(year);\n if (cached !== undefined) return cached;\n const index = toIndex(holidaysOfYear(year));\n holidayCache.set(year, index);\n return index;\n}\n\n/** 日付が祝日(日本の国民の祝日・振替休日・国民の休日)か判定する。対象外ロケール/年は false */\nexport function isHoliday(date: Date, locale: Locale = \"ja\"): boolean {\n assertValidDate(date);\n const index = holidayIndexOf(date, locale);\n if (index === null) return false;\n return (\n index.byMonth.get(date.getMonth() + 1)?.get(date.getDate()) !== undefined\n );\n}\n\n/** 日付の祝日名を返す。祝日でない・対象外ロケール/年は undefined */\nexport function getHolidayName(\n date: Date,\n locale: Locale = \"ja\",\n): string | undefined {\n assertValidDate(date);\n const index = holidayIndexOf(date, locale);\n if (index === null) return undefined;\n return index.byMonth.get(date.getMonth() + 1)?.get(date.getDate());\n}\n\n// ─── 営業日 ───────────────────────────────────────────────\n\n/** 日付が営業日(平日かつ祝日でない)か判定する */\nexport function isBusinessDay(date: Date, locale: Locale = \"ja\"): boolean {\n assertValidDate(date);\n if (date.getDay() === 0 || date.getDay() === 6) return false;\n return !isHoliday(date, locale);\n}\n\n/** 加算する営業日数が整数であることを検証する */\nfunction assertBusinessAmount(amount: number): void {\n if (!Number.isInteger(amount)) {\n throw new RangeError(`Invalid amount: ${amount} (expected an integer)`);\n }\n}\n\n/**\n * 日付に営業日数を加算する(負数で減算)。土日・祝日はスキップされる。\n * 加算の起点は date そのもの(date 自体は数えない)。date === 戻り値になるのは amount = 0 のとき。\n * 例: 2026-05-01(金)に 1 を足すと 2026-05-07(木)になる(5/3-5/6 が祝日)。\n */\nexport function addBusinessDays(\n date: Date,\n amount: number,\n locale: Locale = \"ja\",\n): Date {\n assertValidDate(date);\n assertBusinessAmount(amount);\n const result = new Date(date.getTime());\n const step = amount >= 0 ? 1 : -1;\n let remaining = Math.abs(amount);\n while (remaining > 0) {\n result.setDate(result.getDate() + step);\n if (isBusinessDay(result, locale)) remaining--;\n }\n return result;\n}\n\n/**\n * 2つの日付の間の営業日数(to - from 方向)を返す。マイナスもありうる。\n * from 自身は数えず、to は数える。例: 月曜→火曜 = 1、金曜→翌月曜 = 1(土日はスキップ)。\n * `addBusinessDays(from, n) === to` と `diffInBusinessDays(from, to) === n` は同値。\n */\nexport function diffInBusinessDays(\n from: Date,\n to: Date,\n locale: Locale = \"ja\",\n): number {\n assertValidDate(from);\n assertValidDate(to);\n const sign = to.getTime() >= from.getTime() ? 1 : -1;\n const cursor = new Date(from.getTime());\n let count = 0;\n for (;;) {\n cursor.setDate(cursor.getDate() + sign);\n if (\n sign > 0\n ? cursor.getTime() > to.getTime()\n : cursor.getTime() < to.getTime()\n ) {\n break;\n }\n if (isBusinessDay(cursor, locale)) count++;\n }\n return count * sign;\n}\n","import { isHoliday } from \"./holidays.ts\";\nimport type { Locale, WeekStart } from \"./types.ts\";\nimport {\n assertValidDate,\n assertValidWeekStart,\n assertValidYear,\n assertValidYearMonth,\n createDate,\n} from \"./validation.ts\";\n\nexport interface CalendarCellState {\n isWeekend: boolean;\n /** 祝日かどうか(holidayLocale に従って判定。指定なしは \"ja\") */\n isHoliday: boolean;\n isToday: boolean;\n isHighlight: boolean;\n isInRange: boolean;\n isDisabled: boolean;\n}\n\n/** 日付範囲(from <= to) */\nexport interface DateRange {\n from: Date;\n to: Date;\n}\n\n/**\n * 2つの日付を from <= to の順にソートした範囲を返す。\n * どちらかが null なら undefined(範囲なし)。\n */\nexport function sortRange(\n a: Date | null,\n b: Date | null,\n): DateRange | undefined {\n if (a === null || b === null) return undefined;\n return a.getTime() <= b.getTime() ? { from: a, to: b } : { from: b, to: a };\n}\n\n/** 月初日(1日)を返す */\nexport function firstDayOfMonth(year: number, month: number): Date {\n assertValidYearMonth(year, month);\n return createDate(year, month - 1, 1);\n}\n\n/** 月末日を返す */\nexport function lastDayOfMonth(year: number, month: number): Date {\n assertValidYearMonth(year, month);\n return createDate(year, month, 0);\n}\n\n/**\n * 月の日付グリッドを生成する(6行×7列)\n * 各セルは日数(1-31)または null(空欄)\n */\nexport function buildMonthGrid(\n year: number,\n month: number,\n weekStart: WeekStart,\n): (number | null)[][] {\n assertValidYearMonth(year, month);\n assertValidWeekStart(weekStart);\n\n const daysInMonth = lastDayOfMonth(year, month).getDate();\n let skip = firstDayOfMonth(year, month).getDay();\n if (weekStart === \"monday\") {\n skip = (skip + 6) % 7;\n }\n\n const grid: (number | null)[][] = [];\n let day = 1;\n for (let week = 0; week < 6; week++) {\n const row: (number | null)[] = [];\n for (let col = 0; col < 7; col++) {\n if (day > daysInMonth || (week === 0 && col < skip)) {\n row.push(null);\n } else {\n row.push(day++);\n }\n }\n grid.push(row);\n }\n return grid;\n}\n\n/** 範囲(from/to)が有効であることを検証する */\nfunction assertValidRange(from: Date, to: Date): void {\n assertValidDate(from);\n assertValidDate(to);\n if (from.getTime() > to.getTime()) {\n throw new RangeError(\"Invalid range: from must not be after to\");\n }\n}\n\n/** 日付が範囲内に含まれるか */\nexport function isDateInRange(\n date: Date,\n range?: { from: Date; to: Date },\n): boolean {\n if (!range) return false;\n assertValidRange(range.from, range.to);\n assertValidDate(date);\n const time = date.getTime();\n return time >= range.from.getTime() && time <= range.to.getTime();\n}\n\n/** 日付が今日と一致するか(日付のみ比較) */\nexport function isSameDay(a: Date, b: Date): boolean {\n assertValidDate(a);\n assertValidDate(b);\n return (\n a.getFullYear() === b.getFullYear() &&\n a.getMonth() === b.getMonth() &&\n a.getDate() === b.getDate()\n );\n}\n\n/** 日付セルの表示状態を計算する */\nexport function getCalendarCellState(\n date: Date,\n options: {\n today?: Date;\n highlight?: Date;\n range?: { from: Date; to: Date };\n isDateDisabled?: (date: Date) => boolean;\n /** 祝日判定に使うロケール。省略時は \"ja\"(isHoliday のデフォルト) */\n holidayLocale?: Locale;\n } = {},\n): CalendarCellState {\n assertValidDate(date);\n return {\n isWeekend: date.getDay() === 0 || date.getDay() === 6,\n isHoliday: isHoliday(date, options.holidayLocale),\n isToday: options.today !== undefined && isSameDay(date, options.today),\n isHighlight:\n options.highlight !== undefined && isSameDay(date, options.highlight),\n isInRange:\n options.range !== undefined && isDateInRange(date, options.range),\n isDisabled: options.isDateDisabled?.(date) ?? false,\n };\n}\n\n/** 日付が範囲の開始年から終了年までの月リストを返す */\nexport function getMonthRange(\n from: Date,\n to: Date,\n): { year: number; month: number }[] {\n assertValidRange(from, to);\n const start = from.getFullYear() * 12 + from.getMonth();\n const end = to.getFullYear() * 12 + to.getMonth();\n return Array.from({ length: end - start + 1 }, (_, i) => {\n const n = start + i;\n return { year: Math.floor(n / 12), month: (n % 12) + 1 };\n });\n}\n\n/** グレゴリオ暦のうるう年判定(4で割れるが100では割れない、または400で割れる) */\nexport function isLeapYear(year: number): boolean {\n assertValidYear(year);\n return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;\n}\n\n/** 月の日数(1-31)を返す */\nexport function daysInMonth(year: number, month: number): number {\n assertValidYearMonth(year, month);\n return lastDayOfMonth(year, month).getDate();\n}\n"],"mappings":"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"}
|