bizdays-toolkit 0.12.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,49 @@
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.14.0] - 2026-10-20
8
+
9
+ ### 移行
10
+
11
+ 動作は変わりません(締め期間と、暦日と時刻から瞬間への変換の追加)。版ごとの作業は [docs/migration.md](./docs/migration.md) にまとめた。
12
+
13
+ ### Added
14
+
15
+ - 締め日で区切ったときのその月分の期間を返す `closingPeriod(monthOrDate, closingDay)` を追加した(`closingMonth` の逆算。前月の締め日の翌日からその月の締め日まで、両端を含む `{ from, to }`)。暦日を渡すとその日が属する期間。返す値は変更できず、日付の期間の形なので `closedDates` や `listBusinessDays` にそのまま渡せる。締め日がその月にない場合の読み替え(末日)は `closingMonth` と同じ内部関数で行い、期間が隙間も重なりもなく敷き詰められることをテストで確かめた
16
+ - 暦日と時刻(`"HH:mm"` または `"HH:mm:ss"`)からタイムゾーンでの瞬間を `Date` で返す `toInstant(date, time, timeZone)` と、営業日カレンダー・スケジュールのメソッド `instantOf(date, time)`(そのタイムゾーンで。合成したカレンダー・スケジュールからのカレンダーにも付く)を追加した。`civilOf`・`toDateTimeParts` の逆向き。夏時間で存在しない時刻は飛んだ分だけ後ろに、2 回ある時刻は先のほう(Temporal の `disambiguation: "compatible"` と同じ)。`Intl` だけで実装し、オフセットの差が 1 時間でないゾーン(`Australia/Lord_Howe`)と南半球(`Pacific/Auckland`)でも確かめた。受け付けるのは暦日の文字列だけ(`invalid-date`)。時刻の誤りは `invalid-time`
17
+
18
+ ### Changed
19
+
20
+ - README: 月のヘルパーの節に `closingPeriod` を、日付・日時の入力の節に `toInstant`・`instantOf` と夏時間の例を足した。サイズの値を測り直した(ルート約 9.3KB・日本の祝日込み約 11.1KB・英国の祝日込み約 11.1KB。0.14.0 で測定)
21
+ - `docs/decisions.md`: 39 番(`closingPeriod`)・40 番(`toInstant`)を追加した
22
+ - `src/core/schedule.ts` の `buildSchedule` の注釈の位置を直した(0.13.0 で関数の間に別の定義が入り、注釈が離れていた。動作は変わらない)
23
+
24
+ ### 開発
25
+
26
+ - サイズの上限(`size-limits.json`)を上げた。ルート 20,500 → 22,000、`./jp` 23,500 → 25,000、`./diagnose` 27,000 → 28,500(gzip)。`closingPeriod` と瞬間への変換(ルートで約 1.3KB)のため。0.13.0 で上限に近づいていた分も含めて余裕を持たせた
27
+
28
+ ## [0.13.0] - 2026-10-20
29
+
30
+ ### 移行
31
+
32
+ 動作は変わりません(スケジュールから営業日カレンダーを作る関数と、判定の理由の新しい値の追加。CI の改善)。版ごとの作業は [docs/migration.md](./docs/migration.md) にまとめた。
33
+
34
+ ### Added
35
+
36
+ - スケジュールから営業日カレンダーを作る `createCalendarFromSchedule(schedule, isOpen, { maxSearchDays? })` を追加した。`isOpen` が true を返す値の日を営業日とする通常のカレンダーを返し、営業時間表のようなスケジュールが唯一の設定になる。`isOpen` は値だけを受け取る純粋な関数(日付は渡さない。営業日の探索で繰り返し呼ぶため)。`dayInfo` の `reason` はスケジュールの `reason` と営業・休業の組み合わせで、`name`・`holiday`・`shiftedFrom`・`rulePath` はスケジュールの結果を引き継ぐ。祝日・タイムゾーン・`outOfRange` はスケジュールのもの。`createSchedule` が作ったスケジュール以外は `invalid-argument`
37
+ - 判定の理由(`DayReason`)に `"open-annual"`(スケジュールの `annual` の値で営業になる日)を追加した。`createCalendar` の結果には現れない(`closedAnnual` は休業だけ)
38
+
39
+ ### Changed
40
+
41
+ - README: 「スケジュールから営業日カレンダーを作る」の節を足した。型定義の確認の範囲を、CI で確かめる TypeScript の版(5.0・5.5・5.8・6.0・7.0)に改めた。サイズの値を測り直した(ルート約 9.0KB・日本の祝日込み約 10.8KB・英国の祝日込み約 10.7KB。0.13.0 で測定)
42
+ - `docs/decisions.md`: 38 番(スケジュールからのカレンダー・`"open-annual"`・利用者の TypeScript の版の確認)を追加した
43
+
44
+ ### 開発
45
+
46
+ - CI に `consumer-types` ジョブを追加した。公開する型定義を、利用者が使う TypeScript 5.0.4・5.5.4・5.8.3・7.0.2(ネイティブ版)のそれぞれで、`moduleResolution` の `node16`・`nodenext`・`bundler` で型チェックする。各版は依存にせず、版と SHA-256 を固定した tgz から一時ディレクトリに入れる(7.0 はランナー向けの実行形式 `@typescript/typescript-linux-x64` も固定)。`pnpm check` は従来どおり開発用の 6.0.3 で確かめる
47
+ - `scripts/check-consumer-types.ts` に `--tsc <path>` を足し、わざと型エラーを含む `test/consumer/consumer-error.mts` が各版で失敗として報告されること(検査が機能していること)も確かめるようにした。リポジトリの `@types` を読まないよう `--typeRoots` を空にした(古い TypeScript では `@types/node` の新しい構文を読めないため)。`--ignoreConfig` は 6.0 以降でだけ渡す
48
+ - `createCalendar` の `dayInfo` の変換を `createCalendarFromSchedule` と共用の内部関数に切り出した。結果は変わらない
49
+
7
50
  ## [0.12.0] - 2026-10-20
8
51
 
9
52
  ### 移行
@@ -330,7 +373,9 @@
330
373
 
331
374
  - 日本: 2026 年 2 月の官報(2027 年の春分・秋分の日)まで反映(`dataVersion: "2026-02"`、`confirmedThrough: 2027`)
332
375
 
