datetime-lube 1.0.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.
@@ -0,0 +1,113 @@
1
+ import { days_of, wall_of_fields } from "./calendar.js"
2
+ import time_of from "./time_of.js"
3
+ import {
4
+ check_zone,
5
+ fields_of,
6
+ instant_of,
7
+ offset_in,
8
+ offset_of,
9
+ transition_of,
10
+ unit_start
11
+ } from "./zone.js"
12
+ /** @type {Record<string, number | undefined>} */
13
+ const unit_ms = { H: 3600000, m: 60000, s: 1000 }
14
+ /** @type {Record<string, number>} */
15
+ const units = { D: 3, M: 2, W: 3, Y: 1 }
16
+ const units_of = new Set(
17
+ [ "D", "H", "M", "W", "Y", "m", "s" ]
18
+ )
19
+ /**
20
+ * Returns a new Date at the start of the given unit, such as midnight of the same day.
21
+ * A week starts on Monday, as in ISO 8601.
22
+ * @param {Date} date
23
+ * @param {Exclude<import("../public.js").Unit, "sss">} unit
24
+ * ```
25
+ * "Y" | "M" | "W" | "D" | "H" | "m" | "s"
26
+ * ```
27
+ * @param {import("../public.js").TimeZone=} zone
28
+ * @returns {Date}
29
+ * @throws
30
+ * ```
31
+ * RangeError(`startOf: Invalid unit "${unit}"`) // The unit is not one of the listed ones
32
+ * RangeError(`startOf: Invalid time zone "${zone}"`) // Intl.DateTimeFormat rejects the zone
33
+ * TypeError(`startOf: Expected a Date, got ${typeof date}`)
34
+ * ```
35
+ * @example startOf(new Date, "D", "Asia/Seoul") //=> Date { midnight in Seoul }
36
+ */
37
+ export default function(date, unit, zone) {
38
+ const time = time_of("startOf", date)
39
+ if (!units_of.has(unit)) throw new RangeError(
40
+ `startOf: Invalid unit "${String(unit)}"`
41
+ )
42
+ check_zone("startOf", zone)
43
+ if (isNaN(time)) return new Date(NaN)
44
+ const ms = unit_ms[unit]
45
+ if (ms) {
46
+ if (zone !== undefined) {
47
+ const offset = offset_of(time, zone)
48
+ const rest = ((time + offset) % ms + ms) % ms
49
+ return new Date(
50
+ offset_of(time - rest, zone) == offset
51
+ ? time - rest
52
+ : unit_start(time, ms, zone)
53
+ )
54
+ }
55
+ const rest = ms > 60000
56
+ ? date.getMinutes() * 60000 + date.getSeconds() * 1000 + date.getMilliseconds()
57
+ : ms > 1000
58
+ ? date.getSeconds() * 1000 + date.getMilliseconds()
59
+ : date.getMilliseconds()
60
+ const result = new Date(time - rest)
61
+ if (
62
+ result.getTimezoneOffset() == date.getTimezoneOffset()
63
+ && result.getSeconds() == (ms > 1000 ? 0 : date.getSeconds())
64
+ ) return result
65
+ result.setTime(unit_start(time, ms))
66
+ return result
67
+ }
68
+ const from = /** @type {number} */(units[unit])/**/
69
+ if (zone === undefined) {
70
+ const result = new Date(time)
71
+ result.setHours(
72
+ unit == "D"
73
+ ? 0
74
+ : unit == "W"
75
+ ? -24 * ((result.getDay() + 6) % 7)
76
+ : unit == "M"
77
+ ? 24 - 24 * result.getDate()
78
+ : -24 * (days_of(
79
+ result.getFullYear(),
80
+ result.getMonth(),
81
+ result.getDate()
82
+ ) - days_of(result.getFullYear(), 0, 1)),
83
+ 0,
84
+ 0,
85
+ 0
86
+ )
87
+ if (result.getTime() <= time && !(result.getHours() || result.getMinutes() || result.getSeconds())) return result
88
+ }
89
+ const fields = fields_of(date, zone)
90
+ if (unit == "W") fields[2] = /** @type {number} */(fields[2])/**/ - (/** @type {number} */(fields[7])/**/ + 6) % 7
91
+ for (let i = from; i < 7; i++) fields[i] = i == 2 ? 1 : 0
92
+ const wall = wall_of_fields(fields)
93
+ if (zone !== undefined) {
94
+ const start = instant_of(wall, zone, true)
95
+ if (start <= time) return new Date(start)
96
+ }
97
+ const before = offset_in(wall - 86400000, zone)
98
+ const guess = wall - before
99
+ const after = offset_in(guess, zone)
100
+ const earliest = after == before
101
+ ? wall - offset_in(time, zone)
102
+ : wall - after
103
+ if (!(earliest >= -8.64e15)) return new Date(NaN)
104
+ return new Date(
105
+ transition_of(
106
+ earliest,
107
+ after == before || guess > time
108
+ ? time
109
+ : guess,
110
+ zone
111
+ )
112
+ )
113
+ }
@@ -0,0 +1,178 @@
1
+ import { fields_of_wall, last_day } from "./calendar.js"
2
+ import { check_zone, date_of, fields_of } from "./zone.js"
3
+ const comment_regex = /\([^)]*\)?/g
4
+ /** @type {Map<string, (number | number[])[]>} */
5
+ const formats = new Map()
6
+ const iso_regex = /^([+-]\d{6}|\d{4})(?:-(\d{2})(?:-(\d{2})(?:[T ](\d{2}):(\d{2})(?::(\d{2})(?:\.(\d+))?)?)?)?)?([^]*)$/
7
+ const token_regex = /DD|HH|MM|YYYY|mm|sss?/g
8
+ /** @type {Record<string, number[]>} */
9
+ const tokens = {
10
+ DD: [ 2, 2, 1, 31 ],
11
+ HH: [ 3, 2, 0, 23 ],
12
+ MM: [ 1, 2, 1, 12 ],
13
+ YYYY: [ 0, 4, 0, 275760 ],
14
+ mm: [ 4, 2, 0, 59 ],
15
+ ss: [ 5, 2, 0, 59 ],
16
+ sss: [ 6, 3, 0, 999 ]
17
+ }
18
+ const zone_regex = /(?<![a-z])(?:[cemp][ds]t|gmt|utc?|z)(?![a-z])|(?:\s|[ap]m|\d:\d\d?(?::\d\d?(?:\.\d*)?)?)[+-]\d/i
19
+ /**
20
+ * @param {string} format
21
+ * @returns {(number | number[])[]}
22
+ */
23
+ function compile(format) {
24
+ let parts = formats.get(format)
25
+ if (parts) return parts
26
+ parts = []
27
+ let last = 0
28
+ for (const { 0: token, index = 0 } of format.matchAll(token_regex)) {
29
+ if (index > last) parts.push(
30
+ [ ...format.slice(last, index) ].length
31
+ )
32
+ parts.push(
33
+ /** @type {number[]} */(tokens[token])/**/
34
+ )
35
+ last = index + token.length
36
+ }
37
+ if (last < format.length) parts.push(
38
+ [ ...format.slice(last) ].length
39
+ )
40
+ if (formats.size >= 1000) formats.clear()
41
+ formats.set(format, parts)
42
+ return parts
43
+ }
44
+ /**
45
+ * @param {RegExpExecArray} match
46
+ * @returns {boolean}
47
+ */
48
+ function out_of_range(match) {
49
+ const [ , year, month, day, hour, minute, second ] = match
50
+ if (month === undefined) return false
51
+ const index = +month - 1
52
+ return index < 0 || index > 11 || day !== undefined && (+day < 1 || +day > last_day(+(year ?? 0), index)) || +(hour ?? 0) > (+(minute ?? 0) || +(second ?? 0) || +(match[7] ?? 0)
53
+ ? 23
54
+ : 24) || +(minute ?? 0) > 59 || +(second ?? 0) > 59
55
+ }
56
+ /**
57
+ * Converts a date string to a Date object based on the provided format.
58
+ * Without a format the platform parser reads the string, so an offset such as `"Z"` is applied,
59
+ * while a date without a time is read as midnight. Out-of-range values give an invalid Date only in an
60
+ * ECMAScript date string: V8 rolls `"2025/02/30"` over to March 2, so check user input with a format.
61
+ * With a format, letters that are not a time unit only reserve their place, and a unit reads up to its own length of digits (`"sss"` reads them as a fraction, so `".5"` is 500 ms).
62
+ * `"YYYY"` also reads an expanded year such as `"+012345"`, and text left after the format gives an invalid Date.
63
+ * Missing units default to 0000-01-01T00:00:00.000, where a time zone is at its local mean time, so
64
+ * read a time alone in `"UTC"`. An invalid value returns an invalid Date.
65
+ * A wall clock inside a daylight saving gap moves forward, and one that occurs twice takes the
66
+ * first occurrence, as `new Date(year, month, day, hour)` does.
67
+ * @param {string} date
68
+ * @param {string=} format
69
+ * ```js
70
+ * e.g. "YYYY-MM-DDTHH:mm:ss.sss"
71
+ * ```
72
+ *
73
+ * Supported time units:
74
+ * - "YYYY": Years
75
+ * - "MM": Months
76
+ * - "DD": Days
77
+ * - "HH": Hours
78
+ * - "mm": Minutes
79
+ * - "ss": Seconds
80
+ * - "sss": Milliseconds
81
+ * @param {import("../public.js").TimeZone=} zone
82
+ * @returns {Date}
83
+ * @throws
84
+ * ```
85
+ * RangeError(`stringToDate: Invalid time zone "${zone}"`) // Intl.DateTimeFormat rejects the zone
86
+ * TypeError(`stringToDate: Expected a string, got ${typeof date}`)
87
+ * ```
88
+ * @example stringToDate("2024-07-15 09:00", "YYYY-MM-DD HH:mm", "Asia/Seoul")
89
+ */
90
+ export default function(date, format, zone) {
91
+ if (typeof date != "string") throw new TypeError(
92
+ `stringToDate: Expected a string, got ${date === null ? "null" : typeof date}`
93
+ )
94
+ check_zone("stringToDate", zone)
95
+ if (format === undefined) {
96
+ const native = new Date(date)
97
+ const valid = !isNaN(native.getTime())
98
+ if (!valid && zone === undefined) return native
99
+ const match = iso_regex.exec(date)
100
+ if (match && out_of_range(match)) return new Date(NaN)
101
+ const parsed = match?.[8] === ""
102
+ ? match
103
+ : null
104
+ if (parsed) {
105
+ if (zone === undefined && parsed[4] !== undefined) return native
106
+ if (!valid && isNaN(Date.parse(`${date}Z`))) return native
107
+ const fraction = parsed[7]
108
+ return date_of(
109
+ [
110
+ +(parsed[1] ?? NaN),
111
+ +(parsed[2] ?? 1) - 1,
112
+ +(parsed[3] ?? 1),
113
+ +(parsed[4] ?? 0),
114
+ +(parsed[5] ?? 0),
115
+ +(parsed[6] ?? 0),
116
+ fraction === undefined
117
+ ? 0
118
+ : +fraction.slice(0, 3).padEnd(3, "0")
119
+ ],
120
+ zone
121
+ )
122
+ }
123
+ if (zone === undefined) return native
124
+ const text = date.replace(comment_regex, "")
125
+ if (zone_regex.test(text)) return native
126
+ const wall = new Date(`${text} GMT`)
127
+ if (!valid && isNaN(wall.getTime())) return native
128
+ return date_of(
129
+ isNaN(wall.getTime())
130
+ ? fields_of(native)
131
+ : fields_of_wall(wall.getTime()),
132
+ zone
133
+ )
134
+ }
135
+ const fields = [ 0, 0, 1, 0, 0, 0, 0 ]
136
+ let index = 0
137
+ for (const part of compile(format)) {
138
+ if (typeof part == "number") {
139
+ for (let i = 0; i < part; i++) {
140
+ const code = date.charCodeAt(index)
141
+ index += code >= 0xd800 && code < 0xdc00 && date.charCodeAt(index + 1) >= 0xdc00 && date.charCodeAt(index + 1) < 0xe000
142
+ ? 2
143
+ : 1
144
+ }
145
+ continue
146
+ }
147
+ let text = ""
148
+ let length = /** @type {number} */(part[1])/**/
149
+ let min = /** @type {number} */(part[2])/**/
150
+ let sign = ""
151
+ const code = date.charCodeAt(index)
152
+ if (part[0] == 0 && (code == 43 || code == 45)) {
153
+ sign = code == 45
154
+ ? "-"
155
+ : "+"
156
+ index++
157
+ length = 6
158
+ min = -271821
159
+ }
160
+ while (text.length < length && date.charCodeAt(index) > 47 && date.charCodeAt(index) < 58) text += date[index++]
161
+ if (!text || sign && (text.length < 6 || sign == "-" && !+text)) return new Date(NaN)
162
+ if (part[0] == 6) {
163
+ while (date.charCodeAt(index) > 47 && date.charCodeAt(index) < 58) index++
164
+ }
165
+ const value = part[0] == 6
166
+ ? +text.padEnd(3, "0")
167
+ : +(sign + text)
168
+ if (value > /** @type {number} */(part[3])/**/ || value < min) return new Date(NaN)
169
+ fields[/** @type {number} */(part[0])/**/] = /** @type {number} */(part[0])/**/ == 1
170
+ ? value - 1
171
+ : value
172
+ }
173
+ if (index != date.length || /** @type {number} */(fields[2])/**/ > last_day(
174
+ /** @type {number} */(fields[0])/**/,
175
+ /** @type {number} */(fields[1])/**/
176
+ )) return new Date(NaN)
177
+ return date_of(fields, zone)
178
+ }
package/src/time_of.js ADDED
@@ -0,0 +1,15 @@
1
+ const get_time = Date.prototype.getTime
2
+ /**
3
+ * @param {string} name
4
+ * @param {Date} date
5
+ * @returns {number}
6
+ */
7
+ export default function(name, date) {
8
+ try {
9
+ return get_time.call(date)
10
+ } catch {
11
+ throw new TypeError(
12
+ `${name}: Expected a Date, got ${date === null ? "null" : typeof date}`
13
+ )
14
+ }
15
+ }
@@ -0,0 +1,6 @@
1
+ export default /** @type {const} */({
2
+ DD: 86400000,
3
+ HH: 3600000,
4
+ mm: 60000,
5
+ ss: 1000
6
+ })/**/
@@ -0,0 +1,22 @@
1
+ import time_of from "./time_of.js"
2
+ import { check_zone, offset_of } from "./zone.js"
3
+ /**
4
+ * Returns the offset of the time zone at the given date in milliseconds, east of UTC positive.
5
+ * Daylight saving time is taken from the given date, so a summer date gives the summer offset.
6
+ * @param {Date} date
7
+ * @param {import("../public.js").TimeZone} zone
8
+ * @returns {number}
9
+ * @throws
10
+ * ```
11
+ * RangeError(`timeZoneOffset: Invalid time zone "${zone}"`) // Intl.DateTimeFormat rejects the zone
12
+ * TypeError(`timeZoneOffset: Expected a Date, got ${typeof date}`)
13
+ * ```
14
+ * @example timeZoneOffset(new Date, "Asia/Seoul") //=> 32400000
15
+ */
16
+ export default function(date, zone) {
17
+ const time = time_of("timeZoneOffset", date)
18
+ check_zone("timeZoneOffset", zone)
19
+ return isNaN(time)
20
+ ? NaN
21
+ : offset_of(time, zone)
22
+ }
package/src/zone.js ADDED
@@ -0,0 +1,235 @@
1
+ import { fields_of_wall, wall_of_fields } from "./calendar.js"
2
+ const offset_regex = /GMT([+-])([0-9][0-9]):([0-9][0-9])(?::([0-9][0-9]))?/
3
+ /** @type {Map<string, Intl.DateTimeFormat>} */
4
+ const canonical = new Map()
5
+ /** @type {Map<string, Intl.DateTimeFormat>} */
6
+ const formatters = new Map()
7
+ /**
8
+ * @param {string} name
9
+ * @param {string=} zone
10
+ */
11
+ function check_zone(name, zone) {
12
+ if (zone === undefined || formatters.has(zone)) return
13
+ try {
14
+ formatter_of(zone)
15
+ } catch (error) {
16
+ throw new RangeError(
17
+ `${name}: Invalid time zone "${String(zone)}"`,
18
+ { cause: error }
19
+ )
20
+ }
21
+ }
22
+ /**
23
+ * @param {number[]} fields
24
+ * @param {string=} zone
25
+ * @returns {Date}
26
+ */
27
+ function date_of(fields, zone) {
28
+ if (zone !== undefined) return new Date(
29
+ instant_of(wall_of_fields(fields), zone)
30
+ )
31
+ const year = /** @type {number} */(fields[0])/**/
32
+ if (year >= 0 && year < 100) {
33
+ const date = new Date(0)
34
+ date.setFullYear(year, fields[1], fields[2])
35
+ date.setHours(
36
+ /** @type {number} */(fields[3])/**/,
37
+ fields[4],
38
+ fields[5],
39
+ fields[6]
40
+ )
41
+ return date
42
+ }
43
+ return new Date(
44
+ year,
45
+ /** @type {number} */(fields[1])/**/,
46
+ fields[2],
47
+ fields[3],
48
+ fields[4],
49
+ fields[5],
50
+ fields[6]
51
+ )
52
+ }
53
+ /**
54
+ * @param {number} wall
55
+ * @param {number} end
56
+ * @param {number} time
57
+ * @param {string=} zone
58
+ * @returns {number}
59
+ */
60
+ function end_at(wall, end, time, zone) {
61
+ if (end < time) return wall - offset_in(time, zone) - 1
62
+ const next = end + 1
63
+ const offset = offset_in(next, zone)
64
+ if (next + offset == wall || offset_in(end, zone) != offset) return end
65
+ const transition = transition_of(time, next, zone)
66
+ return transition + offset_in(transition, zone) >= wall
67
+ ? transition - 1
68
+ : end
69
+ }
70
+ /**
71
+ * @param {Date} date
72
+ * @param {string=} zone
73
+ * @returns {number[]}
74
+ */
75
+ function fields_of(date, zone) {
76
+ if (zone === undefined) return [
77
+ date.getFullYear(),
78
+ date.getMonth(),
79
+ date.getDate(),
80
+ date.getHours(),
81
+ date.getMinutes(),
82
+ date.getSeconds(),
83
+ date.getMilliseconds(),
84
+ date.getDay()
85
+ ]
86
+ const time = date.getTime()
87
+ return fields_of_wall(time + offset_of(time, zone))
88
+ }
89
+ /**
90
+ * @param {string} zone
91
+ * @returns {Intl.DateTimeFormat}
92
+ */
93
+ function formatter_of(zone) {
94
+ let formatter = formatters.get(zone)
95
+ if (formatter) return formatter
96
+ formatter = new Intl.DateTimeFormat(
97
+ "en-US",
98
+ {
99
+ timeZone: zone,
100
+ timeZoneName: "longOffset"
101
+ }
102
+ )
103
+ const name = formatter.resolvedOptions().timeZone
104
+ const known = canonical.get(name)
105
+ if (known) {
106
+ formatter = known
107
+ } else {
108
+ if (canonical.size >= 1000) canonical.clear()
109
+ canonical.set(name, formatter)
110
+ }
111
+ if (formatters.size >= 1000) formatters.clear()
112
+ formatters.set(zone, formatter)
113
+ return formatter
114
+ }
115
+ /**
116
+ * @param {number} wall
117
+ * @param {string} zone
118
+ * @param {boolean=} exact
119
+ * @returns {number}
120
+ */
121
+ function instant_of(wall, zone, exact) {
122
+ const before = offset_of(wall - 86400000, zone)
123
+ const guess = wall - before
124
+ const offset = offset_of(guess, zone)
125
+ if (offset == before) return guess
126
+ const candidate = wall - offset
127
+ return offset_of(candidate, zone) == offset
128
+ ? candidate
129
+ : exact
130
+ ? NaN
131
+ : guess
132
+ }
133
+ /**
134
+ * @param {number} time
135
+ * @param {string=} zone
136
+ * @returns {number}
137
+ */
138
+ function offset_in(time, zone) {
139
+ return zone === undefined
140
+ ? wall_of_fields(fields_of(new Date(time))) - time
141
+ : offset_of(time, zone)
142
+ }
143
+ /**
144
+ * @param {number} time
145
+ * @param {string} zone
146
+ * @returns {number}
147
+ */
148
+ function offset_of(time, zone) {
149
+ const match = offset_regex.exec(
150
+ formatter_of(zone).format(
151
+ time < -8.64e15
152
+ ? -8.64e15
153
+ : time <= 8.64e15
154
+ ? time
155
+ : 8.64e15
156
+ )
157
+ )
158
+ if (!match) return 0
159
+ return (match[1] == "-" ? -1 : 1) * (
160
+ (+(match[2] ?? 0) * 60 + +(match[3] ?? 0)) * 60000
161
+ + +(match[4] ?? 0) * 1000
162
+ )
163
+ }
164
+ /**
165
+ * @param {number} from
166
+ * @param {number} to
167
+ * @param {string=} zone
168
+ * @returns {number}
169
+ */
170
+ function transition_of(from, to, zone) {
171
+ const offset = offset_in(to, zone)
172
+ while (to - from > 1) {
173
+ const middle = Math.floor((from + to) / 2)
174
+ if (offset_in(middle, zone) == offset) to = middle
175
+ else from = middle
176
+ }
177
+ return to
178
+ }
179
+ /**
180
+ * @param {number} time
181
+ * @param {number} ms
182
+ * @param {string=} zone
183
+ * @returns {number}
184
+ */
185
+ function unit_end(time, ms, zone) {
186
+ const bucket = Math.floor(
187
+ (time + offset_in(time, zone)) / ms
188
+ )
189
+ let at = time
190
+ for (;;) {
191
+ const offset = offset_in(at, zone)
192
+ const end = (bucket + 1) * ms - offset - 1
193
+ if (!(end <= 8.64e15)) return NaN
194
+ if (offset_in(end, zone) == offset) return end
195
+ const transition = transition_of(at, end, zone)
196
+ const wall = transition + offset_in(transition, zone)
197
+ if (Math.floor(wall / ms) != bucket || wall <= transition - 1 + offset) return transition - 1
198
+ at = transition
199
+ }
200
+ }
201
+ /**
202
+ * @param {number} time
203
+ * @param {number} ms
204
+ * @param {string=} zone
205
+ * @returns {number}
206
+ */
207
+ function unit_start(time, ms, zone) {
208
+ const bucket = Math.floor(
209
+ (time + offset_in(time, zone)) / ms
210
+ )
211
+ let at = time
212
+ for (;;) {
213
+ const offset = offset_in(at, zone)
214
+ const start = bucket * ms - offset
215
+ if (!(start >= -8.64e15)) return NaN
216
+ if (offset_in(start, zone) == offset) return start
217
+ const transition = transition_of(start, at, zone)
218
+ const before = transition - 1
219
+ const wall = before + offset_in(before, zone)
220
+ if (Math.floor(wall / ms) != bucket || wall >= transition + offset) return transition
221
+ at = before
222
+ }
223
+ }
224
+ export {
225
+ check_zone,
226
+ date_of,
227
+ end_at,
228
+ fields_of,
229
+ instant_of,
230
+ offset_in,
231
+ offset_of,
232
+ transition_of,
233
+ unit_end,
234
+ unit_start
235
+ }
package/types/add.d.ts ADDED
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Calculates and adds the specified time duration to the provided date and returns a new Date.
3
+ * Years and months are clamped to the end of the month, e.g. Jan 31 + 1M is Feb 28 or 29.
4
+ * Days follow the clock, so a day over a daylight saving change is 23 or 25 hours,
5
+ * while hours, minutes, seconds and milliseconds are elapsed time.
6
+ * A part of zero adds nothing; any other part of years, months, weeks or days lands on a clock time,
7
+ * which moves forward out of a daylight saving gap and takes the first occurrence of an hour that repeats.
8
+ * @param {Date} date
9
+ * @param {string} sum
10
+ * ```
11
+ * e.g. "1Y2M 3D"
12
+ * ```
13
+ *
14
+ * Supported time units:
15
+ * - "Y": Years
16
+ * - "M": Months
17
+ * - "W": Weeks
18
+ * - "D": Days
19
+ * - "H": Hours
20
+ * - "m": Minutes
21
+ * - "s": Seconds
22
+ * - "sss": Milliseconds
23
+ * @param {import("../public.js").TimeZone=} zone
24
+ * @returns {Date}
25
+ * @throws
26
+ * ```
27
+ * RangeError(`add: Invalid duration "${sum}"`) // sum is empty, or a part of it is not a number followed by a unit
28
+ * RangeError(`add: Invalid time zone "${zone}"`) // Intl.DateTimeFormat rejects the zone
29
+ * TypeError(`add: Expected a Date, got ${typeof date}`)
30
+ * ```
31
+ * @example add(new Date, "-1D") //=> Date { yesterday }
32
+ */
33
+ export default function (date: Date, sum: string, zone?: import("../public.js").TimeZone | undefined): Date;
34
+ //# sourceMappingURL=add.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../src/add.js"],"names":[],"mappings":"AAqEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,MAAM,CAAC,OAAO,WAAU,IAAI,EAzBjB,IAyBiB,EAAE,GAAG,EAxBtB,MAwBsB,EAAE,IAAI,AAVpC,CACA,EADQ,OAAO,cAAc,EAAE,QAAQ,YAUH,GAT1B,IAAI,CAuDhB"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * @param {number} year
3
+ * @param {number} month
4
+ * @param {number} day
5
+ * @returns {number}
6
+ */
7
+ declare function days_of(year: number, month: number, day: number): number;
8
+ /**
9
+ * @param {number} wall
10
+ * @returns {number[]}
11
+ */
12
+ declare function fields_of_wall(wall: number): number[];
13
+ /**
14
+ * @param {number} year
15
+ * @param {number} month
16
+ * @returns {number}
17
+ */
18
+ declare function last_day(year: number, month: number): number;
19
+ /**
20
+ * @param {number[]} fields
21
+ * @returns {number}
22
+ */
23
+ declare function wall_of_fields(fields: number[]): number;
24
+ export { days_of, fields_of_wall, last_day, wall_of_fields };
25
+ //# sourceMappingURL=calendar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"calendar.d.ts","sourceRoot":"","sources":["../src/calendar.js"],"names":[],"mappings":"AACA;;;;;GAKG;AACH,iBAAS,OAAO,CAAC,IAAI,EALV,MAKU,EAAE,KAAK,EAJjB,MAIiB,EAAE,GAAG,EAHtB,MAGsB,GAFpB,MAAM,CAmBlB;AACD;;;GAGG;AACH,iBAAS,cAAc,CAAC,IAAI,EAHjB,MAGiB,GAFf,MAAM,EAAE,CA6BpB;AACD;;;;GAIG;AACH,iBAAS,QAAQ,CAAC,IAAI,EAJX,MAIW,EAAE,KAAK,EAHlB,MAGkB,GAFhB,MAAM,CAMlB;AACD;;;GAGG;AACH,iBAAS,cAAc,CAAC,MAAM,EAHnB,MAAM,EAGa,GAFjB,MAAM,CAYlB;AACD,OAAO,EACN,OAAO,EACP,cAAc,EACd,QAAQ,EACR,cAAc,EACd,CAAA"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Converts a Date object to a formatted string representation.
3
+ * Letters that are not a time unit are kept as they are, so `"HHhmm"` gives `"11h22"`.
4
+ * A year before 0 or after 9999 is printed as an expanded year, such as `"+012345"`.
5
+ * @param {Date} date
6
+ * @param {string=} format
7
+ * ```js
8
+ * = "YYYY-MM-DDTHH:mm:ss.sss"
9
+ * ```
10
+ *
11
+ * Supported time units:
12
+ * - "YYYY": Years
13
+ * - "MM": Months
14
+ * - "DD": Days
15
+ * - "HH": Hours
16
+ * - "mm": Minutes
17
+ * - "ss": Seconds
18
+ * - "sss": Milliseconds
19
+ * @param {import("../public.js").TimeZone=} zone
20
+ * @returns {string}
21
+ * @throws
22
+ * ```
23
+ * RangeError(`dateToString: Invalid time zone "${zone}"`) // Intl.DateTimeFormat rejects the zone
24
+ * TypeError(`dateToString: Expected a Date, got ${typeof date}`)
25
+ * ```
26
+ * @example dateToString(new Date, "YYYY-MM-DD HH:mm", "Asia/Seoul") //=> "2024-07-15 21:00"
27
+ */
28
+ export default function (date: Date, format?: string | undefined, zone?: import("../public.js").TimeZone | undefined): string;
29
+ //# sourceMappingURL=date_to_string.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"date_to_string.d.ts","sourceRoot":"","sources":["../src/date_to_string.js"],"names":[],"mappings":"AAsDA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,CAAC,OAAO,WACb,IAAI,EAxBM,IAwBN,EACJ,MAAM,AAxBJ,CAaA,EAbQ,MAAM,YAwBkB,EAClC,IAAI,AAZF,CACA,EADQ,OAAO,cAAc,EAAE,QAAQ,YAYrC,GAXQ,MAAM,CAgClB"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Counts the whole units from one date to another, negative when the second date is earlier.
3
+ * Years, months, weeks and days follow the clock, so a day over a daylight saving change still
4
+ * counts as one day, while hours, minutes, seconds and milliseconds are elapsed time.
5
+ * @param {Date} from
6
+ * @param {Date} to
7
+ * @param {import("../public.js").Unit} unit
8
+ * ```
9
+ * "Y" | "M" | "W" | "D" | "H" | "m" | "s" | "sss"
10
+ * ```
11
+ * @param {import("../public.js").TimeZone=} zone
12
+ * @returns {number}
13
+ * @throws
14
+ * ```
15
+ * RangeError(`diff: Invalid unit "${unit}"`) // The unit is not one of the listed ones
16
+ * RangeError(`diff: Invalid time zone "${zone}"`) // Intl.DateTimeFormat rejects the zone
17
+ * TypeError(`diff: Expected a Date, got ${typeof from}`) // from or to is not a Date
18
+ * ```
19
+ * @example diff(start, end, "D") //=> 30
20
+ */
21
+ export default function (from: Date, to: Date, unit: import("../public.js").Unit, zone?: import("../public.js").TimeZone | undefined): number;
22
+ //# sourceMappingURL=diff.d.ts.map