bizdays-toolkit 0.8.0 → 0.9.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 +50 -1
- package/README.md +40 -6
- package/dist/core/calendar.d.ts +2 -0
- package/dist/core/calendar.js +2 -1
- package/dist/core/input.d.ts +28 -4
- package/dist/core/input.js +0 -4
- package/dist/core/schedule.d.ts +11 -13
- package/dist/core/schedule.js +13 -2
- package/dist/index.d.ts +1 -1
- package/dist/jp/index.d.ts +5 -5
- package/dist/jp/index.js +0 -4
- package/package.json +4 -3
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,53 @@
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.9.0] - 2026-10-18
|
|
8
|
+
|
|
9
|
+
### 移行
|
|
10
|
+
|
|
11
|
+
作業は要りません(機能の追加だけ)。時刻を必ず持つ入力では `time` の型が `string` になったので、これまでの `null` の分岐は不要になります(残しても動く)。版ごとの作業は [docs/migration.md](./docs/migration.md) にまとめた。
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- 期間の日ごとの情報を返す `daysBetween(from, to)` を、スケジュール(`ScheduleDay` の配列)と営業日カレンダー(`DayInfo` の配列)に追加した。両端を含み、`from` が `to` より後なら `invalid-range`。祝日だけ欲しい場合は、結果を `holiday` で絞る
|
|
16
|
+
- 時刻を必ず持つ入力の型 `DateTimeInput`(`Date`・Temporal の `Instant`・`ZonedDateTime`・`PlainDateTime`・`"YYYY-MM-DDTHH:mm…"` の文字列)と、`TemporalDateTimeLike` を追加した
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
|
|
20
|
+
- `civilOf`(スケジュール・営業日カレンダー)・`toDateTimeParts`・`toJapanDateTime` に、`DateTimeInput` を渡したときは `time` の型を `string` とするオーバーロードを加えた。返す値は変わらない。`CivilDateTimeParts` は時刻の型を引数に取る型になった(省略時はこれまでと同じ `string | null`)
|
|
21
|
+
- README: スケジュールの `dayInfo` の `reason` は値を決めた規則であり、祝日の規則が `"weekday"` のときは祝日でも `"weekday"` になること(祝日かどうかは `holiday` で判定する)を書いた。`createCalendar`・`createSchedule` は作ったものを使い回すのが基本で、作成のコストも小さいこと(測った値)を書いた。1 つの配列で持つ特別営業日を `dates` と `annual` に振り分ける例と、型定義の確認の範囲(CI で `moduleResolution` の `node16`・`nodenext`・`bundler`、0.9.0 の時点で TypeScript 5.0・5.5・5.8 も手作業で確認)を足した
|
|
22
|
+
- README のサイズの値を測り直した(ルート約 7.5KB・日本の祝日込み約 9.0KB・英国の祝日込み約 9.1KB。0.9.0 で測定)
|
|
23
|
+
- 移行ガイド(`docs/migration.md`)を追加した。0.2.0〜0.9.0 で利用者がする作業を版ごとにまとめた
|
|
24
|
+
|
|
25
|
+
### 開発
|
|
26
|
+
|
|
27
|
+
- `pnpm check` で、利用者のプロジェクトとして公開する型定義を型チェックするようにした(`scripts/check-consumer-types.ts`・`test/consumer/consumer.mts`。`moduleResolution` を `node16`・`nodenext`・`bundler` に変え、ライブラリの型定義の検査も有効にする)
|
|
28
|
+
|
|
29
|
+
- GOV.UK の監視を、外部の cron サービス(cron-job.org)から `workflow_dispatch` で起動する形にした(毎日 06:00 日本時間)。GitHub の schedule は予備として 18:17(日本時間)に移した。GitHub の schedule は高負荷時に遅れたり落ちたりし、追加してから一度も動かなかったため。動いたことは最後に healthchecks.io へ知らせ(Secrets の `HEALTHCHECKS_PING_URL`。照合そのものが失敗したときは `/fail`)、知らせが途絶えたらメールが届くようにした(RELEASING.md の「監視の起動とハートビート」。cron-job.org からの呼び出しは REST API の 2026-03-10 版を指定する)
|
|
30
|
+
|
|
31
|
+
- ブラウザーでの確認(`scripts/test-browsers.ts`)に時間制限を設けた。ページの読み込みとスクリプトの実行は 30 秒(WebDriver の `timeouts`)、ドライバーへの各呼び出しは 60 秒。結果を受け取る前の段階(ドライバーの起動・セッションの作成・ページの読み込み・結果の待ち)で止まったときだけ、ドライバーを起動し直して 1 回だけやり直し、その理由を `RETRY` としてログに出す。確認の結果が FAIL のときはやり直さない。CI でランナー上の Edge がページの読み込みで応答しなくなり、既定の 300 秒を待って失敗したため
|
|
32
|
+
|
|
33
|
+
## [0.8.1] - 2026-10-18
|
|
34
|
+
|
|
35
|
+
ライブラリのコードは 0.8.0 と同じ。動作を確かめる環境を広げ、README の記述を確かめた範囲に合わせた。
|
|
36
|
+
|
|
37
|
+
### Changed
|
|
38
|
+
|
|
39
|
+
- README の動作環境の記述を、CI で確かめた範囲に合わせた。「Node.js・ブラウザー・エッジランタイムで動作」を、確かめている環境(Node.js・Chrome・Firefox・Edge・Safari・Cloudflare Workers)の明記に改め、確かめていない環境(Deno・Bun・Vercel の Edge Runtime など)も書いた。Temporal は形で判別していることと、本物の Temporal を備えた環境では CI で確かめていることを書いた。サイズの値に測った版(0.8.1)を添えた。エラーコードの一覧に `invalid-input` を足した
|
|
40
|
+
- README に、CI で確かめている Node.js の版(22.12・22・24・26)と、CommonJS の `require()` で読み込めることを CI で確かめていることを書いた。Node.js 22.12 では `require()` での読み込みに実験的な機能の警告が出ることも書いた(結果には影響しない)。`engines`(`>=22.12`)は変わらない
|
|
41
|
+
|
|
42
|
+
### 開発
|
|
43
|
+
|
|
44
|
+
- 公開する `dist` を ESM(`import`)と CommonJS(`require()`)で確かめるテスト(`test/compat`、`pnpm test:compat`)を追加し、`pnpm check` に含めた。CI に `compat` ジョブを追加し、engines の下限の Node.js 22.12.0 と 26.12.0 でも確かめる(これらの版ではテストの `.ts` と npm 12 が動かないため、ビルドは Node.js 24 で行い、Node.js を切り替えて `dist` だけを確かめる)
|
|
45
|
+
|
|
46
|
+
- CI に、公開する `dist` をブラウザーと Cloudflare Workers で確かめるジョブを追加した。`browsers`(Chrome・Firefox・Edge。ランナーのドライバーを WebDriver で操作する `scripts/test-browsers.ts`)・`safari`(macOS)・`workerd`(版と SHA-256 を固定した公式のリリースの workerd で動かす `scripts/test-workerd.ts`)。確認の中身は `test/compat/smoke.mjs` に共通化し、本物の Temporal を備えた環境では Temporal のオブジェクトでも確かめる
|
|
47
|
+
- `pnpm check` で、README(英語・日本語)のコード例を実行し、コメントに書いた結果と比べるようにした(`scripts/check-readme-examples.ts`)
|
|
48
|
+
- `pnpm check`(`scripts/check-package.ts`)で、`src` が Node.js 固有の機能(`node:` のモジュール・`process`・`Buffer` など)を使っていないことを確かめるようにした
|
|
49
|
+
- 自前のスクリプトとテストで Node.js の警告が出たら失敗にするようにした(`scripts/strict-warnings.ts`。`test/compat` は対象外)
|
|
50
|
+
- `pnpm check` の最初に、開発用のツールの版を確かめる `scripts/check-toolchain.ts` を追加した(ワークフローどうしの Node.js の版、compat の行列の engines の下限、実行している Node.js・npm・pnpm と固定版の比較。固定版との違いは CI ではエラー、手元では注意の表示)
|
|
51
|
+
- GOV.UK の監視のワークフローに、手動実行の入力 `simulate` を追加した。架空の祝日を 1 件足して照合し(`pnpm verify:govuk --simulate`)、ラベル `govuk-data-simulation` の issue で差分の経路を確かめられる
|
|
52
|
+
- `pnpm check` のパッケージの中身の検査(`npm pack --dry-run`)を、Windows で Node.js の非推奨の警告(DEP0190)が出ない形で npm を起動するようにした
|
|
53
|
+
|
|
7
54
|
## [0.8.0] - 2026-10-17
|
|
8
55
|
|
|
9
56
|
### Added
|
|
@@ -179,7 +226,9 @@
|
|
|
179
226
|
|
|
180
227
|
- 日本: 2026 年 2 月の官報(2027 年の春分・秋分の日)まで反映(`dataVersion: "2026-02"`、`confirmedThrough: 2027`)
|
|
181
228
|
|
|
182
|
-
[Unreleased]: https://github.com/inohan77/bizdays-toolkit/compare/v0.
|
|
229
|
+
[Unreleased]: https://github.com/inohan77/bizdays-toolkit/compare/v0.9.0...HEAD
|
|
230
|
+
[0.9.0]: https://github.com/inohan77/bizdays-toolkit/compare/v0.8.1...v0.9.0
|
|
231
|
+
[0.8.1]: https://github.com/inohan77/bizdays-toolkit/compare/v0.8.0...v0.8.1
|
|
183
232
|
[0.8.0]: https://github.com/inohan77/bizdays-toolkit/compare/v0.7.0...v0.8.0
|
|
184
233
|
[0.7.0]: https://github.com/inohan77/bizdays-toolkit/compare/v0.6.0...v0.7.0
|
|
185
234
|
[0.6.0]: https://github.com/inohan77/bizdays-toolkit/compare/v0.5.0...v0.6.0
|
package/README.md
CHANGED
|
@@ -26,7 +26,7 @@ A business-day calendar that combines public holidays with company or store clos
|
|
|
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
28
|
- **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
|
|
29
|
-
- **Lightweight, zero dependencies**: about 7.
|
|
29
|
+
- **Lightweight, zero dependencies**: about 7.5 KB min+gzip (about 9.0 KB with Japanese holidays, about 9.1 KB with UK bank holidays; measured for 0.9.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
|
|
30
30
|
- **Extensible to other countries and regions**: holiday providers are pluggable through the `HolidayProvider` interface. Japan and the UK are bundled
|
|
31
31
|
|
|
32
32
|
## Installation
|
|
@@ -35,7 +35,9 @@ A business-day calendar that combines public holidays with company or store clos
|
|
|
35
35
|
pnpm add bizdays-toolkit
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
-
Node.js 22.12 or later.
|
|
38
|
+
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.
|
|
39
|
+
|
|
40
|
+
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.
|
|
39
41
|
|
|
40
42
|
## Usage
|
|
41
43
|
|
|
@@ -112,8 +114,13 @@ shipping.businessDayOnOrAfter(new Date(), { cutoff: "14:00" });
|
|
|
112
114
|
|
|
113
115
|
shipping.dayInfo("2027-01-01");
|
|
114
116
|
// { date: "2027-01-01", weekday: 5, businessDay: false, reason: "closed-annual", name: "New Year closure", holiday: {…} }
|
|
117
|
+
shipping.daysBetween("2026-12-30", "2027-01-04").map((d) => d.businessDay); // [true, false, false, false, false, true]
|
|
115
118
|
```
|
|
116
119
|
|
|
120
|
+
`daysBetween(from, to)` returns `dayInfo` for every day in the period (both ends included).
|
|
121
|
+
|
|
122
|
+
`createCalendar` and `createSchedule` validate the options when they are created, so the usual pattern is to create them once and reuse them. Creating is also cheap (about 0.02 ms for a calendar and 0.04 ms for a schedule with Japanese holidays on a development machine), so creating one per request is not a problem in practice.
|
|
123
|
+
|
|
117
124
|
Each day is decided in this order of priority (top first).
|
|
118
125
|
|
|
119
126
|
1. `openDates` (specific open days)
|
|
@@ -203,6 +210,23 @@ const jpWithoutCitizensHoliday = {
|
|
|
203
210
|
const calendar = createCalendar({ holidays: jpWithoutCitizensHoliday, closedWeekdays: [0, 6] });
|
|
204
211
|
```
|
|
205
212
|
|
|
213
|
+
**Split special days kept in one list**: dates (`"YYYY-MM-DD"`) go in `dates` and annual dates (`"MM-DD"`) in `annual`.
|
|
214
|
+
|
|
215
|
+
```ts
|
|
216
|
+
type Hours = { open: string; close: string } | null;
|
|
217
|
+
const regular: Hours = { open: "10:00", close: "19:00" };
|
|
218
|
+
const specialDays: { date: string; value: Hours }[] = [
|
|
219
|
+
{ date: "2026-12-31", value: { open: "10:00", close: "17:00" } },
|
|
220
|
+
{ date: "01-01", value: null },
|
|
221
|
+
];
|
|
222
|
+
const special = createSchedule<Hours>({
|
|
223
|
+
weekly: [regular, regular, regular, regular, regular, regular, regular],
|
|
224
|
+
dates: specialDays.filter((d) => d.date.length === 10),
|
|
225
|
+
annual: specialDays.filter((d) => d.date.length === 5),
|
|
226
|
+
});
|
|
227
|
+
special.valueOn("2027-01-01"); // null
|
|
228
|
+
```
|
|
229
|
+
|
|
206
230
|
**Build per-store calendars from shared options**: options are plain objects, so spread and extend them.
|
|
207
231
|
|
|
208
232
|
```ts
|
|
@@ -288,8 +312,16 @@ const storeHours = createSchedule<Hours>({
|
|
|
288
312
|
storeHours.valueOn("2026-11-03"); // { open: "10:00", close: "19:00" } (Culture Day uses Sunday hours)
|
|
289
313
|
storeHours.dayInfo("2027-01-01");
|
|
290
314
|
// { date: "2027-01-01", weekday: 5, value: null, reason: "annual", name: "Closed on New Year's Day", holiday: {…} }
|
|
315
|
+
|
|
316
|
+
// Holidays in a period with their hours: filter daysBetween by holiday
|
|
317
|
+
storeHours
|
|
318
|
+
.daysBetween("2026-11-01", "2026-11-30")
|
|
319
|
+
.filter((d) => d.holiday)
|
|
320
|
+
.map((d) => d.date); // ["2026-11-03", "2026-11-23"]
|
|
291
321
|
```
|
|
292
322
|
|
|
323
|
+
`reason` is the rule that decided the value. With `holiday: "weekday"` (holidays follow the weekday rule), a holiday has `reason: "weekday"`, so check `holiday` to know whether a day is a holiday.
|
|
324
|
+
|
|
293
325
|
Values are decided in the order `dates` (specific dates and ranges) → `annual` (annual dates and ranges) → `recurring` (`"over-holiday"`) → holidays → `recurring` (default and moved days) → `weekly` (weekday). When rules of the same type overlap, the one written first in the array wins.
|
|
294
326
|
|
|
295
327
|
Checking a time range such as "is the store open now" is left to your app, because industries differ (opening past midnight, breaks and so on). With `civilOf` you get the civil date and time in the time zone, and the check is short.
|
|
@@ -297,10 +329,10 @@ Checking a time range such as "is the store open now" is left to your app, becau
|
|
|
297
329
|
```ts
|
|
298
330
|
const { date, time } = storeHours.civilOf(new Date()); // { date: "2026-10-14", time: "16:30" } (Japan time)
|
|
299
331
|
const hours = storeHours.valueOn(date);
|
|
300
|
-
const isOpen = hours !== null &&
|
|
332
|
+
const isOpen = hours !== null && hours.open <= time && time < hours.close;
|
|
301
333
|
```
|
|
302
334
|
|
|
303
|
-
`civilOf` is also on business-day calendars, and the same conversion is available as `toJapanDateTime` in `bizdays-toolkit/jp` and `toDateTimeParts(input, timeZone)` in the root.
|
|
335
|
+
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 `toJapanDateTime` in `bizdays-toolkit/jp` and `toDateTimeParts(input, timeZone)` in the root.
|
|
304
336
|
|
|
305
337
|
### Date and date-time inputs
|
|
306
338
|
|
|
@@ -315,6 +347,8 @@ Every method accepts the following inputs. Returned dates are always `"YYYY-MM-D
|
|
|
315
347
|
| Temporal `PlainDate`, `PlainDateTime` | A civil date or date and time (no dependency on Temporal) |
|
|
316
348
|
| Temporal `Instant`, `ZonedDateTime` | An instant |
|
|
317
349
|
|
|
350
|
+
Temporal objects are recognized by their shape, so the package does not depend on Temporal. CI also checks real Temporal objects in the runtimes that provide Temporal (the CI log shows whether each runtime had it).
|
|
351
|
+
|
|
318
352
|
The calendar's time zone is the `timeZone` option, then the holiday provider's time zone, then `"UTC"`.
|
|
319
353
|
|
|
320
354
|
### Holidays of other countries and regions
|
|
@@ -379,7 +413,7 @@ try {
|
|
|
379
413
|
}
|
|
380
414
|
```
|
|
381
415
|
|
|
382
|
-
Main codes: `invalid-date`, `invalid-month`, `invalid-month-day`, `invalid-time`, `invalid-range`, `invalid-weekday`, `invalid-time-zone`, `invalid-option`, `out-of-range`, `invalid-provider`, `invalid-provider-data`, `no-business-day`. Future versions may add codes.
|
|
416
|
+
Main codes: `invalid-date`, `invalid-input`, `invalid-month`, `invalid-month-day`, `invalid-time`, `invalid-range`, `invalid-weekday`, `invalid-time-zone`, `invalid-option`, `out-of-range`, `invalid-provider`, `invalid-provider-data`, `no-business-day`. Future versions may add codes.
|
|
383
417
|
|
|
384
418
|
### Option diagnostics
|
|
385
419
|
|
|
@@ -446,7 +480,7 @@ Versioning follows [Semantic Versioning](https://semver.org/). See [RELEASING.md
|
|
|
446
480
|
- Official data updates (new, moved and one-off holidays by law, Official Gazette or proclamation, fixed equinox days in Japan, newly published years on GOV.UK) are released as **patch** versions, so they reach you with either `^` or `~`
|
|
447
481
|
- To freeze the holiday results, pin an exact version (for example `"bizdays-toolkit": "0.8.0"`)
|
|
448
482
|
- The reflected data is shown by `dataVersion` (for Japan, the year and month of the Official Gazette reflected; for the UK, the year and month of the GOV.UK data reflected) and `confirmedThrough`
|
|
449
|
-
- Before 1.0.0, minor versions may contain breaking changes
|
|
483
|
+
- Before 1.0.0, minor versions may contain breaking changes. What you need to change when moving between minor versions is listed in the [migration guide](https://github.com/inohan77/bizdays-toolkit/blob/main/docs/migration.md) (Japanese) and in the "移行" (migration) part of each version in the CHANGELOG
|
|
450
484
|
- Decision reasons (`reason`), holiday kinds (`kind`), error codes and diagnostic codes may gain values in future versions. When you branch on their values, handle "anything else" too (see "互換性の約束", the compatibility promise, in [RELEASING.md](https://github.com/inohan77/bizdays-toolkit/blob/main/RELEASING.md))
|
|
451
485
|
|
|
452
486
|
## Data sources
|
package/dist/core/calendar.d.ts
CHANGED
|
@@ -161,6 +161,8 @@ export interface DueDateOptions {
|
|
|
161
161
|
export interface Calendar<Kind extends string = string> extends HolidayLookup<Kind> {
|
|
162
162
|
/** 1 日分の判定結果(営業日か・理由・祝日) */
|
|
163
163
|
dayInfo(input: DateInput): DayInfo<Kind>;
|
|
164
|
+
/** 期間内の日ごとの判定結果(両端を含む。from が to より後ならエラー) */
|
|
165
|
+
daysBetween(from: DateInput, to: DateInput): readonly DayInfo<Kind>[];
|
|
164
166
|
/** 営業日か */
|
|
165
167
|
isBusinessDay(input: DateInput): boolean;
|
|
166
168
|
/** 翌営業日(入力日の翌日以降) */
|
package/dist/core/calendar.js
CHANGED
|
@@ -20,7 +20,7 @@ import { addDays, daysInMonth, formatDate, fromDayNumber, toDayNumber, } from ".
|
|
|
20
20
|
import { checkUnknownKeys, IssueCollector, plainError, rangeError } from "./errors.js";
|
|
21
21
|
import { parseTimeOfDay, toCivil } from "./input.js";
|
|
22
22
|
import { dayOfMonth, isDayOfMonthValue, parseMonth } from "./month.js";
|
|
23
|
-
import { buildSchedule, compileAnnualRules, compileDateRules, compileHolidaySource, compileRecurringRules, isWeekday, RECURRING_RULE_KEYS, } from "./schedule.js";
|
|
23
|
+
import { buildSchedule, compileAnnualRules, compileDateRules, compileHolidaySource, compileRecurringRules, isWeekday, mapDays, RECURRING_RULE_KEYS, } from "./schedule.js";
|
|
24
24
|
const CALENDAR_OPTION_KEYS = [
|
|
25
25
|
"holidays",
|
|
26
26
|
"timeZone",
|
|
@@ -236,6 +236,7 @@ export function createCalendar(options = {}) {
|
|
|
236
236
|
holidaysInYear: schedule.holidaysInYear,
|
|
237
237
|
holidaysBetween: schedule.holidaysBetween,
|
|
238
238
|
dayInfo: (input) => info(dateOf(input)),
|
|
239
|
+
daysBetween: (from, to) => mapDays(dateOf(from), dateOf(to), info),
|
|
239
240
|
isBusinessDay: (input) => isOpen(dateOf(input)),
|
|
240
241
|
nextBusinessDay: (input) => search(addDays(dateOf(input), 1), 1),
|
|
241
242
|
previousBusinessDay: (input) => search(addDays(dateOf(input), -1), -1),
|
package/dist/core/input.d.ts
CHANGED
|
@@ -33,6 +33,30 @@ export interface TemporalInstantLike {
|
|
|
33
33
|
* @public
|
|
34
34
|
*/
|
|
35
35
|
export type DateInput = string | Date | TemporalDateLike | TemporalInstantLike;
|
|
36
|
+
/**
|
|
37
|
+
* Temporal.PlainDateTime として受け付ける最小限の形(時刻を持つ TemporalDateLike)。
|
|
38
|
+
* @public
|
|
39
|
+
*/
|
|
40
|
+
export interface TemporalDateTimeLike extends TemporalDateLike {
|
|
41
|
+
readonly hour: number;
|
|
42
|
+
readonly minute: number;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* 時刻を必ず持つ入力(瞬間、Temporal.PlainDateTime、"YYYY-MM-DDTHH:mm…" の文字列)。
|
|
46
|
+
* これを渡すと、civilOf・toDateTimeParts・toJapanDateTime の time の型が string になる。
|
|
47
|
+
* @public
|
|
48
|
+
*/
|
|
49
|
+
export type DateTimeInput = Date | TemporalInstantLike | TemporalDateTimeLike | `${number}-${number}-${number}T${string}`;
|
|
50
|
+
/**
|
|
51
|
+
* タイムゾーンでの暦日と時刻。Time は時刻の型で、時刻を必ず持つ入力(DateTimeInput)では string になる。
|
|
52
|
+
* @public
|
|
53
|
+
*/
|
|
54
|
+
export interface CivilDateTimeParts<Time extends string | null = string | null> {
|
|
55
|
+
/** 暦日 "YYYY-MM-DD" */
|
|
56
|
+
readonly date: DateString;
|
|
57
|
+
/** 時刻 "HH:mm"。暦日だけの入力では null */
|
|
58
|
+
readonly time: Time;
|
|
59
|
+
}
|
|
36
60
|
/** @internal 暦日と、分かる場合は 0 時からの経過分 */
|
|
37
61
|
export interface CivilDateTime {
|
|
38
62
|
readonly date: DateString;
|
|
@@ -52,11 +76,11 @@ export declare function toCivil(input: DateInput, timeZone: string): CivilDateTi
|
|
|
52
76
|
export declare function toDateString(input: DateInput, timeZone: string): DateString;
|
|
53
77
|
/**
|
|
54
78
|
* 入力を、タイムゾーンでの暦日と時刻("HH:mm"。暦日だけの入力では null)に変換する。
|
|
79
|
+
* 時刻を必ず持つ入力(DateTimeInput)では、time の型が string になる。
|
|
55
80
|
* @public
|
|
56
81
|
*/
|
|
57
|
-
export declare function toDateTimeParts(input:
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
};
|
|
82
|
+
export declare function toDateTimeParts(input: DateTimeInput, timeZone: string): CivilDateTimeParts<string>;
|
|
83
|
+
/** @public */
|
|
84
|
+
export declare function toDateTimeParts(input: DateInput, timeZone: string): CivilDateTimeParts;
|
|
61
85
|
/** @internal "HH:mm" を 0 時からの経過分に変換する(00:00〜23:59) */
|
|
62
86
|
export declare function parseTimeOfDay(value: string): number;
|
package/dist/core/input.js
CHANGED
|
@@ -136,10 +136,6 @@ export function toCivil(input, timeZone) {
|
|
|
136
136
|
export function toDateString(input, timeZone) {
|
|
137
137
|
return toCivil(input, validateTimeZone(timeZone)).date;
|
|
138
138
|
}
|
|
139
|
-
/**
|
|
140
|
-
* 入力を、タイムゾーンでの暦日と時刻("HH:mm"。暦日だけの入力では null)に変換する。
|
|
141
|
-
* @public
|
|
142
|
-
*/
|
|
143
139
|
export function toDateTimeParts(input, timeZone) {
|
|
144
140
|
const civil = toCivil(input, validateTimeZone(timeZone));
|
|
145
141
|
const time = civil.minutes === null
|
package/dist/core/schedule.d.ts
CHANGED
|
@@ -16,7 +16,8 @@
|
|
|
16
16
|
*/
|
|
17
17
|
import { type DateString, type Weekday } from "./date.ts";
|
|
18
18
|
import { IssueCollector } from "./errors.ts";
|
|
19
|
-
import { type DateInput } from "./input.ts";
|
|
19
|
+
import { type CivilDateTimeParts, type DateInput, type DateTimeInput } from "./input.ts";
|
|
20
|
+
export type { CivilDateTimeParts } from "./input.ts";
|
|
20
21
|
import type { Holiday, HolidayProvider } from "./types.ts";
|
|
21
22
|
/**
|
|
22
23
|
* 祝日の値の決め方(スケジュールの holiday の設定)。
|
|
@@ -198,16 +199,6 @@ export interface ScheduleDay<T, Kind extends string = string> {
|
|
|
198
199
|
/** 祝日から振り替えられた規則で値が決まった場合、振替の元の日付(onHolidayRule: "after-holiday") */
|
|
199
200
|
readonly shiftedFrom?: DateString;
|
|
200
201
|
}
|
|
201
|
-
/**
|
|
202
|
-
* 暦日と時刻(カレンダーのタイムゾーン)。
|
|
203
|
-
* @public
|
|
204
|
-
*/
|
|
205
|
-
export interface CivilDateTimeParts {
|
|
206
|
-
/** 暦日 "YYYY-MM-DD" */
|
|
207
|
-
readonly date: DateString;
|
|
208
|
-
/** 時刻 "HH:mm"。暦日だけの入力では null */
|
|
209
|
-
readonly time: string | null;
|
|
210
|
-
}
|
|
211
202
|
/**
|
|
212
203
|
* 祝日を調べる機能(スケジュールと営業日カレンダーで共通)。
|
|
213
204
|
* @public
|
|
@@ -220,6 +211,7 @@ export interface HolidayLookup<Kind extends string = string> {
|
|
|
220
211
|
/** 入力をタイムゾーンでの暦日に変換する */
|
|
221
212
|
dateOf(input: DateInput): DateString;
|
|
222
213
|
/** 入力をタイムゾーンでの暦日と時刻に変換する */
|
|
214
|
+
civilOf(input: DateTimeInput): CivilDateTimeParts<string>;
|
|
223
215
|
civilOf(input: DateInput): CivilDateTimeParts;
|
|
224
216
|
/** 今日の日付(タイムゾーン) */
|
|
225
217
|
today(now?: Date): DateString;
|
|
@@ -239,8 +231,13 @@ export interface HolidayLookup<Kind extends string = string> {
|
|
|
239
231
|
export interface Schedule<T, Kind extends string = string> extends HolidayLookup<Kind> {
|
|
240
232
|
/** その日の値 */
|
|
241
233
|
valueOn(input: DateInput): T;
|
|
242
|
-
/**
|
|
234
|
+
/**
|
|
235
|
+
* その日の値と、値を決めた規則(reason)。reason は値を決めた規則なので、祝日の規則が "weekday"(曜日どおり)の
|
|
236
|
+
* ときは、祝日でも "weekday" になる。祝日かどうかは holiday の有無で判定する
|
|
237
|
+
*/
|
|
243
238
|
dayInfo(input: DateInput): ScheduleDay<T, Kind>;
|
|
239
|
+
/** 期間内の日ごとの値と規則(両端を含む。from が to より後ならエラー) */
|
|
240
|
+
daysBetween(from: DateInput, to: DateInput): readonly ScheduleDay<T, Kind>[];
|
|
244
241
|
}
|
|
245
242
|
/** @internal "MM-DD" として正しいか(2 月 29 日は可) */
|
|
246
243
|
export declare function isValidMonthDay(value: unknown): value is string;
|
|
@@ -331,6 +328,8 @@ type HolidayLookupInternal<Kind extends string> = ReturnType<typeof createHolida
|
|
|
331
328
|
* 規則の診断では、規則を取り除いた版と結果を比べるために、祝日を調べる機能(lookup)を共有して作る
|
|
332
329
|
*/
|
|
333
330
|
export declare function createResolver<T, Kind extends string>(compiled: CompiledSchedule<T, Kind>, lookup: HolidayLookupInternal<Kind>): (date: DateString) => Resolution<T, Kind>;
|
|
331
|
+
/** @internal 期間(両端を含む)の日ごとに fn を呼んだ結果。from が to より後ならエラー */
|
|
332
|
+
export declare function mapDays<R>(from: DateString, to: DateString, fn: (date: DateString) => R): readonly R[];
|
|
334
333
|
/** @internal 検証済みの規則からスケジュールを作る */
|
|
335
334
|
export declare function buildSchedule<T, Kind extends string>(compiled: CompiledSchedule<T, Kind>): Schedule<T, Kind>;
|
|
336
335
|
/**
|
|
@@ -341,4 +340,3 @@ export declare function buildSchedule<T, Kind extends string>(compiled: Compiled
|
|
|
341
340
|
* @public
|
|
342
341
|
*/
|
|
343
342
|
export declare function createSchedule<T, Kind extends string = string>(options: ScheduleOptions<T, Kind>): Schedule<T, Kind>;
|
|
344
|
-
export {};
|
package/dist/core/schedule.js
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
*
|
|
15
15
|
* 営業日カレンダー(createCalendar)は、このスケジュールの真偽値版として作られている。
|
|
16
16
|
*/
|
|
17
|
-
import { addDays, daysInMonth, isValidDate, parseDate, toDayNumber, weekdayOf, } from "./date.js";
|
|
17
|
+
import { addDays, daysInMonth, fromDayNumber, isValidDate, parseDate, toDayNumber, weekdayOf, } from "./date.js";
|
|
18
18
|
import { checkUnknownKeys, IssueCollector, rangeError } from "./errors.js";
|
|
19
19
|
import { instantToCivil, toCivil, toDateTimeParts, validateTimeZone, } from "./input.js";
|
|
20
20
|
// ------------------------------------------------------------
|
|
@@ -454,7 +454,7 @@ export function createHolidayLookup(source) {
|
|
|
454
454
|
providers,
|
|
455
455
|
holidayOn,
|
|
456
456
|
dateOf,
|
|
457
|
-
civilOf: (input) => toDateTimeParts(input, timeZone),
|
|
457
|
+
civilOf: ((input) => toDateTimeParts(input, timeZone)),
|
|
458
458
|
today: (now = new Date()) => instantToCivil(now.getTime(), timeZone).date,
|
|
459
459
|
isHoliday: (input) => holidayOn(dateOf(input)) !== undefined,
|
|
460
460
|
getHoliday: (input) => holidayOn(dateOf(input)),
|
|
@@ -620,6 +620,16 @@ export function createResolver(compiled, lookup) {
|
|
|
620
620
|
return make(weekly[weekday], "weekday", null, undefined);
|
|
621
621
|
};
|
|
622
622
|
}
|
|
623
|
+
/** @internal 期間(両端を含む)の日ごとに fn を呼んだ結果。from が to より後ならエラー */
|
|
624
|
+
export function mapDays(from, to, fn) {
|
|
625
|
+
if (from > to) {
|
|
626
|
+
throw rangeError("invalid-range", `"from" must not be after "to" (${from} > ${to})`);
|
|
627
|
+
}
|
|
628
|
+
const result = [];
|
|
629
|
+
for (let n = toDayNumber(from); n <= toDayNumber(to); n++)
|
|
630
|
+
result.push(fn(fromDayNumber(n)));
|
|
631
|
+
return Object.freeze(result);
|
|
632
|
+
}
|
|
623
633
|
/** @internal 検証済みの規則からスケジュールを作る */
|
|
624
634
|
export function buildSchedule(compiled) {
|
|
625
635
|
const lookup = createHolidayLookup(compiled.source);
|
|
@@ -637,6 +647,7 @@ export function buildSchedule(compiled) {
|
|
|
637
647
|
holidaysBetween: lookup.holidaysBetween,
|
|
638
648
|
valueOn: (input) => info(lookup.dateOf(input)).value,
|
|
639
649
|
dayInfo: (input) => info(lookup.dateOf(input)),
|
|
650
|
+
daysBetween: (from, to) => mapDays(lookup.dateOf(from), lookup.dateOf(to), info),
|
|
640
651
|
};
|
|
641
652
|
return Object.freeze(schedule);
|
|
642
653
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -12,5 +12,5 @@ export { createSchedule, type AnnualRangeValue, type AnnualValue, type CivilDate
|
|
|
12
12
|
export { addDays, diffDays, isValidDate, weekdayOf, type DateString, type Weekday, } from "./core/date.ts";
|
|
13
13
|
export { closingMonth, 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 TemporalDateLike, type TemporalInstantLike, } from "./core/input.ts";
|
|
15
|
+
export { toDateString, toDateTimeParts, 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/jp/index.d.ts
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* isHoliday("2026-11-23"); // true
|
|
12
12
|
*/
|
|
13
13
|
import type { DateString } from "../core/date.ts";
|
|
14
|
-
import type { DateInput } from "../core/input.ts";
|
|
14
|
+
import type { CivilDateTimeParts, DateInput, DateTimeInput } from "../core/input.ts";
|
|
15
15
|
import type { Holiday, HolidayProvider } from "../core/types.ts";
|
|
16
16
|
import { type JapaneseHolidayKind } from "./rules.ts";
|
|
17
17
|
export type { JapaneseHolidayKind, KnownJapaneseHolidayKind } from "./rules.ts";
|
|
@@ -52,12 +52,12 @@ export declare function holidaysBetween(from: DateInput, to: DateInput): readonl
|
|
|
52
52
|
export declare function toJapanDate(input: DateInput): DateString;
|
|
53
53
|
/**
|
|
54
54
|
* 日本時間での暦日と時刻("HH:mm"。暦日だけの入力では null)。
|
|
55
|
+
* 時刻を必ず持つ入力(Date・Temporal.Instant など)では、time の型が string になる。
|
|
55
56
|
* @public
|
|
56
57
|
*/
|
|
57
|
-
export declare function toJapanDateTime(input:
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
};
|
|
58
|
+
export declare function toJapanDateTime(input: DateTimeInput): CivilDateTimeParts<string>;
|
|
59
|
+
/** @public */
|
|
60
|
+
export declare function toJapanDateTime(input: DateInput): CivilDateTimeParts;
|
|
61
61
|
/**
|
|
62
62
|
* 反映済みの官報の年月。
|
|
63
63
|
* @public
|
package/dist/jp/index.js
CHANGED
|
@@ -69,10 +69,6 @@ export function holidaysBetween(from, to) {
|
|
|
69
69
|
export function toJapanDate(input) {
|
|
70
70
|
return calendar().dateOf(input);
|
|
71
71
|
}
|
|
72
|
-
/**
|
|
73
|
-
* 日本時間での暦日と時刻("HH:mm"。暦日だけの入力では null)。
|
|
74
|
-
* @public
|
|
75
|
-
*/
|
|
76
72
|
export function toJapanDateTime(input) {
|
|
77
73
|
return calendar().civilOf(input);
|
|
78
74
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bizdays-toolkit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.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",
|
|
@@ -56,12 +56,13 @@
|
|
|
56
56
|
"build": "rm -rf dist && tsc -p tsconfig.build.json",
|
|
57
57
|
"typecheck": "tsc --noEmit",
|
|
58
58
|
"lint": "oxlint --deny-warnings src scripts test",
|
|
59
|
-
"test": "node --test \"test/**/*.test.ts\"",
|
|
59
|
+
"test": "node --import ./scripts/strict-warnings.ts --test \"test/**/*.test.ts\"",
|
|
60
60
|
"test:tz": "node scripts/test-tz.ts",
|
|
61
|
+
"test:compat": "node --test test/compat/esm.test.mjs test/compat/cjs.test.cjs",
|
|
61
62
|
"bench": "node scripts/bench.ts",
|
|
62
63
|
"fmt": "oxfmt",
|
|
63
64
|
"fmt:check": "oxfmt --check",
|
|
64
|
-
"check": "pnpm typecheck && pnpm lint && pnpm test && pnpm test:tz && pnpm build && pnpm fmt:check && node scripts/check-package.ts && node scripts/check-size.ts && node scripts/api-report.ts",
|
|
65
|
+
"check": "node scripts/check-toolchain.ts && pnpm typecheck && pnpm lint && pnpm test && pnpm test:tz && pnpm build && pnpm test:compat && node scripts/check-readme-examples.ts && node scripts/check-consumer-types.ts && pnpm fmt:check && node scripts/check-package.ts && node scripts/check-size.ts && node scripts/api-report.ts",
|
|
65
66
|
"verify:cao": "node scripts/verify-cao.ts",
|
|
66
67
|
"verify:govuk": "node scripts/verify-govuk.ts",
|
|
67
68
|
"prepublishOnly": "pnpm check",
|