333
- [Unreleased]: https://github.com/inohan77/bizdays-toolkit/compare/v0.12.0...HEAD
376
+ [Unreleased]: https://github.com/inohan77/bizdays-toolkit/compare/v0.14.0...HEAD
377
+ [0.14.0]: https://github.com/inohan77/bizdays-toolkit/compare/v0.13.0...v0.14.0
378
+ [0.13.0]: https://github.com/inohan77/bizdays-toolkit/compare/v0.12.0...v0.13.0
334
379
  [0.12.0]: https://github.com/inohan77/bizdays-toolkit/compare/v0.11.1...v0.12.0
335
380
  [0.11.1]: https://github.com/inohan77/bizdays-toolkit/compare/v0.11.0...v0.11.1
336
381
  [0.11.0]: https://github.com/inohan77/bizdays-toolkit/compare/v0.10.0...v0.11.0
package/README.md CHANGED
@@ -25,9 +25,10 @@ A business-day calendar that combines public holidays with company or store clos
25
25
  - **Option diagnostics**: `diagnoseCalendar` and `diagnoseSchedule` from `bizdays-toolkit/diagnose` list rules that can never apply, rules whose removal changes nothing, typos in option keys, calendars with no business day and more, without throwing. One line in your tests keeps a change of settings from silently killing a rule
26
26
  - **Month-based due dates**: due dates such as "closing on the 20th, paid on the 10th of the next month (next business day if closed)" or "the last business day of the month", with the four adjustment conventions used in finance (following, preceding, modified-following, modified-preceding)
27
27
  - **Business-day arithmetic**: closed weekdays, annual closures (including ranges across the new year), specific closed and open dates, and holidays combine to compute "N business days later", "next business day after the cut-off time" and more
28
+ - **A calendar from a schedule**: `createCalendarFromSchedule` turns a schedule such as store hours into a business-day calendar, so the hours are the only configuration and business-day arithmetic works on them
28
29
  - **Combining calendars**: `combineCalendars` builds a calendar of the days on which all of several calendars are open (your company and the bank, for a remittance date) or any of them is open (any of several stores), and business-day arithmetic works on the result
29
30
  - **Time-zone safe**: instants such as `Date` are converted to a civil date in the calendar's time zone (`Asia/Tokyo` for Japan, `Europe/London` for the UK) before evaluation. A server running in UTC does not treat 00:00–09:00 in Japan as the previous day
30
- - **Lightweight, zero dependencies**: about 8.8 KB min+gzip (about 10.6 KB with Japanese holidays, about 10.5 KB with UK bank holidays; measured for 0.12.0). ESM, bundled types and `sideEffects: false`. Written in standard JavaScript and `Intl` only (no Node.js APIs); CI tests it on Node.js, Chrome, Firefox, Edge, Safari and Cloudflare Workers
31
+ - **Lightweight, zero dependencies**: about 9.3 KB min+gzip (about 11.1 KB with Japanese holidays, about 11.1 KB with UK bank holidays; measured for 0.14.0). ESM, bundled types and `sideEffects: false`. Written in standard JavaScript and `Intl` only (no Node.js APIs); CI tests it on Node.js, Chrome, Firefox, Edge, Safari and Cloudflare Workers
31
32
  - **Extensible to other countries and regions**: holiday providers are pluggable through the `HolidayProvider` interface. Japan and the UK are bundled
32
33
 
33
34
  ## Installation
@@ -38,7 +39,7 @@ pnpm add bizdays-toolkit
38
39
 
39
40
  Node.js 22.12 or later. CI tests the package on Node.js 22.12, 22, 24 and 26, on Chrome, Firefox and Edge (Linux) and Safari (macOS), and on Cloudflare Workers (workerd, the open-source Workers runtime). The browsers are the latest stable versions on GitHub's runners, so their versions change as the runners are updated. The package is ESM only, but it can also be loaded from CommonJS with `require()` (tested in CI as well; on Node.js 22.12, `require()` prints an experimental-feature warning, which does not affect the result, and Node.js 26 prints none). Other runtimes (such as Deno, Bun or Vercel's Edge Runtime) are not tested.
40
41
 
41
- Types are bundled. CI type-checks a consumer project against the published type definitions with `moduleResolution` set to `node16`, `nodenext` and `bundler` (TypeScript 6); TypeScript 5.0, 5.5 and 5.8 were also checked by hand for 0.9.0.
42
+ Types are bundled. CI type-checks a consumer project against the published type definitions with TypeScript 5.0, 5.5, 5.8, 6.0 and 7.0 (the native compiler), each with `moduleResolution` set to `node16`, `nodenext` and `bundler`, and confirms that an intentional type error is reported by each.
42
43
 
43
44
  ## Usage
44
45
 
@@ -396,6 +397,15 @@ calendar.dueDate(monthOf(billing, 1), { day: -1, convention: "preceding" }); //
396
397
 
397
398
  - `monthOf(dateOrMonth, offset?)`: the month `offset` months after (before, if negative) a date or a month `"YYYY-MM"`
398
399
  - `closingMonth(date, closingDay)`: the month a date belongs to when months are closed on `closingDay` (1–31, `-1` for the last day). The day after a closing day up to the next closing day belongs to the month of the next closing day. If the closing day does not exist in a month (closing on the 31st in February), the last day is used
400
+ - `closingPeriod(monthOrDate, closingDay)`: the inverse: the period `{ from, to }` (both ends included) that belongs to the month, from the day after the previous closing day to the closing day. Given a date, the period that date belongs to. The result has the shape of a date range, so it can go straight into `closedDates` or `listBusinessDays`
401
+
402
+ ```ts
403
+ closingPeriod("2026-11", 20); // { from: "2026-10-21", to: "2026-11-20" }
404
+ closingPeriod("2026-03", 31); // { from: "2026-03-01", to: "2026-03-31" } (closing on the 31st in February means the 28th)
405
+ const { from, to } = closingPeriod("2026-11-05", 20); // the period "2026-11-05" belongs to
406
+ const office = createCalendar({ holidays: jp, closedWeekdays: [0, 6] });
407
+ office.listBusinessDays(from, to).length; // 22 (business days in the November period)
408
+ ```
399
409
 
400
410
  The `day` of `dueDate` also maps days that do not exist in a month (such as February 30) to the last day. Recurring rules (`{ day: 31 }`) do not match such days, so the two behave differently: a due date must always fall somewhere in its month.
401
411
 
@@ -450,6 +460,33 @@ const isOpen = hours !== null && hours.open <= time && time < hours.close;
450
460
 
