daymath 0.2.0 → 0.2.1
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 +12 -5
- package/index.d.ts +10 -4
- package/index.js +25 -9
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# daymath
|
|
2
2
|
|
|
3
|
-
Calendar date math for **ISO 8601**
|
|
3
|
+
Calendar date math for **ISO 8601** day strings. **date-fns-shaped** names. **Temporal.PlainDate** under the hood.
|
|
4
4
|
|
|
5
5
|
No `Date`. No time zones. No silent “local now.”
|
|
6
6
|
|
|
@@ -31,23 +31,30 @@ differenceInDays('2026-08-06', '2026-08-01') // 5
|
|
|
31
31
|
isBefore('2026-08-05', '2026-08-06') // true
|
|
32
32
|
isSameDay('2026-08-06', '2026-08-06') // true (alias of isEqual)
|
|
33
33
|
startOfMonth('2026-08-06') // '2026-08-01'
|
|
34
|
+
addDays('9999-12-31', 1) // '+010000-01-01' (expanded year)
|
|
34
35
|
eachDayOfInterval({
|
|
35
36
|
start: '2026-08-05',
|
|
36
37
|
end: '2026-08-07',
|
|
37
38
|
}) // ['2026-08-05', '2026-08-06', '2026-08-07']
|
|
38
39
|
```
|
|
39
40
|
|
|
40
|
-
**Inputs:** ISO 8601
|
|
41
|
-
|
|
41
|
+
**Inputs:** ISO 8601 day string or `Temporal.PlainDate`.
|
|
42
|
+
- `YYYY-MM-DD` (years 0000–9999)
|
|
43
|
+
- expanded `±YYYYYY-MM-DD` (e.g. `+010000-01-01`)
|
|
42
44
|
|
|
43
|
-
|
|
45
|
+
**Outputs:** Temporal’s ISO day string (same forms).
|
|
46
|
+
|
|
47
|
+
`Date` throws (including `isValid(date)`). Bad strings: math helpers throw; `isValid('asdf')` → `false`. Time-bearing / sloppy forms throw.
|
|
48
|
+
|
|
49
|
+
See [FUTURE.md](./FUTURE.md) for backlog (bundle size, business days, …).
|
|
44
50
|
|
|
45
51
|
## date-fns parity notes
|
|
46
52
|
|
|
47
53
|
| Topic | daymath |
|
|
48
54
|
|-------|---------|
|
|
49
|
-
| Value type |
|
|
55
|
+
| Value type | ISO day string (not `Date`) |
|
|
50
56
|
| `isSameDay` | Alias of `isEqual` (same calendar day) |
|
|
57
|
+
| `isValid` | Our predicate: valid day string / PlainDate. `Date` **throws** (not date-fns’s Date check) |
|
|
51
58
|
| `getMonth` / `setMonth` | **0–11** like Date/date-fns (0 = January) |
|
|
52
59
|
| `getDay` | **0–6** like Date/date-fns (0 = Sunday) |
|
|
53
60
|
| `weekStartsOn` | `0` = Sunday … `6` = Saturday (default `0`) |
|
package/index.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import type { Temporal } from 'temporal-polyfill'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Calendar day input: ISO 8601
|
|
5
|
-
* `
|
|
4
|
+
* Calendar day input: ISO 8601 day string, or a Temporal.PlainDate.
|
|
5
|
+
* - `YYYY-MM-DD` (years 0000–9999)
|
|
6
|
+
* - expanded `±YYYYYY-MM-DD` (e.g. `+010000-01-01`)
|
|
7
|
+
* `Date` is rejected at runtime (TypeError).
|
|
6
8
|
*/
|
|
7
9
|
export type DayInput = string | Temporal.PlainDate
|
|
8
10
|
|
|
@@ -19,12 +21,16 @@ export type WeekOptions = {
|
|
|
19
21
|
weekStartsOn?: 0 | 1 | 2 | 3 | 4 | 5 | 6
|
|
20
22
|
}
|
|
21
23
|
|
|
24
|
+
/**
|
|
25
|
+
* True for a valid daymath day string / PlainDate.
|
|
26
|
+
* Invalid strings → false. `Date` → throws TypeError (not a quiet false).
|
|
27
|
+
*/
|
|
22
28
|
export function isValid(value: unknown): boolean
|
|
23
29
|
|
|
24
|
-
/** Validate / normalize to ISO 8601 `
|
|
30
|
+
/** Validate / normalize to ISO 8601 day string (Temporal `toString` form). */
|
|
25
31
|
export function parse(date: DayInput): string
|
|
26
32
|
|
|
27
|
-
/** Format as `YYYY-MM-DD`
|
|
33
|
+
/** Format as ISO day (only `yyyy-MM-dd` / `YYYY-MM-DD` patterns supported). */
|
|
28
34
|
export function format(date: DayInput, pattern?: 'yyyy-MM-dd' | 'YYYY-MM-DD'): string
|
|
29
35
|
|
|
30
36
|
export function addDays(date: DayInput, amount: number): string
|
package/index.js
CHANGED
|
@@ -1,8 +1,16 @@
|
|
|
1
|
-
/** daymath — calendar date math (
|
|
1
|
+
/** daymath — calendar date math (ISO 8601 day). date-fns-shaped. No Date / time zones. */
|
|
2
2
|
import { Temporal as TemporalPolyfill } from 'temporal-polyfill'
|
|
3
3
|
|
|
4
4
|
const Temporal = globalThis.Temporal ?? TemporalPolyfill
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* ISO 8601 calendar day string:
|
|
8
|
+
* - `YYYY-MM-DD` (years 0000–9999)
|
|
9
|
+
* - expanded `±YYYYYY-MM-DD` (Temporal form, e.g. `+010000-01-01`)
|
|
10
|
+
*/
|
|
11
|
+
const ISO_DAY =
|
|
12
|
+
/^(?:[+-]\d{6}|\d{4})-\d{2}-\d{2}$/
|
|
13
|
+
|
|
6
14
|
/** @typedef {string | Temporal.PlainDate} DayInput */
|
|
7
15
|
/**
|
|
8
16
|
* @typedef {object} Interval
|
|
@@ -17,7 +25,7 @@ const Temporal = globalThis.Temporal ?? TemporalPolyfill
|
|
|
17
25
|
// ─── core conversion ───────────────────────────────────────────────
|
|
18
26
|
|
|
19
27
|
/**
|
|
20
|
-
* Reject Date and non-calendar values. Accept
|
|
28
|
+
* Reject Date and non-calendar values. Accept ISO day string or PlainDate.
|
|
21
29
|
* @param {unknown} value
|
|
22
30
|
* @param {string} label
|
|
23
31
|
* @returns {Temporal.PlainDate}
|
|
@@ -25,14 +33,13 @@ const Temporal = globalThis.Temporal ?? TemporalPolyfill
|
|
|
25
33
|
function toPlainDate(value, label = 'date') {
|
|
26
34
|
if (value instanceof Date) {
|
|
27
35
|
throw new TypeError(
|
|
28
|
-
`daymath: Date is not allowed for ${label} (pass
|
|
36
|
+
`daymath: Date is not allowed for ${label} (pass ISO 8601 day string)`,
|
|
29
37
|
)
|
|
30
38
|
}
|
|
31
39
|
if (typeof value === 'string') {
|
|
32
|
-
|
|
33
|
-
if (!/^\d{4}-\d{2}-\d{2}$/.test(value)) {
|
|
40
|
+
if (!ISO_DAY.test(value)) {
|
|
34
41
|
throw new RangeError(
|
|
35
|
-
`daymath: ${label} must be YYYY-MM-DD (got ${JSON.stringify(value)})`,
|
|
42
|
+
`daymath: ${label} must be ISO 8601 day YYYY-MM-DD or ±YYYYYY-MM-DD (got ${JSON.stringify(value)})`,
|
|
36
43
|
)
|
|
37
44
|
}
|
|
38
45
|
try {
|
|
@@ -47,7 +54,7 @@ function toPlainDate(value, label = 'date') {
|
|
|
47
54
|
return value
|
|
48
55
|
}
|
|
49
56
|
throw new TypeError(
|
|
50
|
-
`daymath: ${label} must be
|
|
57
|
+
`daymath: ${label} must be ISO 8601 day string or Temporal.PlainDate`,
|
|
51
58
|
)
|
|
52
59
|
}
|
|
53
60
|
|
|
@@ -105,8 +112,17 @@ function toInterval(interval) {
|
|
|
105
112
|
|
|
106
113
|
// ─── parse / format / valid ────────────────────────────────────────
|
|
107
114
|
|
|
108
|
-
/**
|
|
115
|
+
/**
|
|
116
|
+
* True if value is a valid daymath day (ISO day string or PlainDate).
|
|
117
|
+
* Invalid strings → false. `Date` → throws (not a quiet false — swap trap).
|
|
118
|
+
* @param {unknown} value
|
|
119
|
+
*/
|
|
109
120
|
export function isValid(value) {
|
|
121
|
+
if (value instanceof Date) {
|
|
122
|
+
throw new TypeError(
|
|
123
|
+
'daymath: Date is not allowed for isValid (pass ISO 8601 day string)',
|
|
124
|
+
)
|
|
125
|
+
}
|
|
110
126
|
try {
|
|
111
127
|
toPlainDate(value)
|
|
112
128
|
return true
|
|
@@ -116,7 +132,7 @@ export function isValid(value) {
|
|
|
116
132
|
}
|
|
117
133
|
|
|
118
134
|
/**
|
|
119
|
-
* Validate / normalize
|
|
135
|
+
* Validate / normalize an ISO 8601 calendar day string.
|
|
120
136
|
* @param {DayInput} date
|
|
121
137
|
* @returns {string}
|
|
122
138
|
*/
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "daymath",
|
|
3
|
-
"version": "0.2.
|
|
4
|
-
"description": "Calendar date math (
|
|
3
|
+
"version": "0.2.1",
|
|
4
|
+
"description": "Calendar date math (ISO 8601 day / PlainDate). date-fns-shaped. No time zones.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./index.js",
|
|
7
7
|
"types": "./index.d.ts",
|