temporal-fmt 0.9.4 → 0.9.5
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/LICENSE +196 -17
- package/README.md +11 -5
- package/dist/calendarUtils.cjs +17 -9
- package/dist/calendarUtils.cjs.map +1 -1
- package/dist/calendarUtils.js +2 -2
- package/dist/{chunk-VNIUIQA4.js → chunk-3FMUGYE2.js} +217 -52
- package/dist/chunk-3FMUGYE2.js.map +1 -0
- package/dist/{chunk-H7YQX25T.js → chunk-64UB3WDT.js} +73 -8
- package/dist/chunk-64UB3WDT.js.map +1 -0
- package/dist/{chunk-M3GDTHMT.js → chunk-AN4UFCLA.js} +16 -11
- package/dist/chunk-AN4UFCLA.js.map +1 -0
- package/dist/{chunk-MKPDLQKD.js → chunk-BLZDBPSV.js} +19 -8
- package/dist/chunk-BLZDBPSV.js.map +1 -0
- package/dist/{chunk-ACKKWH5Z.js → chunk-BZPNSQHI.js} +43 -40
- package/dist/chunk-BZPNSQHI.js.map +1 -0
- package/dist/{chunk-UOPAV3WX.js → chunk-CGI4FL6H.js} +2 -2
- package/dist/chunk-CGI4FL6H.js.map +1 -0
- package/dist/{chunk-ZQZF5EXW.js → chunk-DFWTCRS3.js} +1 -1
- package/dist/chunk-DFWTCRS3.js.map +1 -0
- package/dist/{chunk-FBPHNRVW.js → chunk-E2FBHVQW.js} +179 -85
- package/dist/chunk-E2FBHVQW.js.map +1 -0
- package/dist/{chunk-GPB4JHGI.js → chunk-G6RYR72T.js} +4 -4
- package/dist/chunk-G6RYR72T.js.map +1 -0
- package/dist/{chunk-HXY2GUUM.js → chunk-KEPIXQK7.js} +4 -4
- package/dist/chunk-KEPIXQK7.js.map +1 -0
- package/dist/{chunk-L24NPTAJ.js → chunk-LPSNAV3S.js} +29 -7
- package/dist/chunk-LPSNAV3S.js.map +1 -0
- package/dist/{chunk-EGUUO6LE.js → chunk-OLNU4LON.js} +1 -1
- package/dist/chunk-OLNU4LON.js.map +1 -0
- package/dist/{chunk-4N3WCGEY.js → chunk-QIZ2MXS2.js} +16 -7
- package/dist/chunk-QIZ2MXS2.js.map +1 -0
- package/dist/{chunk-TSLPIURC.js → chunk-SC6ENLEB.js} +11 -38
- package/dist/chunk-SC6ENLEB.js.map +1 -0
- package/dist/{chunk-YEUASGDK.js → chunk-SOPTTXUI.js} +1 -1
- package/dist/chunk-SOPTTXUI.js.map +1 -0
- package/dist/{chunk-5UTV5VP6.js → chunk-T7EKGDQT.js} +6 -6
- package/dist/chunk-T7EKGDQT.js.map +1 -0
- package/dist/config.d.cts +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/duration.cjs +32 -23
- package/dist/duration.cjs.map +1 -1
- package/dist/duration.js +5 -5
- package/dist/format.cjs +59 -20
- package/dist/format.cjs.map +1 -1
- package/dist/format.js +7 -7
- package/dist/index.cjs +581 -240
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +44 -29
- package/dist/index.js.map +1 -1
- package/dist/interval.cjs +472 -196
- package/dist/interval.cjs.map +1 -1
- package/dist/interval.js +15 -15
- package/dist/isoWeek.d.cts +2 -0
- package/dist/isoWeek.d.ts +2 -0
- package/dist/localeRegistry.cjs.map +1 -1
- package/dist/localeRegistry.js +2 -2
- package/dist/parse.cjs +48 -18
- package/dist/parse.cjs.map +1 -1
- package/dist/parse.js +7 -7
- package/dist/recurrence.cjs +222 -62
- package/dist/recurrence.cjs.map +1 -1
- package/dist/recurrence.d.cts +5 -0
- package/dist/recurrence.d.ts +5 -0
- package/dist/recurrence.js +4 -4
- package/dist/relativeTime.cjs +12 -8
- package/dist/relativeTime.cjs.map +1 -1
- package/dist/relativeTime.js +7 -7
- package/dist/timezone.cjs +87 -33
- package/dist/timezone.cjs.map +1 -1
- package/dist/timezone.js +5 -5
- package/dist/tokenize.d.cts +14 -0
- package/dist/tokenize.d.ts +14 -0
- package/package.json +4 -4
- package/scripts/cli.mjs +8 -2
- package/dist/chunk-4N3WCGEY.js.map +0 -1
- package/dist/chunk-5UTV5VP6.js.map +0 -1
- package/dist/chunk-ACKKWH5Z.js.map +0 -1
- package/dist/chunk-EGUUO6LE.js.map +0 -1
- package/dist/chunk-FBPHNRVW.js.map +0 -1
- package/dist/chunk-GPB4JHGI.js.map +0 -1
- package/dist/chunk-H7YQX25T.js.map +0 -1
- package/dist/chunk-HXY2GUUM.js.map +0 -1
- package/dist/chunk-L24NPTAJ.js.map +0 -1
- package/dist/chunk-M3GDTHMT.js.map +0 -1
- package/dist/chunk-MKPDLQKD.js.map +0 -1
- package/dist/chunk-TSLPIURC.js.map +0 -1
- package/dist/chunk-UOPAV3WX.js.map +0 -1
- package/dist/chunk-VNIUIQA4.js.map +0 -1
- package/dist/chunk-YEUASGDK.js.map +0 -1
- package/dist/chunk-ZQZF5EXW.js.map +0 -1
|
@@ -1,20 +1,17 @@
|
|
|
1
1
|
import {
|
|
2
2
|
add
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-SC6ENLEB.js";
|
|
4
4
|
import {
|
|
5
5
|
asDateFieldView
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-KEPIXQK7.js";
|
|
7
|
+
import {
|
|
8
|
+
dayOfWeekFromCivil,
|
|
9
|
+
daysFromCivil
|
|
10
|
+
} from "./chunk-BLZDBPSV.js";
|
|
7
11
|
|
|
8
12
|
// src/comparison.ts
|
|
9
13
|
function toComparableMs(view) {
|
|
10
|
-
const
|
|
11
|
-
const y2 = m <= 2 ? y - 1 : y;
|
|
12
|
-
const era = Math.floor((y2 >= 0 ? y2 : y2 - 399) / 400);
|
|
13
|
-
const yoe = y2 - era * 400;
|
|
14
|
-
const m2 = m > 2 ? m - 3 : m + 9;
|
|
15
|
-
const doy = Math.floor((153 * m2 + 2) / 5) + d - 1;
|
|
16
|
-
const doe = yoe * 365 + Math.floor(yoe / 4) - Math.floor(yoe / 100) + doy;
|
|
17
|
-
const days = era * 146097 + doe - 719468;
|
|
14
|
+
const days = daysFromCivil(view.year, view.month, view.day);
|
|
18
15
|
const MS_PER_HOUR = 36e5;
|
|
19
16
|
const MS_PER_MINUTE = 6e4;
|
|
20
17
|
const MS_PER_SECOND = 1e3;
|
|
@@ -104,27 +101,17 @@ function isYesterday(value) {
|
|
|
104
101
|
return dateEqualYearMonthDay(readYearMonthDay(value), yesterdayYearMonthDay());
|
|
105
102
|
}
|
|
106
103
|
function sameWeek(yearA, monthA, dayA, yearB, monthB, dayB) {
|
|
107
|
-
const DAYS_PER_400_YEARS = 146097;
|
|
108
104
|
const daysSince = (y, m, d) => {
|
|
109
|
-
|
|
110
|
-
const era = (y2 >= 0 ? y2 : y2 - 399) / 400 | 0;
|
|
111
|
-
const yoe = y2 - era * 400;
|
|
112
|
-
const m2 = m > 2 ? m - 3 : m + 9;
|
|
113
|
-
const doy = Math.floor(Math.floor(153 * m2 + 2) / 5 + d - 1);
|
|
114
|
-
const doe = yoe * 365 + Math.floor(yoe / 4) - Math.floor(yoe / 100) + doy;
|
|
115
|
-
return era * DAYS_PER_400_YEARS + doe - 719468;
|
|
105
|
+
return daysFromCivil(y, m, d);
|
|
116
106
|
};
|
|
117
107
|
const a = daysSince(yearA, monthA, dayA);
|
|
118
108
|
const b = daysSince(yearB, monthB, dayB);
|
|
119
109
|
if (Math.abs(a - b) >= 7) return false;
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
const date = new Date(Date.UTC(y, m - 1, d));
|
|
123
|
-
const jsDow = date.getUTCDay();
|
|
124
|
-
return jsDow === 0 ? 7 : jsDow;
|
|
110
|
+
const weekdayOf2 = (y, m, d) => {
|
|
111
|
+
return dayOfWeekFromCivil(y, m, d);
|
|
125
112
|
};
|
|
126
|
-
const wa = a - (
|
|
127
|
-
const wb = b - (
|
|
113
|
+
const wa = a - (weekdayOf2(yearA, monthA, dayA) - 1);
|
|
114
|
+
const wb = b - (weekdayOf2(yearB, monthB, dayB) - 1);
|
|
128
115
|
return wa === wb;
|
|
129
116
|
}
|
|
130
117
|
function isSameWeek(value, reference) {
|
|
@@ -162,52 +149,173 @@ function isWeekday(value) {
|
|
|
162
149
|
}
|
|
163
150
|
|
|
164
151
|
// src/recurrence.ts
|
|
152
|
+
function daysInMonthOf(year, month) {
|
|
153
|
+
const LENGTHS = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
|
154
|
+
const leap = year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;
|
|
155
|
+
return month === 2 && leap ? 29 : LENGTHS[month - 1];
|
|
156
|
+
}
|
|
157
|
+
function weekdayOf(year, month, day) {
|
|
158
|
+
const days = daysFromCivil(year, month, day);
|
|
159
|
+
return ((days + 3) % 7 + 7) % 7 + 1;
|
|
160
|
+
}
|
|
161
|
+
function nthWeekdayDay(year, month, weekday, ordinal) {
|
|
162
|
+
const last = daysInMonthOf(year, month);
|
|
163
|
+
if (ordinal > 0) {
|
|
164
|
+
const firstDow = weekdayOf(year, month, 1);
|
|
165
|
+
const first = 1 + (weekday - firstDow + 7) % 7;
|
|
166
|
+
const day2 = first + (ordinal - 1) * 7;
|
|
167
|
+
return day2 <= last ? day2 : null;
|
|
168
|
+
}
|
|
169
|
+
const lastDow = weekdayOf(year, month, last);
|
|
170
|
+
const lastOccurrence = last - (lastDow - weekday + 7) % 7;
|
|
171
|
+
const day = lastOccurrence + (ordinal + 1) * 7;
|
|
172
|
+
return day >= 1 ? day : null;
|
|
173
|
+
}
|
|
165
174
|
function recurrence(start, rule) {
|
|
166
|
-
|
|
167
|
-
|
|
175
|
+
if (rule.count !== void 0 && (!Number.isSafeInteger(rule.count) || rule.count < 1)) {
|
|
176
|
+
throw new RangeError(`temporal-fmt: recurrence rule count must be a positive safe integer (got ${String(rule.count)}).`);
|
|
177
|
+
}
|
|
178
|
+
const interval = rule.interval !== void 0 && rule.interval !== null ? rule.interval : 1;
|
|
179
|
+
if (!Number.isSafeInteger(interval) || interval < 1) {
|
|
180
|
+
throw new RangeError(`temporal-fmt: recurrence rule interval must be a positive safe integer (got ${String(rule.interval)}).`);
|
|
181
|
+
}
|
|
182
|
+
if (rule.byMonthDay && rule.byMonthDay.some((d) => !Number.isSafeInteger(d) || d === 0 || d < -31 || d > 31)) {
|
|
183
|
+
throw new RangeError("temporal-fmt: recurrence rule byMonthDay entries must be nonzero integers in [-31, 31].");
|
|
184
|
+
}
|
|
185
|
+
if (rule.byWeekday && rule.byWeekday.some((d) => !Number.isSafeInteger(d) || d < 1 || d > 7)) {
|
|
186
|
+
throw new RangeError("temporal-fmt: recurrence rule byWeekday entries must be ISO weekdays 1 (Mon) through 7 (Sun).");
|
|
187
|
+
}
|
|
188
|
+
if (rule.byMonth && rule.byMonth.some((m) => !Number.isSafeInteger(m) || m < 1 || m > 12)) {
|
|
189
|
+
throw new RangeError("temporal-fmt: recurrence rule byMonth entries must be months 1 through 12.");
|
|
190
|
+
}
|
|
191
|
+
if (rule.byWeekdayOrdinal && rule.byWeekdayOrdinal.some((o) => !Number.isSafeInteger(o.ordinal) || o.ordinal === 0 || o.ordinal < -53 || o.ordinal > 53 || !Number.isSafeInteger(o.weekday) || o.weekday < 1 || o.weekday > 7)) {
|
|
192
|
+
throw new RangeError("temporal-fmt: recurrence rule byWeekdayOrdinal entries need a nonzero ordinal in [-53, 53] and an ISO weekday 1-7.");
|
|
193
|
+
}
|
|
168
194
|
const history = [];
|
|
169
195
|
const MAX_HISTORY = 1e4;
|
|
170
196
|
let atEnd = false;
|
|
171
197
|
let atStart = true;
|
|
198
|
+
const anchor = asDateFieldView(start);
|
|
199
|
+
const originDayCount = daysFromCivil(anchor.year, anchor.month, anchor.day);
|
|
200
|
+
let current = start;
|
|
201
|
+
if (rule.byWeekday && rule.byWeekday.length > 0 && typeof start.dayOfWeek !== "number") {
|
|
202
|
+
current = { ...anchor, dayOfWeek: weekdayOf(anchor.year, anchor.month, anchor.day) };
|
|
203
|
+
}
|
|
204
|
+
let count = 0;
|
|
172
205
|
function matches(value) {
|
|
173
206
|
const v = value;
|
|
174
207
|
if (rule.byWeekday && rule.byWeekday.length > 0) {
|
|
208
|
+
/* c8 ignore next @preserve */
|
|
175
209
|
if (!rule.byWeekday.includes(v.dayOfWeek ?? 0)) return false;
|
|
176
210
|
}
|
|
211
|
+
if (rule.byWeekdayOrdinal && rule.byWeekdayOrdinal.length > 0 && (rule.frequency === "monthly" || rule.frequency === "yearly")) {
|
|
212
|
+
/* c8 ignore next @preserve */
|
|
213
|
+
const plainOk = !!rule.byWeekday && rule.byWeekday.length > 0 && rule.byWeekday.includes(v.dayOfWeek ?? 0);
|
|
214
|
+
/* c8 ignore next @preserve */
|
|
215
|
+
const ordinalOk = (rule.byWeekdayOrdinal ?? []).some((o) => (
|
|
216
|
+
/* c8 ignore next @preserve */
|
|
217
|
+
nthWeekdayDay(v.year ?? 0, v.month ?? 0, o.weekday, o.ordinal) === (v.day ?? 0)
|
|
218
|
+
));
|
|
219
|
+
if (!plainOk && !ordinalOk) return false;
|
|
220
|
+
}
|
|
177
221
|
if (rule.byMonthDay && rule.byMonthDay.length > 0) {
|
|
178
|
-
|
|
222
|
+
/* c8 ignore next @preserve */
|
|
223
|
+
const day = v.day ?? 0;
|
|
224
|
+
/* c8 ignore next @preserve */
|
|
225
|
+
const last = daysInMonthOf(v.year ?? 0, v.month ?? 0);
|
|
226
|
+
/* c8 ignore next @preserve */
|
|
227
|
+
const hit = (rule.byMonthDay ?? []).some((d) => d > 0 ? d === day : d + last + 1 === day);
|
|
228
|
+
if (!hit) return false;
|
|
179
229
|
}
|
|
180
230
|
if (rule.byMonth && rule.byMonth.length > 0) {
|
|
231
|
+
/* c8 ignore next @preserve */
|
|
181
232
|
if (!rule.byMonth.includes(v.month ?? 0)) return false;
|
|
182
233
|
}
|
|
183
234
|
if (rule.exDates && rule.exDates.some((d) => compare(d, value) === 0)) return false;
|
|
184
235
|
return true;
|
|
185
236
|
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
237
|
+
let pending = [];
|
|
238
|
+
let periodIndex = 0;
|
|
239
|
+
function fillNextPeriod() {
|
|
240
|
+
const k = periodIndex;
|
|
241
|
+
periodIndex++;
|
|
242
|
+
let year;
|
|
243
|
+
let months;
|
|
244
|
+
if (rule.frequency === "monthly") {
|
|
245
|
+
const totalMonths = anchor.year * 12 + anchor.month - 1 + k * interval;
|
|
246
|
+
year = Math.floor(totalMonths / 12);
|
|
247
|
+
months = [totalMonths - year * 12 + 1];
|
|
248
|
+
} else {
|
|
249
|
+
year = anchor.year + k * interval;
|
|
250
|
+
months = rule.byMonth && rule.byMonth.length > 0 ? [...rule.byMonth].sort((a, b) => a - b) : [anchor.month];
|
|
251
|
+
}
|
|
252
|
+
const days = [];
|
|
253
|
+
for (const m of months) {
|
|
254
|
+
const last = daysInMonthOf(year, m);
|
|
255
|
+
if (rule.byMonthDay && rule.byMonthDay.length > 0) {
|
|
256
|
+
for (const d of rule.byMonthDay) {
|
|
257
|
+
const real = d > 0 ? d : last + 1 + d;
|
|
258
|
+
if (real >= 1 && real <= last) days.push({ month: m, day: real });
|
|
259
|
+
}
|
|
260
|
+
} else if (rule.byWeekdayOrdinal && rule.byWeekdayOrdinal.length > 0) {
|
|
261
|
+
for (const o of rule.byWeekdayOrdinal) {
|
|
262
|
+
const real = nthWeekdayDay(year, m, o.weekday, o.ordinal);
|
|
263
|
+
if (real !== null) days.push({ month: m, day: real });
|
|
264
|
+
}
|
|
265
|
+
} else {
|
|
266
|
+
if (anchor.day <= last) days.push({ month: m, day: anchor.day });
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
days.sort((a, b) => a.month - b.month || a.day - b.day);
|
|
270
|
+
pending = days.map(({ month, day }) => ({
|
|
271
|
+
...anchor,
|
|
272
|
+
year,
|
|
273
|
+
month,
|
|
274
|
+
day,
|
|
275
|
+
dayOfWeek: weekdayOf(year, month, day)
|
|
276
|
+
}));
|
|
193
277
|
}
|
|
194
278
|
function nextMatch(value) {
|
|
195
279
|
let candidate = value;
|
|
196
280
|
let safetyCounter = 0;
|
|
197
|
-
|
|
198
|
-
|
|
281
|
+
const daywise = rule.frequency === "weekly" && !!rule.byWeekday && rule.byWeekday.length > 0;
|
|
282
|
+
const periodwise = rule.frequency === "monthly" || rule.frequency === "yearly";
|
|
283
|
+
const unit = rule.frequency === "secondly" ? "seconds" : rule.frequency === "minutely" ? "minutes" : rule.frequency === "hourly" ? "hours" : rule.frequency === "daily" ? "days" : "weeks";
|
|
284
|
+
while (true) {
|
|
199
285
|
safetyCounter++;
|
|
200
|
-
if (safetyCounter >
|
|
286
|
+
if (safetyCounter > 2e3) {
|
|
201
287
|
atEnd = true;
|
|
202
288
|
return { value: candidate, found: false };
|
|
203
289
|
}
|
|
290
|
+
if (daywise) {
|
|
291
|
+
candidate = add(candidate, 1, "days");
|
|
292
|
+
if (interval > 1) {
|
|
293
|
+
const v = asDateFieldView(candidate);
|
|
294
|
+
const dayCount = daysFromCivil(v.year, v.month, v.day);
|
|
295
|
+
if (Math.floor((dayCount - originDayCount) / 7) % interval !== 0) continue;
|
|
296
|
+
}
|
|
297
|
+
} else if (periodwise) {
|
|
298
|
+
if (pending.length === 0) {
|
|
299
|
+
fillNextPeriod();
|
|
300
|
+
if (pending.length === 0) continue;
|
|
301
|
+
}
|
|
302
|
+
candidate = pending.shift();
|
|
303
|
+
if (compare(candidate, value) <= 0) continue;
|
|
304
|
+
} else {
|
|
305
|
+
candidate = add(candidate, interval, unit);
|
|
306
|
+
}
|
|
204
307
|
if (rule.until && compare(candidate, rule.until) > 0) {
|
|
205
308
|
atEnd = true;
|
|
206
309
|
return { value: candidate, found: false };
|
|
207
310
|
}
|
|
208
|
-
|
|
311
|
+
if (matches(candidate)) break;
|
|
312
|
+
}
|
|
209
313
|
return { value: candidate, found: true };
|
|
210
314
|
}
|
|
315
|
+
function recordHistory(value) {
|
|
316
|
+
history.push(value);
|
|
317
|
+
if (history.length > MAX_HISTORY) history.shift();
|
|
318
|
+
}
|
|
211
319
|
return {
|
|
212
320
|
next() {
|
|
213
321
|
if (atEnd) return { value: void 0, done: true };
|
|
@@ -256,8 +364,14 @@ function take(iter, n) {
|
|
|
256
364
|
return result;
|
|
257
365
|
}
|
|
258
366
|
var MAX_SKIP_COLLECTION = 1e5;
|
|
367
|
+
var MAX_SKIP_STEPS = 1e6;
|
|
259
368
|
function skip(iter, n) {
|
|
260
369
|
for (let i = 0; i < n; i++) {
|
|
370
|
+
if (i >= MAX_SKIP_STEPS) {
|
|
371
|
+
throw new RangeError(
|
|
372
|
+
`temporal-fmt: skip() was asked to skip more than ${MAX_SKIP_STEPS} occurrences \u2014 that's not a bounded operation; use take() on a count/until-bounded rule instead.`
|
|
373
|
+
);
|
|
374
|
+
}
|
|
261
375
|
const r = iter.next();
|
|
262
376
|
if (r.done) break;
|
|
263
377
|
}
|
|
@@ -274,7 +388,14 @@ function skip(iter, n) {
|
|
|
274
388
|
function between(start, rule, rangeStart, rangeEnd) {
|
|
275
389
|
const iter = recurrence(start, rule);
|
|
276
390
|
const result = [];
|
|
391
|
+
const MAX_TRAVERSAL = 1e6;
|
|
392
|
+
let traversed = 0;
|
|
277
393
|
while (true) {
|
|
394
|
+
if (traversed++ > MAX_TRAVERSAL) {
|
|
395
|
+
throw new RangeError(
|
|
396
|
+
`temporal-fmt: between() walked more than ${MAX_TRAVERSAL} occurrences without reaching rangeEnd \u2014 pass a start closer to the range, or bound the rule with count/until.`
|
|
397
|
+
);
|
|
398
|
+
}
|
|
278
399
|
const r = iter.next();
|
|
279
400
|
if (r.done) break;
|
|
280
401
|
if (compare(r.value, rangeEnd) >= 0) break;
|
|
@@ -282,6 +403,27 @@ function between(start, rule, rangeStart, rangeEnd) {
|
|
|
282
403
|
}
|
|
283
404
|
return result;
|
|
284
405
|
}
|
|
406
|
+
function parseUntil(value) {
|
|
407
|
+
const m = /^(\d{4})(\d{2})(\d{2})(?:T(\d{2})(\d{2})(\d{2})Z?)?$/.exec(value.trim());
|
|
408
|
+
if (!m) {
|
|
409
|
+
throw new RangeError(
|
|
410
|
+
`temporal-fmt: RRULE UNTIL must be a date ("20240110") or UTC date-time ("20240110T153000Z") \u2014 got "${value}".`
|
|
411
|
+
);
|
|
412
|
+
}
|
|
413
|
+
const year = Number(m[1]);
|
|
414
|
+
const month = Number(m[2]);
|
|
415
|
+
const day = Number(m[3]);
|
|
416
|
+
if (month < 1 || month > 12 || day < 1 || day > 31) {
|
|
417
|
+
throw new RangeError(`temporal-fmt: RRULE UNTIL carries an out-of-range date "${value}".`);
|
|
418
|
+
}
|
|
419
|
+
const hour = m[4] !== void 0 ? Number(m[4]) : void 0;
|
|
420
|
+
const minute = m[5] !== void 0 ? Number(m[5]) : void 0;
|
|
421
|
+
const second = m[6] !== void 0 ? Number(m[6]) : void 0;
|
|
422
|
+
if (hour !== void 0 && (hour > 23 || minute > 59 || second > 59)) {
|
|
423
|
+
throw new RangeError(`temporal-fmt: RRULE UNTIL carries an out-of-range time "${value}".`);
|
|
424
|
+
}
|
|
425
|
+
return { year, month, day, hour, minute, second };
|
|
426
|
+
}
|
|
285
427
|
function parseRRule(input) {
|
|
286
428
|
const parts = input.trim().toUpperCase().replace(/^RRULE:/, "").split(";");
|
|
287
429
|
const rule = { frequency: "daily", interval: 1 };
|
|
@@ -324,17 +466,32 @@ function parseRRule(input) {
|
|
|
324
466
|
break;
|
|
325
467
|
}
|
|
326
468
|
case "UNTIL":
|
|
327
|
-
rule.until = value;
|
|
469
|
+
rule.until = parseUntil(value);
|
|
328
470
|
break;
|
|
329
|
-
case "BYDAY":
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
const
|
|
335
|
-
|
|
336
|
-
|
|
471
|
+
case "BYDAY": {
|
|
472
|
+
const WEEKDAY_MAP = { MO: 1, TU: 2, WE: 3, TH: 4, FR: 5, SA: 6, SU: 7 };
|
|
473
|
+
const plain = [];
|
|
474
|
+
const ordinals = [];
|
|
475
|
+
for (const d of value.split(",")) {
|
|
476
|
+
const m = d.match(/^([+-]?\d{1,2})?([A-Z]{2})$/);
|
|
477
|
+
if (!m || WEEKDAY_MAP[m[2]] === void 0) {
|
|
478
|
+
throw new RangeError(`temporal-fmt: RRULE BYDAY contains an invalid weekday "${d}".`);
|
|
479
|
+
}
|
|
480
|
+
const weekday = WEEKDAY_MAP[m[2]];
|
|
481
|
+
if (m[1] !== void 0) {
|
|
482
|
+
const ordinal = Number(m[1]);
|
|
483
|
+
if (!Number.isSafeInteger(ordinal) || ordinal === 0 || ordinal < -53 || ordinal > 53) {
|
|
484
|
+
throw new RangeError(`temporal-fmt: RRULE BYDAY ordinal out of range in "${d}".`);
|
|
485
|
+
}
|
|
486
|
+
ordinals.push({ ordinal, weekday });
|
|
487
|
+
} else {
|
|
488
|
+
plain.push(weekday);
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
rule.byWeekday = plain;
|
|
492
|
+
if (ordinals.length > 0) rule.byWeekdayOrdinal = ordinals;
|
|
337
493
|
break;
|
|
494
|
+
}
|
|
338
495
|
case "BYMONTHDAY": {
|
|
339
496
|
const values = value.split(",").map(Number);
|
|
340
497
|
if (values.some((day) => !Number.isInteger(day) || day === 0 || day < -31 || day > 31)) {
|
|
@@ -357,12 +514,20 @@ function parseRRule(input) {
|
|
|
357
514
|
}
|
|
358
515
|
function formatRRule(rule) {
|
|
359
516
|
const parts = [`FREQ=${rule.frequency.toUpperCase()}`];
|
|
360
|
-
if (rule.interval !== 1) parts.push(`INTERVAL=${rule.interval}`);
|
|
517
|
+
if (rule.interval !== void 0 && rule.interval !== 1) parts.push(`INTERVAL=${rule.interval}`);
|
|
361
518
|
if (rule.count !== void 0) parts.push(`COUNT=${rule.count}`);
|
|
362
519
|
if (rule.until !== void 0) parts.push(`UNTIL=${String(rule.until)}`);
|
|
520
|
+
const WEEKDAY_NAMES = { 1: "MO", 2: "TU", 3: "WE", 4: "TH", 5: "FR", 6: "SA", 7: "SU" };
|
|
363
521
|
if (rule.byWeekday && rule.byWeekday.length > 0) {
|
|
364
|
-
|
|
365
|
-
|
|
522
|
+
parts.push(`BYDAY=${rule.byWeekday.map((d) => WEEKDAY_NAMES[d] ?? String(d)).join(",")}`);
|
|
523
|
+
}
|
|
524
|
+
if (rule.byWeekdayOrdinal && rule.byWeekdayOrdinal.length > 0) {
|
|
525
|
+
const rendered = rule.byWeekdayOrdinal.map((o) => `${o.ordinal}${WEEKDAY_NAMES[o.weekday] ?? String(o.weekday)}`);
|
|
526
|
+
if (rule.byWeekday && rule.byWeekday.length > 0) {
|
|
527
|
+
parts[parts.length - 1] = `BYDAY=${[...rule.byWeekday.map((d) => WEEKDAY_NAMES[d] ?? String(d)), ...rendered].join(",")}`;
|
|
528
|
+
} else {
|
|
529
|
+
parts.push(`BYDAY=${rendered.join(",")}`);
|
|
530
|
+
}
|
|
366
531
|
}
|
|
367
532
|
if (rule.byMonthDay && rule.byMonthDay.length > 0) parts.push(`BYMONTHDAY=${rule.byMonthDay.join(",")}`);
|
|
368
533
|
if (rule.byMonth && rule.byMonth.length > 0) parts.push(`BYMONTH=${rule.byMonth.join(",")}`);
|
|
@@ -395,4 +560,4 @@ export {
|
|
|
395
560
|
parseRRule,
|
|
396
561
|
formatRRule
|
|
397
562
|
};
|
|
398
|
-
//# sourceMappingURL=chunk-
|
|
563
|
+
//# sourceMappingURL=chunk-3FMUGYE2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/comparison.ts","../src/recurrence.ts"],"sourcesContent":["/*\n * Copyright 2026 DirazCoder\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// Comparison helpers. Pure functions over the field\n// shape, no Temporal namespace needed — same convention as\n// calendarUtils.ts. All comparisons are field-based, not identity-based,\n// so a polyfill PlainDate compares equal to a native PlainDate with the\n// same year/month/day.\n\nimport { asDateFieldView, type DateFieldView } from './calendarUtils.js';\nimport { dayOfWeekFromCivil, daysFromCivil } from './isoWeek.js';\n\ninterface DateTimeFieldView extends DateFieldView {\n hour?: number;\n minute?: number;\n second?: number;\n millisecond?: number;\n}\n\nfunction toComparableMs(view: DateTimeFieldView): number {\n // Exact proleptic-Gregorian day count (Howard Hinnant's days_from_civil,\n // same algorithm arithmetic.ts/interval.ts use) plus the time-of-day —\n // NOT an approximation. The previous implementation multiplied the\n // year offset by an average 365.2425 days/year, on the theory that the\n // error \"is constant for any given year, so it cancels out in a diff\".\n // That's only true when both dates fall in the same year: the year\n // term's error differs by up to ~0.76 days between adjacent years\n // (365.2425 vs 365/366 actual), which corrupts cross-year comparisons\n // near the boundary — e.g. isAfter(2025-01-01T00:00, 2024-12-31T18:12)\n // returned false (truth: ~5.8h after), and isEqual() returned true for\n // instants ~18h apart (2025-01-01T00:00 vs 2024-12-31T05:49:12).\n // Exact arithmetic has no such error term. The day count itself comes\n // from isoWeek.ts's daysFromCivil (Howard Hinnant's days_from_civil:\n // O(1), correct for negative years — the inlined era formula this\n // replaced double-corrected pre-year-0 dates by a day via Math.floor\n // of the -399-offset numerator).\n const days = daysFromCivil(view.year!, view.month!, view.day!);\n\n const MS_PER_HOUR = 3_600_000;\n const MS_PER_MINUTE = 60_000;\n const MS_PER_SECOND = 1_000;\n\n return days * 86_400_000\n + (view.hour ?? 0) * MS_PER_HOUR\n + (view.minute ?? 0) * MS_PER_MINUTE\n + (view.second ?? 0) * MS_PER_SECOND\n + (view.millisecond ?? 0);\n}\n\nfunction asDateTimeFieldView(value: unknown): DateTimeFieldView {\n const v = asDateFieldView(value);\n return v as DateTimeFieldView;\n}\n\n// Returns < 0 if a < b, 0 if a === b, > 0 if a > b. Same convention as\n// Array.prototype.sort and Temporal.PlainDate.compare. Lets callers\n// pass this directly as a comparator.\nexport function compare(a: unknown, b: unknown): number {\n const av = asDateTimeFieldView(a);\n const bv = asDateTimeFieldView(b);\n const am = toComparableMs(av);\n const bm = toComparableMs(bv);\n if (am < bm) return -1;\n if (am > bm) return 1;\n return 0;\n}\n\nexport function isEqual(a: unknown, b: unknown): boolean {\n return compare(a, b) === 0;\n}\n\nexport function isBefore(a: unknown, b: unknown): boolean {\n return compare(a, b) < 0;\n}\n\nexport function isAfter(a: unknown, b: unknown): boolean {\n return compare(a, b) > 0;\n}\n\nexport function min(values: unknown[]): unknown {\n if (!Array.isArray(values) || values.length === 0) {\n throw new Error('temporal-fmt: min() requires a non-empty array of values.');\n }\n let best = values[0];\n for (let i = 1; i < values.length; i++) {\n if (compare(values[i], best) < 0) best = values[i];\n }\n return best;\n}\n\nexport function max(values: unknown[]): unknown {\n if (!Array.isArray(values) || values.length === 0) {\n throw new Error('temporal-fmt: max() requires a non-empty array of values.');\n }\n let best = values[0];\n for (let i = 1; i < values.length; i++) {\n if (compare(values[i], best) > 0) best = values[i];\n }\n return best;\n}\n\nexport function clamp(value: unknown, lo: unknown, hi: unknown): unknown {\n if (compare(value, lo) < 0) return lo;\n if (compare(value, hi) > 0) return hi;\n return value;\n}\n\nexport function isBetween(value: unknown, lo: unknown, hi: unknown): boolean {\n return compare(value, lo) >= 0 && compare(value, hi) <= 0;\n}\n\n// Semantic helpers — same-day/week/month/quarter/year tests. Useful for\n// UI (\"is this event today?\") and for grouping/aggregation. All take a\n// reference value to compare against; the \"isToday\" / \"isTomorrow\" /\n// \"isYesterday\" variants compute the reference from the current system\n// date themselves so callers don't have to.\nfunction readYearMonthDay(value: unknown): { year: number; month: number; day: number } {\n const v = asDateFieldView(value);\n return { year: v.year!, month: v.month!, day: v.day! };\n}\n\nfunction todayYearMonthDay(): { year: number; month: number; day: number } {\n const now = new Date();\n return { year: now.getFullYear(), month: now.getMonth() + 1, day: now.getDate() };\n}\n\nfunction dateEqualYearMonthDay(a: { year: number; month: number; day: number }, b: { year: number; month: number; day: number }): boolean {\n return a.year === b.year && a.month === b.month && a.day === b.day;\n}\n\nexport function isSameDay(value: unknown, reference: unknown): boolean {\n return dateEqualYearMonthDay(readYearMonthDay(value), readYearMonthDay(reference));\n}\n\nexport function isToday(value: unknown): boolean {\n return dateEqualYearMonthDay(readYearMonthDay(value), todayYearMonthDay());\n}\n\nfunction tomorrowYearMonthDay(): { year: number; month: number; day: number } {\n const d = new Date();\n d.setDate(d.getDate() + 1);\n return { year: d.getFullYear(), month: d.getMonth() + 1, day: d.getDate() };\n}\n\nfunction yesterdayYearMonthDay(): { year: number; month: number; day: number } {\n const d = new Date();\n d.setDate(d.getDate() - 1);\n return { year: d.getFullYear(), month: d.getMonth() + 1, day: d.getDate() };\n}\n\nexport function isTomorrow(value: unknown): boolean {\n return dateEqualYearMonthDay(readYearMonthDay(value), tomorrowYearMonthDay());\n}\n\nexport function isYesterday(value: unknown): boolean {\n return dateEqualYearMonthDay(readYearMonthDay(value), yesterdayYearMonthDay());\n}\n\nfunction sameWeek(yearA: number, monthA: number, dayA: number, yearB: number, monthB: number, dayB: number): boolean {\n // Same week iff the dates are within 7 days of each other AND the earlier\n // one's weekday is ≤ the later one's weekday (so we don't say \"Sun and\n // the following Mon are in the same week\" — ISO weeks run Mon-Sun).\n // Easier: compute ISO week numbers via isoWeekYearAndWeek, compare both\n // year and week. That handles the year-boundary case (Dec 31 vs Jan 1 of\n // the next year, which can be in the same ISO week).\n // Local import to avoid module-cycle: isoWeek.ts doesn't import from here.\n // Lazy require-style dynamic via inline static import at top would be\n // cleaner; this inline computation is fine for a pure helper.\n // ...actually let's just compute weekday offsets directly. Same-ISO-week\n // iff |d1 - d2| < 7 days AND the earlier date's ISO weekday ≤ the later\n // date's ISO weekday so they fall in the same Mon-Sun span.\n const daysSince = (y: number, m: number, d: number): number => {\n // daysFromCivil: O(1), correct for negative years. (The inlined\n // formula this replaced was the one remaining copy of the\n // Math.floor-of-offset era bug — see daysFromCivil's comment.)\n return daysFromCivil(y, m, d);\n };\n const a = daysSince(yearA, monthA, dayA);\n const b = daysSince(yearB, monthB, dayB);\n if (Math.abs(a - b) >= 7) return false;\n // Same week iff both dates round to the same Monday. Compute the\n // Monday-of-week for each: subtract (weekday - 1) days, where weekday\n // is 1=Mon..7=Sun. Use the standard Zeller formula for weekday.\n const weekdayOf = (y: number, m: number, d: number): number => {\n // O(1) proleptic-Gregorian weekday from isoWeek.ts's dayOfWeekFromCivil.\n // The old Date.UTC(y, m-1, d) form remapped years 0-99 to 1900-1999\n // (ECMAScript spec), computing the weekday of the wrong century for\n // first-century dates.\n return dayOfWeekFromCivil(y, m, d);\n };\n const wa = a - (weekdayOf(yearA, monthA, dayA) - 1);\n const wb = b - (weekdayOf(yearB, monthB, dayB) - 1);\n return wa === wb;\n}\n\nexport function isSameWeek(value: unknown, reference: unknown): boolean {\n const a = readYearMonthDay(value);\n const b = readYearMonthDay(reference);\n return sameWeek(a.year, a.month, a.day, b.year, b.month, b.day);\n}\n\nexport function isSameMonth(value: unknown, reference: unknown): boolean {\n const a = readYearMonthDay(value);\n const b = readYearMonthDay(reference);\n return a.year === b.year && a.month === b.month;\n}\n\nexport function isSameQuarter(value: unknown, reference: unknown): boolean {\n const a = readYearMonthDay(value);\n const b = readYearMonthDay(reference);\n return a.year === b.year && Math.ceil(a.month / 3) === Math.ceil(b.month / 3);\n}\n\nexport function isSameYear(value: unknown, reference: unknown): boolean {\n return readYearMonthDay(value).year === readYearMonthDay(reference).year;\n}\n\n// isWeekend / isWeekday depend on dayOfWeek — present on PlainDate,\n// PlainDateTime, ZonedDateTime, but NOT on PlainTime. Callers passing\n// PlainTime get a descriptive throw. Doesn't call asDateFieldView\n// because that would reject PlainTime (no year/month/day) before\n// reaching the dayOfWeek check — and the error we want here is the\n// \"no dayOfWeek field\" one, not the \"no date fields\" one.\nexport function isWeekend(value: unknown): boolean {\n if (typeof value !== 'object' || value === null) {\n throw new Error(`temporal-fmt: isWeekend() expected a Temporal value, got ${String(value)}.`);\n }\n const v = value as { dayOfWeek?: unknown };\n if (typeof v.dayOfWeek !== 'number') {\n throw new Error(\n `temporal-fmt: isWeekend() needs a value with a dayOfWeek field (PlainDate / PlainDateTime / ZonedDateTime).`\n );\n }\n // 6=Sat, 7=Sun in Temporal's Mon=1..Sun=7 numbering.\n return v.dayOfWeek === 6 || v.dayOfWeek === 7;\n}\n\nexport function isWeekday(value: unknown): boolean {\n return !isWeekend(value);\n}\n","/*\n * Copyright 2026 DirazCoder\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// Recurrence engine. Deterministic RRULE-like\n// recurrence without pulling in a runtime dependency. Supports\n// secondly/minutely/hourly/daily/weekly/monthly/yearly frequencies,\n// interval, count, until, weekdays (incl. ordinal BYDAY like 2MO/-1FR\n// for monthly/yearly), monthDays (incl. negative end-of-month values),\n// exclusions, inclusions.\n//\n// RRULE interop: parseRRule() / formatRRule() convert to/from the\n// standard iCalendar RRULE string format (RFC 5545). Implemented\n// without depending on a RRULE library — the grammar is small enough\n// to handle inline. Not enforced (documented limitation, same as\n// before): BYSETPOS, BYHOUR, BYMINUTE, BYSECOND, WKST.\n\nimport { add } from './arithmetic.js';\nimport { compare } from './comparison.js';\nimport { daysFromCivil } from './isoWeek.js';\nimport { asDateFieldView } from './calendarUtils.js';\n\nexport type RecurrenceFrequency = 'secondly' | 'minutely' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly';\n\nexport interface WeekdayOrdinal {\n // 2 = \"2nd such weekday of the month\", -1 = \"last such weekday\".\n // Only meaningful with monthly/yearly frequency (RFC 5545 3.3.10:\n // the numeric prefix is invalid with WEEKLY, where it's ignored).\n ordinal: number;\n weekday: number; // ISO 1=Mon..7=Sun\n}\n\nexport interface RecurrenceRule {\n frequency: RecurrenceFrequency;\n interval: number; // default 1 — omitted/null now means 1 (used to mean NaN)\n count?: number; // max occurrences\n until?: unknown; // Temporal value (or RRULE UNTIL date form) — recurrence ends after this\n // For weekly: ISO weekdays to include (1=Mon..7=Sun). Empty = all.\n byWeekday?: number[];\n // Ordinal BYDAY parts (2MO, -1FR) parsed from RRULE strings — the nth\n // weekday of each month/year. Matched in addition to plain byWeekday.\n byWeekdayOrdinal?: WeekdayOrdinal[];\n // For monthly/yearly: days of month to include (1-31, or negative\n // for end-of-month: -1 = last day).\n byMonthDay?: number[];\n // For yearly: months to include (1-12).\n byMonth?: number[];\n // For weekly: which week of the year (1-53).\n byWeek?: number[];\n // Exclusions: dates to skip even if they match the rule.\n exDates?: unknown[];\n // Inclusions: dates to add even if they don't match the rule.\n rDates?: unknown[];\n}\n\nexport interface RecurrenceIterator {\n next(): { value: unknown; done: boolean } | { value: undefined; done: true };\n previous(): { value: unknown; done: boolean } | { value: undefined; done: true };\n}\n\nfunction daysInMonthOf(year: number, month: number): number {\n const LENGTHS = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];\n const leap = (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;\n return month === 2 && leap ? 29 : LENGTHS[month - 1]!;\n}\n\n// Day of week (ISO, 1=Mon..7=Sun) for a proleptic Gregorian y/m/d in\n// O(1): 1970-01-01 was a Thursday (dow 4), so dow = ((days + 3) mod 7) + 1.\nfunction weekdayOf(year: number, month: number, day: number): number {\n const days = daysFromCivil(year, month, day);\n return (((days + 3) % 7) + 7) % 7 + 1;\n}\n\n// Day-of-month of the `ordinal`-th `weekday` in the given month\n// (ordinal < 0 counts from the end, -1 = last). Returns null when no\n// such day exists in this month (e.g. 5th Monday of a 4-Monday month).\nfunction nthWeekdayDay(year: number, month: number, weekday: number, ordinal: number): number | null {\n const last = daysInMonthOf(year, month);\n if (ordinal > 0) {\n const firstDow = weekdayOf(year, month, 1);\n const first = 1 + ((weekday - firstDow + 7) % 7);\n const day = first + (ordinal - 1) * 7;\n return day <= last ? day : null;\n }\n const lastDow = weekdayOf(year, month, last);\n const lastOccurrence = last - ((lastDow - weekday + 7) % 7);\n const day = lastOccurrence + (ordinal + 1) * 7;\n return day >= 1 ? day : null;\n}\n\n// Creates a recurrence iterator starting from `start`. The first call\n// to next() returns `start` itself (if it matches the rule); subsequent\n// calls return the next matching occurrence.\nexport function recurrence(start: unknown, rule: RecurrenceRule): RecurrenceIterator {\n if (rule.count !== undefined && (!Number.isSafeInteger(rule.count) || rule.count < 1)) {\n throw new RangeError(`temporal-fmt: recurrence rule count must be a positive safe integer (got ${String(rule.count)}).`);\n }\n // The interface documents interval as \"default 1\" — normalize it here\n // so a rule object omitting it (or passing undefined) behaves as 1\n // instead of poisoning every candidate with NaN arithmetic.\n const interval = rule.interval !== undefined && rule.interval !== null\n ? rule.interval\n : 1;\n if (!Number.isSafeInteger(interval) || interval < 1) {\n throw new RangeError(`temporal-fmt: recurrence rule interval must be a positive safe integer (got ${String(rule.interval)}).`);\n }\n // Programmatic rules skip parseRRule's validation, so re-check the\n // BY* lists here — garbage used to fall through to `?? 0` fallbacks\n // in matches() and quietly match nothing (a rule like byMonthDay:[0]\n // produced an empty sequence with no hint why). Real rules from\n // parseRRule always pass.\n if (rule.byMonthDay && rule.byMonthDay.some((d) => !Number.isSafeInteger(d) || d === 0 || d < -31 || d > 31)) {\n throw new RangeError('temporal-fmt: recurrence rule byMonthDay entries must be nonzero integers in [-31, 31].');\n }\n if (rule.byWeekday && rule.byWeekday.some((d) => !Number.isSafeInteger(d) || d < 1 || d > 7)) {\n throw new RangeError('temporal-fmt: recurrence rule byWeekday entries must be ISO weekdays 1 (Mon) through 7 (Sun).');\n }\n if (rule.byMonth && rule.byMonth.some((m) => !Number.isSafeInteger(m) || m < 1 || m > 12)) {\n throw new RangeError('temporal-fmt: recurrence rule byMonth entries must be months 1 through 12.');\n }\n if (rule.byWeekdayOrdinal && rule.byWeekdayOrdinal.some((o) =>\n !Number.isSafeInteger(o.ordinal) || o.ordinal === 0 || o.ordinal < -53 || o.ordinal > 53 ||\n !Number.isSafeInteger(o.weekday) || o.weekday < 1 || o.weekday > 7)) {\n throw new RangeError('temporal-fmt: recurrence rule byWeekdayOrdinal entries need a nonzero ordinal in [-53, 53] and an ISO weekday 1-7.');\n }\n // Track past values for previous() — keeps a ring buffer of the last\n // N occurrences so previous() can walk back without recomputing.\n const history: unknown[] = [];\n const MAX_HISTORY = 10_000;\n let atEnd = false;\n let atStart = true;\n\n // Anchor: the ORIGINAL start, as a field view. Monthly/yearly\n // candidates are derived from this (not from the previous occurrence)\n // so the day-of-month never drifts: advancing Jan 31 by months used\n // to go 01-31 → 02-28 → 03-28 → 04-28 …, permanently stuck on day 28\n // after the first February clamp. Deriving each period's candidates\n // from the anchor keeps the original day and skips (rather than\n // clamps) periods that lack it — RFC 5545 semantics.\n const anchor = asDateFieldView(start);\n const originDayCount = daysFromCivil(anchor.year!, anchor.month!, anchor.day!);\n\n // A plain field-bag start without dayOfWeek used to make every\n // byWeekday-dependent rule silently produce nothing: matches()'s\n // `?? 0` never equals a real weekday, and add()'s dayOfWeek\n // recompute only refreshes a field that already exists — so the\n // chain never picks one up (a Temporal start works because its\n // dayOfWeek getter seeds it). Derive it once here so bag starts and\n // Temporal starts behave identically for BYDAY rules.\n let current: unknown = start;\n if (rule.byWeekday && rule.byWeekday.length > 0 && typeof (start as { dayOfWeek?: unknown }).dayOfWeek !== 'number') {\n current = { ...anchor, dayOfWeek: weekdayOf(anchor.year!, anchor.month!, anchor.day!) };\n }\n let count = 0;\n\n function matches(value: unknown): boolean {\n // The `?? 0` / `?? []` fallbacks on the lines flagged below are\n // defensive only and unreachable through the public API: recurrence()\n // rejects starts missing year/month/day, every generated candidate is\n // a full field view (fillNextPeriod sets dayOfWeek; add()'s\n // recomputeDayOfWeek refreshes one seeded at the top), and the\n // byWeekday gate above runs before plainOk is ever evaluated — so\n // dayOfWeek is defined whenever `?? 0` would fire, and year/month/day\n // are always present. The lines they sit on are otherwise live and\n // test-covered; only the fallback arms need the ignore.\n const v = value as { dayOfWeek?: number; year?: number; month?: number; day?: number; hour?: number; minute?: number; second?: number };\n if (rule.byWeekday && rule.byWeekday.length > 0) {\n // `?? 0` is defensive only since the dayOfWeek seeding above: every\n // value a byWeekday rule tests (seeded start, generated candidates)\n // carries a number.\n /* c8 ignore next @preserve */\n if (!rule.byWeekday.includes(v.dayOfWeek ?? 0)) return false;\n }\n if (rule.byWeekdayOrdinal && rule.byWeekdayOrdinal.length > 0\n && (rule.frequency === 'monthly' || rule.frequency === 'yearly')) {\n // Union with the plain-byWeekday check above per RFC: any BYDAY\n // entry matching is enough. (Monthly/yearly candidates are\n // generated from the ordinal itself, so this re-check is about\n // rules that mix plain and ordinal entries.)\n /* c8 ignore next @preserve */\n const plainOk = !!rule.byWeekday && rule.byWeekday.length > 0 && rule.byWeekday.includes(v.dayOfWeek ?? 0);\n /* c8 ignore next @preserve */\n const ordinalOk = (rule.byWeekdayOrdinal ?? []).some((o) =>\n /* c8 ignore next @preserve */\n nthWeekdayDay(v.year ?? 0, v.month ?? 0, o.weekday, o.ordinal) === (v.day ?? 0));\n if (!plainOk && !ordinalOk) return false;\n }\n if (rule.byMonthDay && rule.byMonthDay.length > 0) {\n // Negative values count back from the end of the month\n // (-1 = last day). They used to be accepted by parseRRule but\n // never matched anything — a day-of-month is never negative.\n /* c8 ignore next @preserve */\n const day = v.day ?? 0;\n /* c8 ignore next @preserve */\n const last = daysInMonthOf(v.year ?? 0, v.month ?? 0);\n // `?? []` is defensive only: the enclosing if guards byMonthDay\n // non-empty.\n /* c8 ignore next @preserve */\n const hit = (rule.byMonthDay ?? []).some((d) => (d > 0 ? d === day : d + last + 1 === day));\n if (!hit) return false;\n }\n if (rule.byMonth && rule.byMonth.length > 0) {\n /* c8 ignore next @preserve */\n if (!rule.byMonth.includes(v.month ?? 0)) return false;\n }\n if (rule.exDates && rule.exDates.some((d) => compare(d, value) === 0)) return false;\n return true;\n }\n\n // ---- Monthly/yearly candidate generation ------------------------------\n // Each interval step yields one period (a month, or a year with its\n // byMonth months). The period's candidate days are:\n // - byMonthDay values, if present (negatives resolved to real days);\n // - else ordinal BYDAY days, if present;\n // - else the anchor's day (periods lacking it yield nothing).\n // Candidates carry the anchor's time-of-day and a recomputed\n // dayOfWeek, and are yielded in chronological order.\n let pending: unknown[] = [];\n // Starts at 0: the start's OWN period gets generated first (RFC —\n // FREQ=MONTHLY;BYMONTHDAY=15 from Jan 1 yields Jan 15 before Feb 15),\n // with candidates at or before `start` skipped by nextMatch.\n let periodIndex = 0;\n\n function fillNextPeriod(): void {\n // k starts at 0 (the start's own period) and increments AFTER use,\n // so every period from the anchor's onward is generated exactly once.\n const k = periodIndex;\n periodIndex++;\n let year: number;\n let months: number[];\n if (rule.frequency === 'monthly') {\n const totalMonths = anchor.year! * 12 + anchor.month! - 1 + k * interval;\n year = Math.floor(totalMonths / 12);\n months = [totalMonths - year * 12 + 1];\n } else {\n year = anchor.year! + k * interval;\n months = rule.byMonth && rule.byMonth.length > 0\n ? [...rule.byMonth].sort((a, b) => a - b)\n : [anchor.month!];\n }\n const days: Array<{ month: number; day: number }> = [];\n for (const m of months) {\n const last = daysInMonthOf(year, m);\n if (rule.byMonthDay && rule.byMonthDay.length > 0) {\n for (const d of rule.byMonthDay) {\n const real = d > 0 ? d : last + 1 + d;\n if (real >= 1 && real <= last) days.push({ month: m, day: real });\n }\n } else if (rule.byWeekdayOrdinal && rule.byWeekdayOrdinal.length > 0) {\n for (const o of rule.byWeekdayOrdinal) {\n const real = nthWeekdayDay(year, m, o.weekday, o.ordinal);\n if (real !== null) days.push({ month: m, day: real });\n }\n } else {\n if (anchor.day! <= last) days.push({ month: m, day: anchor.day! });\n }\n }\n days.sort((a, b) => a.month - b.month || a.day - b.day);\n pending = days.map(({ month, day }) => ({\n ...anchor,\n year,\n month,\n day,\n dayOfWeek: weekdayOf(year, month, day),\n }));\n }\n\n // Steps to the next candidate after `value`, by the frequency's own\n // granularity:\n // - monthly/yearly: pop the period queue (refilling as needed);\n // - weekly + BYDAY: one day at a time (stepping whole weeks preserves\n // the weekday, so a start not already on a BYDAY weekday could\n // never match — FREQ=WEEKLY;BYDAY=SA from a Monday used to produce\n // an empty sequence), gated to the interval's week windows;\n // - everything else: one `interval` step from the current value, the\n // same way the original implementation did.\n function nextMatch(value: unknown): { value: unknown; found: boolean } {\n let candidate = value;\n let safetyCounter = 0;\n const daywise = rule.frequency === 'weekly' && !!rule.byWeekday && rule.byWeekday.length > 0;\n const periodwise = rule.frequency === 'monthly' || rule.frequency === 'yearly';\n const unit = rule.frequency === 'secondly' ? 'seconds'\n : rule.frequency === 'minutely' ? 'minutes'\n : rule.frequency === 'hourly' ? 'hours'\n : rule.frequency === 'daily' ? 'days'\n : 'weeks';\n\n while (true) {\n // Count EVERY iteration, including the two `continue` paths below\n // (empty periods, candidates at/before the start): those used to\n // skip the increment, so a rule whose every period is empty — e.g.\n // monthly BYDAY=-6MO, which no month can ever satisfy — spun the\n // loop forever. The cap is a total-work bound per next() call, not\n // a candidates-produced bound.\n safetyCounter++;\n if (safetyCounter > 2000) {\n // Defensive — if the rule is so restrictive no match exists\n // within 2000 steps, give up rather than spin forever. The\n // caller must treat this as \"no more occurrences\", not as a\n // real match — returning the unmatched candidate here used to\n // get handed back to next()'s caller as if it were valid.\n // (1000 previously; doubled because day-granular stepping for\n // weekly BYDAY rules legitimately needs up to 7 steps per\n // occurrence, and monthly skips can chain across short months.)\n atEnd = true;\n return { value: candidate, found: false };\n }\n if (daywise) {\n candidate = add(candidate, 1, 'days');\n // INTERVAL > 1 on a weekly BYDAY rule: only weeks that are a\n // whole multiple of `interval` away from the anchor's week emit\n // occurrences (WKST unsupported — the window anchors on the\n // start's own day).\n if (interval > 1) {\n const v = asDateFieldView(candidate);\n const dayCount = daysFromCivil(v.year!, v.month!, v.day!);\n if (Math.floor((dayCount - originDayCount) / 7) % interval !== 0) continue;\n }\n } else if (periodwise) {\n if (pending.length === 0) {\n fillNextPeriod();\n if (pending.length === 0) continue; // period had no valid days\n }\n candidate = pending.shift()!;\n // The start's own period can contain candidate days at or before\n // the start itself (BYMONTHDAY=15 generating Jan 15 for a Jan 1\n // start, where Jan 1..14 precede it) — those aren't occurrences.\n if (compare(candidate, value) <= 0) continue;\n } else {\n candidate = add(candidate, interval, unit as Parameters<typeof add>[2]);\n }\n if (rule.until && compare(candidate, rule.until) > 0) {\n atEnd = true;\n return { value: candidate, found: false };\n }\n if (matches(candidate)) break;\n }\n return { value: candidate, found: true };\n }\n\n function recordHistory(value: unknown): void {\n history.push(value);\n if (history.length > MAX_HISTORY) history.shift();\n }\n\n return {\n next() {\n if (atEnd) return { value: undefined, done: true };\n if (atStart) {\n atStart = false;\n if (matches(current)) {\n count++;\n if (rule.count !== undefined && count >= rule.count) atEnd = true;\n if (rule.until && compare(current, rule.until) > 0) {\n atEnd = true;\n return { value: undefined, done: true };\n }\n // Include rDates that match the current value.\n recordHistory(current);\n return { value: current, done: false };\n }\n // If start doesn't match, advance to first match.\n const advanced = nextMatch(current);\n if (!advanced.found) return { value: undefined, done: true };\n current = advanced.value;\n count++;\n if (rule.count !== undefined && count >= rule.count) atEnd = true;\n recordHistory(current);\n return { value: current, done: false };\n }\n const advanced = nextMatch(current);\n if (!advanced.found) return { value: undefined, done: true };\n current = advanced.value;\n count++;\n if (rule.count !== undefined && count >= rule.count) atEnd = true;\n recordHistory(current);\n return { value: current, done: false };\n },\n previous() {\n if (history.length === 0) return { value: undefined, done: true };\n const v = history.pop()!;\n return { value: v, done: false };\n },\n };\n}\n\n// Take N occurrences from a recurrence iterator.\nexport function take(iter: RecurrenceIterator, n: number): unknown[] {\n const result: unknown[] = [];\n for (let i = 0; i < n; i++) {\n const r = iter.next();\n if (r.done) break;\n result.push(r.value);\n }\n return result;\n}\n\n// Upper bound on how many occurrences skip() will collect after its\n// skip phase. skip() used to call take(iter, Number.MAX_SAFE_INTEGER),\n// and an iterator over an unbounded rule (no count, no until — e.g.\n// { frequency: 'daily', interval: 1 }) never returns done: next() always\n// has another day. The call then looped forever, pushing into a result\n// array until the process OOM'd. Same cap style as businessCalendar.ts.\nconst MAX_SKIP_COLLECTION = 100_000;\n// Upper bound on skip()'s skip phase too: skip(iter, 1e9) on an\n// unbounded rule used to burn a billion next() calls before the\n// collection cap was ever reached.\nconst MAX_SKIP_STEPS = 1_000_000;\n\n// Skip N occurrences from a recurrence iterator, returning the ones\n// that follow. Throws a RangeError when the iterator is still producing\n// occurrences after MAX_SKIP_COLLECTION — that means the rule is\n// unbounded (no count/until) and \"everything after the skip\" has no\n// finite answer.\nexport function skip(iter: RecurrenceIterator, n: number): unknown[] {\n for (let i = 0; i < n; i++) {\n if (i >= MAX_SKIP_STEPS) {\n throw new RangeError(\n `temporal-fmt: skip() was asked to skip more than ${MAX_SKIP_STEPS} occurrences — that's not a bounded operation; use take() on a count/until-bounded rule instead.`\n );\n }\n const r = iter.next();\n if (r.done) break;\n }\n const result: unknown[] = [];\n while (result.length < MAX_SKIP_COLLECTION) {\n const r = iter.next();\n if (r.done) return result;\n result.push(r.value);\n }\n throw new RangeError(\n `temporal-fmt: skip() collected ${MAX_SKIP_COLLECTION} occurrences and the rule is still ` +\n `producing — add a count or until to the rule, or use take(iter, n) for a bounded read.`\n );\n}\n\n// All occurrences between two dates (inclusive of start, exclusive of end).\nexport function between(start: unknown, rule: RecurrenceRule, rangeStart: unknown, rangeEnd: unknown): unknown[] {\n const iter = recurrence(start, rule);\n const result: unknown[] = [];\n // Traversal cap: a fine-grained rule anchored far before rangeEnd\n // (e.g. daily from year -2000) walks every occurrence since `start`\n // — bounded work instead of an unbounded loop, same style as skip().\n const MAX_TRAVERSAL = 1_000_000;\n let traversed = 0;\n while (true) {\n if (traversed++ > MAX_TRAVERSAL) {\n throw new RangeError(\n `temporal-fmt: between() walked more than ${MAX_TRAVERSAL} occurrences without reaching rangeEnd — ` +\n `pass a start closer to the range, or bound the rule with count/until.`\n );\n }\n const r = iter.next();\n if (r.done) break;\n if (compare(r.value, rangeEnd) >= 0) break;\n if (compare(r.value, rangeStart) >= 0) result.push(r.value);\n }\n return result;\n}\n\n// Parses an RRULE UNTIL value (RFC 5545 date \"20240110\" or UTC\n// date-time \"20240110T153000Z\") into a comparable field bag. Stored raw\n// previously, so iterating a parsed rule threw \"expected a date-carrying\n// Temporal value\" on the first next() — a parsed RRULE was unusable\n// with UNTIL, the single most common termination form.\nfunction parseUntil(value: string): { year: number; month: number; day: number; hour?: number; minute?: number; second?: number } {\n const m = /^(\\d{4})(\\d{2})(\\d{2})(?:T(\\d{2})(\\d{2})(\\d{2})Z?)?$/.exec(value.trim());\n if (!m) {\n throw new RangeError(\n `temporal-fmt: RRULE UNTIL must be a date (\"20240110\") or UTC date-time (\"20240110T153000Z\") — got \"${value}\".`\n );\n }\n const year = Number(m[1]);\n const month = Number(m[2]);\n const day = Number(m[3]);\n if (month < 1 || month > 12 || day < 1 || day > 31) {\n throw new RangeError(`temporal-fmt: RRULE UNTIL carries an out-of-range date \"${value}\".`);\n }\n const hour = m[4] !== undefined ? Number(m[4]) : undefined;\n const minute = m[5] !== undefined ? Number(m[5]) : undefined;\n const second = m[6] !== undefined ? Number(m[6]) : undefined;\n if (hour !== undefined && (hour > 23 || minute! > 59 || second! > 59)) {\n throw new RangeError(`temporal-fmt: RRULE UNTIL carries an out-of-range time \"${value}\".`);\n }\n return { year, month, day, hour, minute, second };\n}\n\n// Parses an RRULE string like \"FREQ=DAILY;INTERVAL=2;COUNT=5\" into a\n// RecurrenceRule. Doesn't support every RRULE feature (BYSETPOS,\n// BYHOUR, BYMINUTE, BYSECOND, WKST are not enforced by the recurrence\n// iterator above), but covers the common cases.\nexport function parseRRule(input: string): RecurrenceRule {\n const parts = input.trim().toUpperCase().replace(/^RRULE:/, '').split(';');\n const rule: RecurrenceRule = { frequency: 'daily', interval: 1 };\n const frequencies: ReadonlySet<string> = new Set([\n 'SECONDLY', 'MINUTELY', 'HOURLY', 'DAILY', 'WEEKLY', 'MONTHLY', 'YEARLY',\n ]);\n for (const part of parts) {\n if (!part) continue;\n const eq = part.indexOf('=');\n if (eq < 0) continue;\n const key = part.slice(0, eq);\n const value = part.slice(eq + 1);\n switch (key) {\n case 'FREQ':\n if (!frequencies.has(value)) {\n throw new RangeError(`temporal-fmt: unsupported RRULE frequency \"${value}\".`);\n }\n rule.frequency = value.toLowerCase() as RecurrenceFrequency;\n break;\n case 'INTERVAL': {\n const interval = Number(value);\n if (!Number.isSafeInteger(interval) || interval < 1) {\n throw new RangeError(`temporal-fmt: RRULE INTERVAL must be a positive safe integer (got \"${value}\").`);\n }\n rule.interval = interval;\n break;\n }\n case 'COUNT': {\n const count = Number(value);\n if (!Number.isSafeInteger(count) || count < 1) {\n throw new RangeError(`temporal-fmt: RRULE COUNT must be a positive safe integer (got \"${value}\").`);\n }\n rule.count = count;\n break;\n }\n case 'UNTIL':\n rule.until = parseUntil(value);\n break;\n case 'BYDAY': {\n const WEEKDAY_MAP: Record<string, number> = { MO: 1, TU: 2, WE: 3, TH: 4, FR: 5, SA: 6, SU: 7 };\n const plain: number[] = [];\n const ordinals: WeekdayOrdinal[] = [];\n for (const d of value.split(',')) {\n // RFC 5545 ordinals run -53..53 — two digits are legal, so the\n // pattern must accept them (it used to cap at one digit, which\n // made valid rules like BYDAY=53MO throw \"invalid weekday\" and\n // pushed out-of-range ordinals past the range check below\n // instead of reaching it).\n const m = d.match(/^([+-]?\\d{1,2})?([A-Z]{2})$/);\n // Unknown tokens used to map to 0 silently — a typo'd BYDAY\n // entry quietly matched nothing instead of failing loudly.\n if (!m || WEEKDAY_MAP[m[2]!] === undefined) {\n throw new RangeError(`temporal-fmt: RRULE BYDAY contains an invalid weekday \"${d}\".`);\n }\n const weekday = WEEKDAY_MAP[m[2]!]!;\n if (m[1] !== undefined) {\n const ordinal = Number(m[1]);\n if (!Number.isSafeInteger(ordinal) || ordinal === 0 || ordinal < -53 || ordinal > 53) {\n throw new RangeError(`temporal-fmt: RRULE BYDAY ordinal out of range in \"${d}\".`);\n }\n ordinals.push({ ordinal, weekday });\n } else {\n plain.push(weekday);\n }\n }\n rule.byWeekday = plain;\n if (ordinals.length > 0) rule.byWeekdayOrdinal = ordinals;\n break;\n }\n case 'BYMONTHDAY': {\n const values = value.split(',').map(Number);\n if (values.some((day) => !Number.isInteger(day) || day === 0 || day < -31 || day > 31)) {\n throw new RangeError(`temporal-fmt: RRULE BYMONTHDAY contains an out-of-range value.`);\n }\n rule.byMonthDay = values;\n break;\n }\n case 'BYMONTH': {\n const values = value.split(',').map(Number);\n if (values.some((month) => !Number.isInteger(month) || month < 1 || month > 12)) {\n throw new RangeError(`temporal-fmt: RRULE BYMONTH contains an out-of-range value.`);\n }\n rule.byMonth = values;\n break;\n }\n }\n }\n return rule;\n}\n\nexport function formatRRule(rule: RecurrenceRule): string {\n const parts: string[] = [`FREQ=${rule.frequency.toUpperCase()}`];\n // Programmatic rules may omit interval (documented default: 1) — emitting\n // \"INTERVAL=undefined\" for them produced output that parseRRule itself\n // rejects, breaking the round-trip. Omit it unless it's an explicit != 1.\n if (rule.interval !== undefined && rule.interval !== 1) parts.push(`INTERVAL=${rule.interval}`);\n if (rule.count !== undefined) parts.push(`COUNT=${rule.count}`);\n if (rule.until !== undefined) parts.push(`UNTIL=${String(rule.until)}`);\n const WEEKDAY_NAMES: Record<number, string> = { 1: 'MO', 2: 'TU', 3: 'WE', 4: 'TH', 5: 'FR', 6: 'SA', 7: 'SU' };\n if (rule.byWeekday && rule.byWeekday.length > 0) {\n parts.push(`BYDAY=${rule.byWeekday.map((d) => WEEKDAY_NAMES[d] ?? String(d)).join(',')}`);\n }\n if (rule.byWeekdayOrdinal && rule.byWeekdayOrdinal.length > 0) {\n const rendered = rule.byWeekdayOrdinal.map((o) => `${o.ordinal}${WEEKDAY_NAMES[o.weekday] ?? String(o.weekday)}`);\n // Merge into the plain BYDAY part when both exist (RRULE carries\n // one combined list).\n if (rule.byWeekday && rule.byWeekday.length > 0) {\n parts[parts.length - 1] = `BYDAY=${[...rule.byWeekday.map((d) => WEEKDAY_NAMES[d] ?? String(d)), ...rendered].join(',')}`;\n } else {\n parts.push(`BYDAY=${rendered.join(',')}`);\n }\n }\n if (rule.byMonthDay && rule.byMonthDay.length > 0) parts.push(`BYMONTHDAY=${rule.byMonthDay.join(',')}`);\n if (rule.byMonth && rule.byMonth.length > 0) parts.push(`BYMONTH=${rule.byMonth.join(',')}`);\n return parts.join(';');\n}\n"],"mappings":"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","names":["weekdayOf","day","advanced"]}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getTemporal
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-DFWTCRS3.js";
|
|
4
4
|
import {
|
|
5
5
|
add
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-SC6ENLEB.js";
|
|
7
7
|
|
|
8
8
|
// src/timezone.ts
|
|
9
9
|
function resolveZoned(fields, timeZone, options = {}) {
|
|
@@ -73,15 +73,30 @@ function isDST(value) {
|
|
|
73
73
|
}
|
|
74
74
|
const temporal = getTemporal();
|
|
75
75
|
try {
|
|
76
|
+
const options = { disambiguation: "compatible" };
|
|
76
77
|
const jan = temporal.ZonedDateTime.from(
|
|
77
78
|
{ year: v.year, month: 1, day: 1, hour: 12, timeZone: v.timeZoneId },
|
|
78
|
-
|
|
79
|
+
options
|
|
80
|
+
);
|
|
81
|
+
const jul = temporal.ZonedDateTime.from(
|
|
82
|
+
{ year: v.year, month: 7, day: 1, hour: 12, timeZone: v.timeZoneId },
|
|
83
|
+
options
|
|
79
84
|
);
|
|
80
|
-
|
|
85
|
+
const janOff = jan.offsetNanoseconds !== void 0 ? Number(jan.offsetNanoseconds) / 1e9 : offsetToSeconds(jan.offset);
|
|
86
|
+
const julOff = jul.offsetNanoseconds !== void 0 ? Number(jul.offsetNanoseconds) / 1e9 : offsetToSeconds(jul.offset);
|
|
87
|
+
if (janOff === julOff) return false;
|
|
88
|
+
const standardOff = Math.min(janOff, julOff);
|
|
89
|
+
return offsetToSeconds(v.offset) !== standardOff;
|
|
81
90
|
} catch {
|
|
82
91
|
return false;
|
|
83
92
|
}
|
|
84
93
|
}
|
|
94
|
+
function offsetToSeconds(offset) {
|
|
95
|
+
const m = /^([+-])(\d{2}):(\d{2})(?::(\d{2}))?(?:\.\d+)?$/.exec(offset);
|
|
96
|
+
if (!m) return 0;
|
|
97
|
+
const sign = m[1] === "-" ? -1 : 1;
|
|
98
|
+
return sign * (Number(m[2]) * 3600 + Number(m[3]) * 60 + Number(m[4] ?? 0));
|
|
99
|
+
}
|
|
85
100
|
function getNextTransition(value) {
|
|
86
101
|
return findTransition(value, 1);
|
|
87
102
|
}
|
|
@@ -96,7 +111,17 @@ function findTransition(value, direction) {
|
|
|
96
111
|
const temporal = getTemporal();
|
|
97
112
|
const timeZone = v.timeZoneId;
|
|
98
113
|
let candidateFields = add(value, direction, "days");
|
|
99
|
-
const startOffset = v.offset
|
|
114
|
+
const startOffset = typeof v.offset === "string" ? v.offset : (() => {
|
|
115
|
+
try {
|
|
116
|
+
return temporal.ZonedDateTime.from(
|
|
117
|
+
{ year: v.year, month: v.month, day: v.day, hour: v.hour ?? 12, timeZone },
|
|
118
|
+
{ disambiguation: "compatible" }
|
|
119
|
+
).offset;
|
|
120
|
+
} catch {
|
|
121
|
+
return void 0;
|
|
122
|
+
}
|
|
123
|
+
})();
|
|
124
|
+
if (startOffset === void 0) return void 0;
|
|
100
125
|
for (let i = 0; i < 365 * 2; i++) {
|
|
101
126
|
const cf = candidateFields;
|
|
102
127
|
const candidateZdt = temporal.ZonedDateTime.from(
|
|
@@ -104,12 +129,48 @@ function findTransition(value, direction) {
|
|
|
104
129
|
{ disambiguation: "compatible" }
|
|
105
130
|
);
|
|
106
131
|
if (candidateZdt.offset !== startOffset) {
|
|
107
|
-
return candidateZdt;
|
|
132
|
+
return bisectTransition(temporal, timeZone, candidateZdt, startOffset, direction);
|
|
108
133
|
}
|
|
109
134
|
candidateFields = add(candidateFields, direction, "days");
|
|
110
135
|
}
|
|
111
136
|
return void 0;
|
|
112
137
|
}
|
|
138
|
+
function bisectTransition(temporal, timeZone, day, beforeOffset, direction) {
|
|
139
|
+
const zonedFrom = temporal.ZonedDateTime.from.bind(temporal.ZonedDateTime);
|
|
140
|
+
const options = { disambiguation: "compatible" };
|
|
141
|
+
const windowStart = direction > 0 ? { year: day.year, month: day.month, day: day.day, hour: 0, minute: 0 } : { year: day.year, month: day.month, day: day.day, hour: 12, minute: 0 };
|
|
142
|
+
const fieldsAt = (m) => add(windowStart, m, "minutes");
|
|
143
|
+
const offsetAt = (m) => {
|
|
144
|
+
try {
|
|
145
|
+
const f = fieldsAt(m);
|
|
146
|
+
return zonedFrom({ ...f, timeZone }, options).offset;
|
|
147
|
+
} catch {
|
|
148
|
+
return void 0;
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
const oldOffset = direction > 0 ? beforeOffset : day.offset;
|
|
152
|
+
let lo = 0;
|
|
153
|
+
let hi = 1440;
|
|
154
|
+
while (hi - lo > 1) {
|
|
155
|
+
const mid = Math.floor((lo + hi) / 2);
|
|
156
|
+
const off = offsetAt(mid);
|
|
157
|
+
if (off === void 0 || off === oldOffset) lo = mid;
|
|
158
|
+
else hi = mid;
|
|
159
|
+
}
|
|
160
|
+
const boundary = hi >= 1440 ? fieldsAt(1439) : fieldsAt(hi);
|
|
161
|
+
try {
|
|
162
|
+
return zonedFrom({
|
|
163
|
+
year: boundary.year,
|
|
164
|
+
month: boundary.month,
|
|
165
|
+
day: boundary.day,
|
|
166
|
+
hour: boundary.hour,
|
|
167
|
+
minute: boundary.minute,
|
|
168
|
+
timeZone
|
|
169
|
+
}, options);
|
|
170
|
+
} catch {
|
|
171
|
+
return day;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
113
174
|
function getTransitions(start, end) {
|
|
114
175
|
const result = [];
|
|
115
176
|
const startV = start;
|
|
@@ -117,6 +178,10 @@ function getTransitions(start, end) {
|
|
|
117
178
|
throw new Error(`temporal-fmt: getTransitions() expected a ZonedDateTime for start, got ${typeof start}.`);
|
|
118
179
|
}
|
|
119
180
|
const endV = end;
|
|
181
|
+
if (typeof endV?.year !== "number" || typeof endV?.month !== "number" || typeof endV?.day !== "number") {
|
|
182
|
+
throw new Error(`temporal-fmt: getTransitions() expected a date-carrying value for end, got ${typeof end}.`);
|
|
183
|
+
}
|
|
184
|
+
const endYear = endV.year, endMonth = endV.month, endDay = endV.day;
|
|
120
185
|
const temporal = getTemporal();
|
|
121
186
|
const timeZone = startV.timeZoneId;
|
|
122
187
|
let cursorFields = add(start, 1, "days");
|
|
@@ -128,7 +193,7 @@ function getTransitions(start, end) {
|
|
|
128
193
|
{ disambiguation: "compatible" }
|
|
129
194
|
);
|
|
130
195
|
if (cursorZdt.offset !== lastOffset) {
|
|
131
|
-
if (cursorZdt.year >
|
|
196
|
+
if (cursorZdt.year > endYear || cursorZdt.year === endYear && (cursorZdt.month > endMonth || cursorZdt.month === endMonth && cursorZdt.day > endDay)) break;
|
|
132
197
|
result.push(cursorZdt);
|
|
133
198
|
lastOffset = cursorZdt.offset;
|
|
134
199
|
}
|
|
@@ -167,4 +232,4 @@ export {
|
|
|
167
232
|
getTransitions,
|
|
168
233
|
possibleInstantsFor
|
|
169
234
|
};
|
|
170
|
-
//# sourceMappingURL=chunk-
|
|
235
|
+
//# sourceMappingURL=chunk-64UB3WDT.js.map
|