451
461
  For inputs that always carry a time (a `Date`, Temporal `Instant`, `ZonedDateTime` or `PlainDateTime`, or a `"YYYY-MM-DDTHH:mm"` string), `time` is typed as `string`, so no `null` check is needed. `civilOf` is also on business-day calendars, and the same conversion is available as `toDateTimeParts(input, timeZone)` in the root. (`toJapanDate` and `toJapanDateTime` in `bizdays-toolkit/jp` are deprecated since 0.10.0: use `toDateString(input, "Asia/Tokyo")`, `toDateTimeParts(input, "Asia/Tokyo")` or `dateOf`/`civilOf` on a calendar instead. They will be removed in 1.0.0.)
452
462
 
463
+ ### A business-day calendar from a schedule
464
+
465
+ When the schedule (store hours, say) is the real configuration, `createCalendarFromSchedule(schedule, isOpen)` makes a business-day calendar from it, so you do not write a second set of rules to keep in sync. `isOpen` decides from the value alone whether the day is a business day; the result is an ordinary calendar with business-day arithmetic, `adjust`, `dueDate` and the rest.
466
+
467
+ ```ts
468
+ import { createCalendarFromSchedule } from "bizdays-toolkit";
469
+
470
+ const hours = createSchedule<Hours>({
471
+ holidays: jp,
472
+ weekly: [null, weekday, weekday, weekday, weekday, weekday, { open: "10:00", close: "17:00" }],
473
+ holiday: { sameAs: 0 },
474
+ annual: [
475
+ { from: "12-31", to: "01-03", value: null, name: "New Year closure" },
476
+ { date: "01-04", value: { open: "11:00", close: "15:00" }, name: "First day of the year" },
477
+ ],
478
+ });
479
+ const calendar = createCalendarFromSchedule(hours, (v) => v !== null);
480
+ calendar.addBusinessDays("2026-12-29", 2); // "2027-01-04"
481
+ calendar.dayInfo("2027-01-04");
482
+ // { date: "2027-01-04", weekday: 1, businessDay: true, reason: "open-annual", name: "First day of the year", rulePath: "annual[1]" }
483
+ ```
484
+
485
+ - `isOpen` must be a pure function of the value: it receives only the value (not the date), and the calendar calls it repeatedly while searching for business days, so a function that looks at the date, the time or outside state would make the result change from call to call. Conditions that depend on the date belong in the schedule's rules (`dates`, `recurring`)
486
+ - `dayInfo` maps the schedule's `reason` to the calendar's: `date` → `"open-date"`/`"closed-date"`, `annual` → `"open-annual"`/`"closed-annual"`, `recurring` → `"open-recurring"`/`"closed-recurring"`, `holiday` → `"holiday"` (whether or not the holiday is open, as with `holidayPolicy: "open"`), `weekday` → `"regular"`/`"closed-weekday"`. `"open-annual"` exists only for calendars made this way, since `closedAnnual` of `createCalendar` only closes. `name`, `holiday`, `shiftedFrom` and `rulePath` are the schedule's
487
+ - Holidays, the time zone and `outOfRange` are the schedule's. Diagnose the schedule's options with `diagnoseSchedule`; the calendar itself is not diagnosed. `maxSearchDays` (default 3660) can be given in the options
488
+ - Use `createCalendar` when you only need open or closed; use this when you have a schedule anyway
489
+
453
490
  ### Date and date-time inputs
454
491
 
455
492
  Every method accepts the following inputs. Returned dates are always `"YYYY-MM-DD"` strings.
@@ -467,6 +504,26 @@ Temporal objects are recognized by their shape, so the package does not depend o
467
504
 
468
505
  The calendar's time zone is the `timeZone` option, then the holiday provider's time zone, then `"UTC"`.
469
506
 
507
+ **From a civil date and time to an instant**: `toInstant(date, time, timeZone)` and `calendar.instantOf(date, time)` (also on schedules) go the other way from `civilOf`: a civil date `"YYYY-MM-DD"` and a time `"HH:mm"` or `"HH:mm:ss"` become a `Date` for that instant in the time zone. Only a date string is accepted (a `Date` would be ambiguous about which day it means), and the result is a `Date`, which is one line from an ISO string (`.toISOString()`) or a Temporal `Instant` (`Temporal.Instant.fromEpochMilliseconds(d.getTime())`).
508
+
509
+ ```ts
510
+ import { toInstant } from "bizdays-toolkit";
511
+
512
+ toInstant("2026-11-23", "10:00", "Asia/Tokyo").toISOString(); // "2026-11-23T01:00:00.000Z"
513
+ const store = createCalendar({ holidays: jp, closedWeekdays: [0] });
514
+ const opensAt = store.instantOf(store.nextBusinessDay(store.today()), "10:00"); // the next opening, as a Date
515
+ ```
516
+
517
+ Around daylight-saving changes the result follows Temporal's default (`disambiguation: "compatible"`): a time that does not exist (in the UK, 01:00–01:59 on the last Sunday of March) is moved forward by the length of the gap, and a time that occurs twice (01:00–01:59 on the last Sunday of October) is the earlier one.
518
+
519
+ ```ts
520
+ import { england } from "bizdays-toolkit/uk";
521
+
522
+ const uk = createCalendar({ holidays: england });
523
+ uk.instantOf("2026-03-29", "01:30").toISOString(); // "2026-03-29T01:30:00.000Z" (02:30 BST; 01:30 does not exist)
524
+ uk.instantOf("2026-10-25", "01:30").toISOString(); // "2026-10-25T00:30:00.000Z" (the first 01:30, still BST)
525
+ ```
526
+
470
527
  ### Holidays of other countries and regions
471
528
 
472
529
  Implement `HolidayProvider` and pass it as `holidays`. Several providers give their union (if their time zones differ, `timeZone` is required).
@@ -22,7 +22,7 @@ import { type DateString, type Weekday } from "./date.ts";
22
22
  import { IssueCollector } from "./errors.ts";
23
23
  import { type DateInput } from "./input.ts";
24
24
  import { type MonthString } from "./month.ts";
25
- import { type CompiledSchedule, type DayOfMonth, type EffectivePeriod, type RecurringRule, type HolidayLookup, type HolidaySourceOptions } from "./schedule.ts";
25
+ import { type CompiledSchedule, type DayOfMonth, type EffectivePeriod, type RecurringRule, type HolidayLookup, type HolidaySourceOptions, type Schedule } from "./schedule.ts";
26
26
  import type { Holiday } from "./types.ts";
27
27
  /**
28
28
  * 祝日の扱い。
@@ -93,7 +93,7 @@ export interface CalendarOptions<Kind extends string = string> extends HolidaySo
93
93
  * 営業・休業を決めた規則(既知の値)。
94
94
  * @public
95
95
  */
96
- export type KnownDayReason = "open-date" | "closed-date" | "closed-annual" | "open-recurring" | "closed-recurring" | "holiday" | "closed-weekday" | "regular";
96
+ export type KnownDayReason = "open-date" | "closed-date" | "open-annual" | "closed-annual" | "open-recurring" | "closed-recurring" | "holiday" | "closed-weekday" | "regular";
97
97
  /**
98
98
  * 営業・休業を決めた規則。将来の版で値が増えることがあるので、分岐では「その他」も扱うこと。
99
99
  * すべての値を網羅したことを型で確かめたい場合は KnownDayReason を使う。
@@ -255,4 +255,21 @@ export declare function createCalendar<Kind extends string = string>(options?: C
255
255
  * @public
256
256
  */
257
257
  export declare function combineCalendars<Kind extends string = string>(calendars: readonly Calendar<Kind>[], options: CombineOptions): Calendar<Kind>;
258
+ /**
259
+ * スケジュール(createSchedule)から営業日カレンダーを作る。isOpen が true を返す値の日を営業日とする。
260
+ * 営業時間表のような日ごとの値が設定の正本で、営業日の計算(加減算・調整・期日など)も同じ設定から行いたいときに使う
261
+ * (営業日カレンダーを別に書いて同期を取る必要がなくなる)。
262
+ *
263
+ * - isOpen は値だけで決まる純粋な関数であること(日付・時刻・外部の状態を見ない)。営業日の探索は isOpen を繰り返し呼ぶので、
264
+ * 結果が変わる関数を渡すと探索の結果が呼ぶたびに変わる。日付で変えたい条件は、スケジュールの規則(dates・recurring)に書く
265
+ * - dayInfo の reason は、スケジュールの reason と営業・休業の組み合わせ(date → "open-date"/"closed-date"、annual → "open-annual"/
266
+ * "closed-annual"、recurring → "open-recurring"/"closed-recurring"、holiday → "holiday"、weekday → "regular"/"closed-weekday")。
267
+ * name・holiday・shiftedFrom・rulePath はスケジュールの結果をそのまま引き継ぐ
268
+ * - 祝日の判定(holiday・isHoliday など)・タイムゾーン・outOfRange はスケジュールのもの。規則の診断(diagnoseSchedule)は
269
+ * スケジュールの設定に対して行う
270
+ * @public
271
+ */
272
+ export declare function createCalendarFromSchedule<T, Kind extends string = string>(schedule: Schedule<T, Kind>, isOpen: (value: T) => boolean, options?: {
273
+ readonly maxSearchDays?: number;
274
+ }): Calendar<Kind>;
258
275
  export {};
@@ -22,7 +22,7 @@ import { addDays, daysInMonth, formatDate, fromDayNumber, toDayNumber, } from ".
22
22
  import { checkUnknownKeys, IssueCollector, plainError, rangeError } from "./errors.js";
23
23
  import { parseTimeOfDay, toCivil } from "./input.js";
24
24
  import { dayOfMonth, isDayOfMonthValue, parseMonth } from "./month.js";
25
- import { buildSchedule, compileAnnualRules, compileDateRules, compileHolidaySource, compileRecurringRules, createHolidayLookup, isWeekday, mapDays, RECURRING_RULE_KEYS, } from "./schedule.js";
25
+ import { buildSchedule, compileAnnualRules, compileDateRules, compileHolidaySource, compileRecurringRules, createHolidayLookup, infoOfSchedule, isWeekday, mapDays, RECURRING_RULE_KEYS, } from "./schedule.js";
26
26
  const CALENDAR_OPTION_KEYS = [
27
27
  "holidays",
28
28
  "timeZone",
@@ -100,54 +100,62 @@ export function createCalendar(options = {}) {
100
100
  c.throwFirstError();
101
101
  const { maxSearchDays } = compiled;
102
102
  const schedule = buildSchedule(compiled.schedule);
103
- function info(date) {
103
+ const info = (date) => {
104
104
  const day = schedule.dayInfo(date);
105
- let reason;
106
- // 内部では閉じた型(KnownScheduleReason)で分岐し、値が増えたときの対応漏れを型で検出する
107
- const known = day.reason;
108
- switch (known) {
109
- case "date":
110
- reason = day.value ? "open-date" : "closed-date";
111
- break;
112
- case "annual":
113
- reason = "closed-annual";
114
- break;
115
- case "recurring":
116
- reason = day.value ? "open-recurring" : "closed-recurring";
117
- break;
118
- case "holiday":
119
- reason = "holiday";
120
- break;
121
- case "weekday":
122
- reason = day.value ? "regular" : "closed-weekday";
123
- break;
124
- default: {
125
- const unreachable = known;
126
- throw plainError("invalid-option", `Unexpected schedule reason: ${String(unreachable)}`);
127
- }
105
+ return dayInfoFromScheduleDay(day, day.value);
106
+ };
107
+ return buildCalendar(schedule, (date) => schedule.valueOn(date), info, maxSearchDays);
108
+ }
109
+ /**
110
+ * @internal スケジュールの 1 日分の結果(値は営業日か)を、営業日カレンダーの結果に変換する。
111
+ * reason はスケジュールの reason と営業・休業の組み合わせで決まる。createCalendar の closedAnnual は休業だけなので
112
+ * "open-annual" にはならないが、createCalendarFromSchedule では annual の値で営業になる日がある
113
+ */
114
+ function dayInfoFromScheduleDay(day, open) {
115
+ let reason;
116
+ // 内部では閉じた型(KnownScheduleReason)で分岐し、値が増えたときの対応漏れを型で検出する
117
+ const known = day.reason;
118
+ switch (known) {
119
+ case "date":
120
+ reason = open ? "open-date" : "closed-date";
121
+ break;
122
+ case "annual":
123
+ reason = open ? "open-annual" : "closed-annual";
124
+ break;
125
+ case "recurring":
126
+ reason = open ? "open-recurring" : "closed-recurring";
127
+ break;
128
+ case "holiday":
129
+ reason = "holiday";
130
+ break;
131
+ case "weekday":
132
+ reason = open ? "regular" : "closed-weekday";
133
+ break;
134
+ default: {
135
+ const unreachable = known;
136
+ throw plainError("invalid-option", `Unexpected schedule reason: ${String(unreachable)}`);
128
137
  }
129
- const result = {
130
- date: day.date,
131
- weekday: day.weekday,
132
- businessDay: day.value,
133
- reason,
134
- };
135
- // 曜日で決まった日には名前を付けない(祝日名は holiday で分かる)
136
- if (day.name !== undefined && day.reason !== "weekday")
137
- result.name = day.name;
138
- if (day.holiday !== undefined)
139
- result.holiday = day.holiday;
140
- if (day.shiftedFrom !== undefined)
141
- result.shiftedFrom = day.shiftedFrom;
142
- if (day.rulePath !== undefined)
143
- result.rulePath = day.rulePath;
144
- return Object.freeze(result);
145
138
  }
146
- return buildCalendar(schedule, (date) => schedule.valueOn(date), info, maxSearchDays);
139
+ const result = {
140
+ date: day.date,
141
+ weekday: day.weekday,
142
+ businessDay: open,
143
+ reason,
144
+ };
145
+ // 曜日で決まった日には名前を付けない(祝日名は holiday で分かる)
146
+ if (day.name !== undefined && day.reason !== "weekday")
147
+ result.name = day.name;
148
+ if (day.holiday !== undefined)
149
+ result.holiday = day.holiday;
150
+ if (day.shiftedFrom !== undefined)
151
+ result.shiftedFrom = day.shiftedFrom;
152
+ if (day.rulePath !== undefined)
153
+ result.rulePath = day.rulePath;
154
+ return Object.freeze(result);
147
155
  }
148
156
  /**
149
157
  * @internal 祝日を調べる機能と 1 日分の判定から、営業日カレンダーの機能(探索・調整・月の営業日・期日)を組み立てる。
150
- * createCalendar と combineCalendars で共用する
158
+ * createCalendar・combineCalendars・createCalendarFromSchedule で共用する
151
159
  */
152
160
  function buildCalendar(lookup, isOpen, info, maxSearchDays) {
153
161
  const dateOf = lookup.dateOf;
@@ -241,6 +249,7 @@ function buildCalendar(lookup, isOpen, info, maxSearchDays) {
241
249
  outOfRange: lookup.outOfRange,
242
250
  dateOf,
243
251
  civilOf: lookup.civilOf,
252
+ instantOf: lookup.instantOf,
244
253
  today: lookup.today,
245
254
  isHoliday: lookup.isHoliday,
246
255
  getHoliday: lookup.getHoliday,
@@ -386,3 +395,36 @@ export function combineCalendars(calendars, options) {
386
395
  }
387
396
  return buildCalendar(lookup, isOpen, info, maxSearchDays);
388
397
  }
398
+ /**
399
+ * スケジュール(createSchedule)から営業日カレンダーを作る。isOpen が true を返す値の日を営業日とする。
400
+ * 営業時間表のような日ごとの値が設定の正本で、営業日の計算(加減算・調整・期日など)も同じ設定から行いたいときに使う
401
+ * (営業日カレンダーを別に書いて同期を取る必要がなくなる)。
402
+ *
403
+ * - isOpen は値だけで決まる純粋な関数であること(日付・時刻・外部の状態を見ない)。営業日の探索は isOpen を繰り返し呼ぶので、
404
+ * 結果が変わる関数を渡すと探索の結果が呼ぶたびに変わる。日付で変えたい条件は、スケジュールの規則(dates・recurring)に書く
405
+ * - dayInfo の reason は、スケジュールの reason と営業・休業の組み合わせ(date → "open-date"/"closed-date"、annual → "open-annual"/
406
+ * "closed-annual"、recurring → "open-recurring"/"closed-recurring"、holiday → "holiday"、weekday → "regular"/"closed-weekday")。
407
+ * name・holiday・shiftedFrom・rulePath はスケジュールの結果をそのまま引き継ぐ
408
+ * - 祝日の判定(holiday・isHoliday など)・タイムゾーン・outOfRange はスケジュールのもの。規則の診断(diagnoseSchedule)は
409
+ * スケジュールの設定に対して行う
410
+ * @public
411
+ */
412
+ export function createCalendarFromSchedule(schedule, isOpen, options) {
413
+ const info = infoOfSchedule(schedule);
414
+ if (info === undefined) {
415
+ throw rangeError("invalid-argument", "schedule must be a schedule created by createSchedule");
416
+ }
417
+ if (typeof isOpen !== "function") {
418
+ throw rangeError("invalid-argument", "isOpen must be a function (value) => boolean");
419
+ }
420
+ const maxSearchDays = options?.maxSearchDays ?? 3660;
421
+ if (!Number.isInteger(maxSearchDays) || maxSearchDays < 1) {
422
+ throw rangeError("invalid-option", "maxSearchDays must be a positive integer");
423
+ }
424
+ const open = (date) => isOpen(info(date).value) === true;
425
+ return buildCalendar(schedule, open, (date) => {
426
+ const day = info(date);
427
+ // 変換は value を読まない(営業・休業は open で渡す)ので、boolean の値として扱ってよい
428
+ return dayInfoFromScheduleDay(day, isOpen(day.value) === true);
429
+ }, maxSearchDays);
430
+ }
@@ -82,5 +82,21 @@ export declare function toDateString(input: DateInput, timeZone: string): DateSt
82
82
  export declare function toDateTimeParts(input: DateTimeInput, timeZone: string): CivilDateTimeParts<string>;
83
83
  /** @public */
84
84
  export declare function toDateTimeParts(input: DateInput, timeZone: string): CivilDateTimeParts;
85
+ /**
86
+ * @internal 暦日と時刻(0 時からの経過分)から、タイムゾーンでの瞬間(エポックミリ秒)を求める。
87
+ * 夏時間の扱いは Temporal の disambiguation: "compatible" と同じ。存在しない時刻(飛び)は切り替え前のオフセットで解釈して
88
+ * 飛んだ分だけ後ろの瞬間に、2 回ある時刻(重複)は先のほう(切り替え前のオフセット)にする。
89
+ * Intl 以外に依存しないよう、前後 1 日のオフセットを候補にして、暦日に戻して一致するものを選ぶ
90
+ */
91
+ export declare function civilToInstant(date: DateString, minutes: number, timeZone: string): number;
92
+ /** @internal "HH:mm" または "HH:mm:ss" を 0 時からの経過秒に変換する(00:00:00〜23:59:59) */
93
+ export declare function parseTimeOfDaySeconds(value: unknown): number;
94
+ /**
95
+ * 暦日と時刻("HH:mm" または "HH:mm:ss")から、タイムゾーンでのその瞬間を Date で返す(civilOf・toDateTimeParts の逆向き)。
96
+ * 夏時間の切り替えで存在しない時刻は、飛んだ分だけ後ろの瞬間(英国の 3 月の 01:30 は 02:30 BST)、2 回ある時刻は先のほう
97
+ * (Temporal の disambiguation: "compatible" と同じ)。
98
+ * @public
99
+ */
100
+ export declare function toInstant(date: DateString, time: string, timeZone: string): Date;
85
101
  /** @internal "HH:mm" を 0 時からの経過分に変換する(00:00〜23:59) */
86
102
  export declare function parseTimeOfDay(value: string): number;
@@ -143,6 +143,56 @@ export function toDateTimeParts(input, timeZone) {
143
143
  : `${String(Math.floor(civil.minutes / 60)).padStart(2, "0")}:${String(civil.minutes % 60).padStart(2, "0")}`;
144
144
  return Object.freeze({ date: civil.date, time });
145
145
  }
146
+ /**
147
+ * @internal 暦日と時刻(0 時からの経過分)から、タイムゾーンでの瞬間(エポックミリ秒)を求める。
148
+ * 夏時間の扱いは Temporal の disambiguation: "compatible" と同じ。存在しない時刻(飛び)は切り替え前のオフセットで解釈して
149
+ * 飛んだ分だけ後ろの瞬間に、2 回ある時刻(重複)は先のほう(切り替え前のオフセット)にする。
150
+ * Intl 以外に依存しないよう、前後 1 日のオフセットを候補にして、暦日に戻して一致するものを選ぶ
151
+ */
152
+ export function civilToInstant(date, minutes, timeZone) {
153
+ const { year, month, day } = parseDate(date);
154
+ const wall = Date.UTC(year, month - 1, day, Math.floor(minutes / 60), minutes % 60);
155
+ const offsetAt = (ms) => {
156
+ const civil = instantToCivil(ms, timeZone);
157
+ const c = parseDate(civil.date);
158
+ const m = civil.minutes ?? 0; // 瞬間からの変換では時刻が必ずある
159
+ return Date.UTC(c.year, c.month - 1, c.day, Math.floor(m / 60), m % 60) - ms;
160
+ };
161
+ const before = offsetAt(wall - 86_400_000);
162
+ const after = offsetAt(wall + 86_400_000);
163
+ const valid = (ms) => {
164
+ const civil = instantToCivil(ms, timeZone);
165
+ return civil.date === date && civil.minutes === minutes;
166
+ };
167
+ const candidates = before === after ? [wall - before] : [wall - before, wall - after];
168
+ const found = candidates.filter(valid);
169
+ // 重複なら先のほう(小さいミリ秒)、飛びなら切り替え前のオフセット(before)で解釈した瞬間
170
+ return found.length > 0 ? Math.min(...found) : wall - before;
171
+ }
172
+ /** @internal "HH:mm" または "HH:mm:ss" を 0 時からの経過秒に変換する(00:00:00〜23:59:59) */
173
+ export function parseTimeOfDaySeconds(value) {
174
+ const m = typeof value === "string" ? /^(\d{2}):(\d{2})(?::(\d{2}))?$/.exec(value) : null;
175
+ const seconds = m ? Number(m[3] ?? "0") : NaN;
176
+ if (!m || seconds > 59) {
177
+ throw rangeError("invalid-time", `Invalid time of day: ${JSON.stringify(value)} (expected HH:mm or HH:mm:ss)`);
178
+ }
179
+ return wallTime(Number(m[1]), Number(m[2])) * 60 + seconds;
180
+ }
181
+ /**
182
+ * 暦日と時刻("HH:mm" または "HH:mm:ss")から、タイムゾーンでのその瞬間を Date で返す(civilOf・toDateTimeParts の逆向き)。
183
+ * 夏時間の切り替えで存在しない時刻は、飛んだ分だけ後ろの瞬間(英国の 3 月の 01:30 は 02:30 BST)、2 回ある時刻は先のほう
184
+ * (Temporal の disambiguation: "compatible" と同じ)。
185
+ * @public
186
+ */
187
+ export function toInstant(date, time, timeZone) {
188
+ const zone = validateTimeZone(timeZone);
189
+ if (typeof date !== "string")
190
+ throw typeError("invalid-date", `Invalid date: ${String(date)}`);
191
+ parseDate(date);
192
+ const seconds = parseTimeOfDaySeconds(time);
193
+ const ms = civilToInstant(date, Math.floor(seconds / 60), zone) + (seconds % 60) * 1000;
194
+ return new Date(ms);
195
+ }
146
196
  /** @internal "HH:mm" を 0 時からの経過分に変換する(00:00〜23:59) */
147
197
  export function parseTimeOfDay(value) {
148
198
  const m = /^(\d{2}):(\d{2})$/.exec(value);
@@ -48,3 +48,20 @@ export declare function monthOf(input: DateString | MonthString, offset?: number
48
48
  * @public
49
49
  */
50
50
  export declare function closingMonth(date: DateString, closingDay: number): MonthString;
51
+ /**
52
+ * 締め日で区切ったときの、その月分の期間(両端を含む暦日)。closingMonth の逆算。
53
+ *
54
+ * 前月の締め日の翌日から、その月の締め日まで。月の代わりに暦日を渡すと、その日が属する期間(closingMonth で求めた月の期間)。
55
+ * 返す値は変更できず、name は付かない(DateRange の形なので、そのまま closedDates などに渡せる)。
56
+ *
57
+ * @example
58
+ * closingPeriod("2026-11", 20); // { from: "2026-10-21", to: "2026-11-20" }
59
+ * closingPeriod("2026-10", -1); // { from: "2026-10-01", to: "2026-10-31" }(末日締め)
60
+ * closingPeriod("2026-03", 31); // { from: "2026-03-01", to: "2026-03-31" }(2 月の 31 日締めは 2 月末日)
61
+ * closingPeriod("2026-11-05", 20); // { from: "2026-10-21", to: "2026-11-20" }(この日が属する期間)
62
+ * @public
63
+ */
64
+ export declare function closingPeriod(input: DateString | MonthString, closingDay: number): {
65
+ readonly from: DateString;
66
+ readonly to: DateString;
67
+ };
@@ -4,7 +4,7 @@
4
4
  * 営業日を考えない暦の計算なので、カレンダーなしで使える。営業日を考えた月の計算
5
5
  * (月の第 n 営業日・期日)は営業日カレンダーのメソッドにある。
6
6
  */
7
- import { daysInMonth, formatDate, parseDate } from "./date.js";
7
+ import { addDays, daysInMonth, formatDate, parseDate } from "./date.js";
8
8
  import { rangeError } from "./errors.js";
9
9
  const MONTH_RE = /^(\d{4})-(\d{2})$/;
10
10
  /** @internal "YYYY-MM" を年と月に分解する(誤りは code: "invalid-month") */
@@ -67,10 +67,40 @@ export function monthOf(input, offset = 0) {
67
67
  * @public
68
68
  */
69
69
  export function closingMonth(date, closingDay) {
70
+ checkClosingDay(closingDay);
71
+ const { year, month, day } = parseDate(date);
72
+ return formatMonth(shiftMonth({ year, month }, day <= closingDayIn({ year, month }, closingDay) ? 0 : 1));
73
+ }
74
+ function checkClosingDay(closingDay) {
70
75
  if (!isDayOfMonthValue(closingDay)) {
71
76
  throw rangeError("invalid-argument", `closingDay must be an integer from 1 to 31, or -1 (last day): ${closingDay}`);
72
77
  }
73
- const { year, month, day } = parseDate(date);
74
- const closing = closingDay === -1 ? daysInMonth(year, month) : closingDay;
75
- return formatMonth(shiftMonth({ year, month }, day <= closing ? 0 : 1));
78
+ }
79
+ /** その月の締め日(日)。-1 またはその月の日数以上なら末日(decisions.md の 16 番の読み替えはここだけで行う) */
80
+ function closingDayIn({ year, month }, closingDay) {
81
+ const last = daysInMonth(year, month);
82
+ return closingDay === -1 || closingDay > last ? last : closingDay;
83
+ }
84
+ /**
85
+ * 締め日で区切ったときの、その月分の期間(両端を含む暦日)。closingMonth の逆算。
86
+ *
87
+ * 前月の締め日の翌日から、その月の締め日まで。月の代わりに暦日を渡すと、その日が属する期間(closingMonth で求めた月の期間)。
88
+ * 返す値は変更できず、name は付かない(DateRange の形なので、そのまま closedDates などに渡せる)。
89
+ *
90
+ * @example
91
+ * closingPeriod("2026-11", 20); // { from: "2026-10-21", to: "2026-11-20" }
92
+ * closingPeriod("2026-10", -1); // { from: "2026-10-01", to: "2026-10-31" }(末日締め)
93
+ * closingPeriod("2026-03", 31); // { from: "2026-03-01", to: "2026-03-31" }(2 月の 31 日締めは 2 月末日)
94
+ * closingPeriod("2026-11-05", 20); // { from: "2026-10-21", to: "2026-11-20" }(この日が属する期間)
95
+ * @public
96
+ */
97
+ export function closingPeriod(input, closingDay) {
98
+ checkClosingDay(closingDay);
99
+ const month = typeof input === "string" && input.split("-").length === 3
100
+ ? parseMonth(closingMonth(input, closingDay))
101
+ : parseMonth(input);
102
+ const previous = shiftMonth(month, -1);
103
+ const to = dayOfMonth(month, closingDayIn(month, closingDay));
104
+ const from = addDays(dayOfMonth(previous, closingDayIn(previous, closingDay)), 1);
105
+ return Object.freeze({ from, to });
76
106
  }
@@ -283,6 +283,11 @@ export interface HolidayLookup<Kind extends string = string> {
283
283
  /** 入力をタイムゾーンでの暦日と時刻に変換する */
284
284
  civilOf(input: DateTimeInput): CivilDateTimeParts<string>;
285
285
  civilOf(input: DateInput): CivilDateTimeParts;
286
+ /**
287
+ * 暦日 "YYYY-MM-DD" と時刻("HH:mm" または "HH:mm:ss")から、タイムゾーンでのその瞬間を Date で返す(civilOf の逆向き)。
288
+ * 夏時間で存在しない時刻は飛んだ分だけ後ろに、2 回ある時刻は先のほう(toInstant と同じ)
289
+ */
290
+ instantOf(date: DateString, time: string): Date;
286
291
  /** 今日の日付(タイムゾーン) */
287
292
  today(now?: Date): DateString;
288
293
  /** 祝日か */
@@ -429,6 +434,8 @@ type HolidayLookupInternal<Kind extends string> = ReturnType<typeof createHolida
429
434
  export declare function createResolver<T, Kind extends string>(compiled: CompiledSchedule<T, Kind>, lookup: HolidayLookupInternal<Kind>): (date: DateString) => Resolution<T, Kind>;
430
435
  /** @internal 期間(両端を含む)の日ごとに fn を呼んだ結果。from が to より後ならエラー */
431
436
  export declare function mapDays<R>(from: DateString, to: DateString, fn: (date: DateString) => R): readonly R[];
437
+ /** @internal スケジュールの内部の判定を取り出す(createSchedule が作ったものでなければ undefined) */
438
+ export declare function infoOfSchedule<T, Kind extends string>(schedule: Schedule<T, Kind>): ((date: DateString) => ScheduleDay<T, Kind>) | undefined;
432
439
  /** @internal 検証済みの規則からスケジュールを作る */
433
440
  export declare function buildSchedule<T, Kind extends string>(compiled: CompiledSchedule<T, Kind>): Schedule<T, Kind>;
434
441
  /**
@@ -19,7 +19,7 @@
19
19
  */
20
20
  import { addDays, daysInMonth, fromDayNumber, isValidDate, parseDate, toDayNumber, weekdayOf, } from "./date.js";
21
21
  import { checkUnknownKeys, IssueCollector, rangeError } from "./errors.js";
22
- import { instantToCivil, toCivil, toDateTimeParts, validateTimeZone, } from "./input.js";
22
+ import { instantToCivil, toCivil, toDateTimeParts, toInstant, validateTimeZone, } from "./input.js";
23
23
  // ------------------------------------------------------------
24
24
  // 入力チェック(誤りを集める。作成時は最初の誤りを例外にする)
25
25
  // ------------------------------------------------------------
@@ -577,6 +577,7 @@ export function createHolidayLookup(source) {
577
577
  holidayOn,
578
578
  dateOf,
579
579
  civilOf: ((input) => toDateTimeParts(input, timeZone)),
580
+ instantOf: (date, time) => toInstant(date, time, timeZone),
580
581
  today: (now = new Date()) => instantToCivil(now.getTime(), timeZone).date,
581
582
  isHoliday: (input) => holidayOn(dateOf(input)) !== undefined,
582
583
  getHoliday: (input) => holidayOn(dateOf(input)),
@@ -773,6 +774,15 @@ export function mapDays(from, to, fn) {
773
774
  result.push(fn(fromDayNumber(n)));
774
775
  return Object.freeze(result);
775
776
  }
777
+ /**
778
+ * @internal スケジュールの内部の判定(暦日の文字列を直接受け取る)。createCalendarFromSchedule が、公開メソッド
779
+ * (入力の解析を通る)を経由せずに 1 日分の結果を得るために使う。スケジュールごとに作成時に登録する
780
+ */
781
+ const internalInfo = new WeakMap();
782
+ /** @internal スケジュールの内部の判定を取り出す(createSchedule が作ったものでなければ undefined) */
783
+ export function infoOfSchedule(schedule) {
784
+ return internalInfo.get(schedule);
785
+ }
776
786
  /** @internal 検証済みの規則からスケジュールを作る */
777
787
  export function buildSchedule(compiled) {
778
788
  const lookup = createHolidayLookup(compiled.source);
@@ -784,6 +794,7 @@ export function buildSchedule(compiled) {
784
794
  outOfRange: lookup.outOfRange,
785
795
  dateOf: lookup.dateOf,
786
796
  civilOf: lookup.civilOf,
797
+ instantOf: lookup.instantOf,
787
798
  today: lookup.today,
788
799
  isHoliday: lookup.isHoliday,
789
800
  getHoliday: lookup.getHoliday,
@@ -793,7 +804,9 @@ export function buildSchedule(compiled) {
793
804
  dayInfo: (input) => info(lookup.dateOf(input)),
794
805
  daysBetween: (from, to) => mapDays(lookup.dateOf(from), lookup.dateOf(to), info),
795
806
  };
796
- return Object.freeze(schedule);
807
+ Object.freeze(schedule);
808
+ internalInfo.set(schedule, info);
809
+ return schedule;
797
810
  }
798
811
  /**
799
812
  * 曜日・祝日・特定日の規則から、日ごとに値を返すスケジュールを作る。
package/dist/index.d.ts CHANGED
@@ -7,10 +7,10 @@
7
7
  * 公開する API には TSDoc の @public(安定)または @beta(マイナー版で変わりうる)を付ける。
8
8
  * 公開する名前と型は etc/api.md に記録し、pnpm check で意図しない変化を検出する。
9
9
  */
10
- export { combineCalendars, createCalendar, type AdjustOptions, type AnnualDate, type AnnualRange, type BusinessDayConvention, type BusinessDayOptions, type Calendar, type CalendarOptions, type CombineOptions, type DateRange, type DayInfo, type DayReason, type DueDateOptions, type HolidayPolicy, type KnownDayReason, type SpecificDate, } from "./core/calendar.ts";
10
+ export { combineCalendars, createCalendar, createCalendarFromSchedule, type AdjustOptions, type AnnualDate, type AnnualRange, type BusinessDayConvention, type BusinessDayOptions, type Calendar, type CalendarOptions, type CombineOptions, type DateRange, type DayInfo, type DayReason, type DueDateOptions, type HolidayPolicy, type KnownDayReason, type SpecificDate, } from "./core/calendar.ts";
11
11
  export { createSchedule, type AnnualRangeValue, type AnnualValue, type CivilDateTimeParts, type DateRangeValue, type DateValue, type DayAfterHolidayPattern, type DayOfMonth, type DayOfMonthPattern, type EffectivePeriod, type HolidayLookup, type HolidayPattern, type HolidaySourceOptions, type HolidayValueRule, type KnownScheduleReason, type Month, type Nth, type OnHolidayRule, type RecurringPattern, type RecurringRule, type RecurringValue, type Schedule, type ScheduleDay, type ScheduleOptions, type ScheduleReason, type WeekdayPattern, } from "./core/schedule.ts";
12
12
  export { addDays, diffDays, isValidDate, weekdayOf, type DateString, type Weekday, } from "./core/date.ts";
13
- export { closingMonth, monthOf, type MonthString } from "./core/month.ts";
13
+ export { closingMonth, closingPeriod, monthOf, type MonthString } from "./core/month.ts";
14
14
  export { isBizdaysError, type ErrorCode, type KnownErrorCode } from "./core/errors.ts";
15
- export { toDateString, toDateTimeParts, type DateInput, type DateTimeInput, type TemporalDateLike, type TemporalDateTimeLike, type TemporalInstantLike, } from "./core/input.ts";
15
+ export { toDateString, toDateTimeParts, toInstant, type DateInput, type DateTimeInput, type TemporalDateLike, type TemporalDateTimeLike, type TemporalInstantLike, } from "./core/input.ts";
16
16
  export type { Holiday, HolidayProvider } from "./core/types.ts";
package/dist/index.js CHANGED
@@ -7,9 +7,9 @@
7
7
  * 公開する API には TSDoc の @public(安定)または @beta(マイナー版で変わりうる)を付ける。
8
8
  * 公開する名前と型は etc/api.md に記録し、pnpm check で意図しない変化を検出する。
9
9
  */
10
- export { combineCalendars, createCalendar, } from "./core/calendar.js";
10
+ export { combineCalendars, createCalendar, createCalendarFromSchedule, } from "./core/calendar.js";
11
11
  export { createSchedule, } from "./core/schedule.js";
12
12
  export { addDays, diffDays, isValidDate, weekdayOf, } from "./core/date.js";
13
- export { closingMonth, monthOf } from "./core/month.js";
13
+ export { closingMonth, closingPeriod, monthOf } from "./core/month.js";
14
14
  export { isBizdaysError } from "./core/errors.js";
15
- export { toDateString, toDateTimeParts, } from "./core/input.js";
15
+ export { toDateString, toDateTimeParts, toInstant, } from "./core/input.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bizdays-toolkit",
3
- "version": "0.12.0",
3
+ "version": "0.14.0",
4
4
  "description": "Holidays, business-day calendar and day-by-day schedules (e.g. store hours) with time zone support. Japanese holidays verified against the Cabinet Office data; UK bank holidays (England, Wales, Scotland, Northern Ireland) verified against GOV.UK. / 祝日と営業日のカレンダー(タイムゾーン対応・日本の祝日は内閣府、英国の bank holidays は GOV.UK のデータで全日照合)",
5
5
  "keywords": [
6
6
  "bank-holidays",