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.
Files changed (90) hide show
  1. package/LICENSE +196 -17
  2. package/README.md +11 -5
  3. package/dist/calendarUtils.cjs +17 -9
  4. package/dist/calendarUtils.cjs.map +1 -1
  5. package/dist/calendarUtils.js +2 -2
  6. package/dist/{chunk-VNIUIQA4.js → chunk-3FMUGYE2.js} +217 -52
  7. package/dist/chunk-3FMUGYE2.js.map +1 -0
  8. package/dist/{chunk-H7YQX25T.js → chunk-64UB3WDT.js} +73 -8
  9. package/dist/chunk-64UB3WDT.js.map +1 -0
  10. package/dist/{chunk-M3GDTHMT.js → chunk-AN4UFCLA.js} +16 -11
  11. package/dist/chunk-AN4UFCLA.js.map +1 -0
  12. package/dist/{chunk-MKPDLQKD.js → chunk-BLZDBPSV.js} +19 -8
  13. package/dist/chunk-BLZDBPSV.js.map +1 -0
  14. package/dist/{chunk-ACKKWH5Z.js → chunk-BZPNSQHI.js} +43 -40
  15. package/dist/chunk-BZPNSQHI.js.map +1 -0
  16. package/dist/{chunk-UOPAV3WX.js → chunk-CGI4FL6H.js} +2 -2
  17. package/dist/chunk-CGI4FL6H.js.map +1 -0
  18. package/dist/{chunk-ZQZF5EXW.js → chunk-DFWTCRS3.js} +1 -1
  19. package/dist/chunk-DFWTCRS3.js.map +1 -0
  20. package/dist/{chunk-FBPHNRVW.js → chunk-E2FBHVQW.js} +179 -85
  21. package/dist/chunk-E2FBHVQW.js.map +1 -0
  22. package/dist/{chunk-GPB4JHGI.js → chunk-G6RYR72T.js} +4 -4
  23. package/dist/chunk-G6RYR72T.js.map +1 -0
  24. package/dist/{chunk-HXY2GUUM.js → chunk-KEPIXQK7.js} +4 -4
  25. package/dist/chunk-KEPIXQK7.js.map +1 -0
  26. package/dist/{chunk-L24NPTAJ.js → chunk-LPSNAV3S.js} +29 -7
  27. package/dist/chunk-LPSNAV3S.js.map +1 -0
  28. package/dist/{chunk-EGUUO6LE.js → chunk-OLNU4LON.js} +1 -1
  29. package/dist/chunk-OLNU4LON.js.map +1 -0
  30. package/dist/{chunk-4N3WCGEY.js → chunk-QIZ2MXS2.js} +16 -7
  31. package/dist/chunk-QIZ2MXS2.js.map +1 -0
  32. package/dist/{chunk-TSLPIURC.js → chunk-SC6ENLEB.js} +11 -38
  33. package/dist/chunk-SC6ENLEB.js.map +1 -0
  34. package/dist/{chunk-YEUASGDK.js → chunk-SOPTTXUI.js} +1 -1
  35. package/dist/chunk-SOPTTXUI.js.map +1 -0
  36. package/dist/{chunk-5UTV5VP6.js → chunk-T7EKGDQT.js} +6 -6
  37. package/dist/chunk-T7EKGDQT.js.map +1 -0
  38. package/dist/config.d.cts +1 -1
  39. package/dist/config.d.ts +1 -1
  40. package/dist/duration.cjs +32 -23
  41. package/dist/duration.cjs.map +1 -1
  42. package/dist/duration.js +5 -5
  43. package/dist/format.cjs +59 -20
  44. package/dist/format.cjs.map +1 -1
  45. package/dist/format.js +7 -7
  46. package/dist/index.cjs +581 -240
  47. package/dist/index.cjs.map +1 -1
  48. package/dist/index.js +44 -29
  49. package/dist/index.js.map +1 -1
  50. package/dist/interval.cjs +472 -196
  51. package/dist/interval.cjs.map +1 -1
  52. package/dist/interval.js +15 -15
  53. package/dist/isoWeek.d.cts +2 -0
  54. package/dist/isoWeek.d.ts +2 -0
  55. package/dist/localeRegistry.cjs.map +1 -1
  56. package/dist/localeRegistry.js +2 -2
  57. package/dist/parse.cjs +48 -18
  58. package/dist/parse.cjs.map +1 -1
  59. package/dist/parse.js +7 -7
  60. package/dist/recurrence.cjs +222 -62
  61. package/dist/recurrence.cjs.map +1 -1
  62. package/dist/recurrence.d.cts +5 -0
  63. package/dist/recurrence.d.ts +5 -0
  64. package/dist/recurrence.js +4 -4
  65. package/dist/relativeTime.cjs +12 -8
  66. package/dist/relativeTime.cjs.map +1 -1
  67. package/dist/relativeTime.js +7 -7
  68. package/dist/timezone.cjs +87 -33
  69. package/dist/timezone.cjs.map +1 -1
  70. package/dist/timezone.js +5 -5
  71. package/dist/tokenize.d.cts +14 -0
  72. package/dist/tokenize.d.ts +14 -0
  73. package/package.json +4 -4
  74. package/scripts/cli.mjs +8 -2
  75. package/dist/chunk-4N3WCGEY.js.map +0 -1
  76. package/dist/chunk-5UTV5VP6.js.map +0 -1
  77. package/dist/chunk-ACKKWH5Z.js.map +0 -1
  78. package/dist/chunk-EGUUO6LE.js.map +0 -1
  79. package/dist/chunk-FBPHNRVW.js.map +0 -1
  80. package/dist/chunk-GPB4JHGI.js.map +0 -1
  81. package/dist/chunk-H7YQX25T.js.map +0 -1
  82. package/dist/chunk-HXY2GUUM.js.map +0 -1
  83. package/dist/chunk-L24NPTAJ.js.map +0 -1
  84. package/dist/chunk-M3GDTHMT.js.map +0 -1
  85. package/dist/chunk-MKPDLQKD.js.map +0 -1
  86. package/dist/chunk-TSLPIURC.js.map +0 -1
  87. package/dist/chunk-UOPAV3WX.js.map +0 -1
  88. package/dist/chunk-VNIUIQA4.js.map +0 -1
  89. package/dist/chunk-YEUASGDK.js.map +0 -1
  90. package/dist/chunk-ZQZF5EXW.js.map +0 -1
@@ -1,20 +1,17 @@
1
1
  import {
2
2
  add
3
- } from "./chunk-TSLPIURC.js";
3
+ } from "./chunk-SC6ENLEB.js";
4
4
  import {
5
5
  asDateFieldView
6
- } from "./chunk-HXY2GUUM.js";
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 y = view.year, m = view.month, d = view.day;
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
- const y2 = m <= 2 ? y - 1 : y;
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 weekdayOf = (y, m, d) => {
121
- const days = daysSince(y, m, d);
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 - (weekdayOf(yearA, monthA, dayA) - 1);
127
- const wb = b - (weekdayOf(yearB, monthB, dayB) - 1);
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
- let current = start;
167
- let count = 0;
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
- if (!rule.byMonthDay.includes(v.day ?? 0)) return false;
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
- function advance(value, steps) {
187
- const unit = rule.frequency === "secondly" ? "seconds" : rule.frequency === "minutely" ? "minutes" : rule.frequency === "hourly" ? "hours" : rule.frequency === "daily" ? "days" : rule.frequency === "weekly" ? "weeks" : rule.frequency === "monthly" ? "months" : "years";
188
- return add(value, steps * rule.interval, unit);
189
- }
190
- function recordHistory(value) {
191
- history.push(value);
192
- if (history.length > MAX_HISTORY) history.shift();
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
- do {
198
- candidate = advance(candidate, 1);
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 > 1e3) {
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
- } while (!matches(candidate));
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
- rule.byWeekday = value.split(",").map((d) => {
331
- const m = d.match(/^([+-]?\d)?([A-Z]{2})$/);
332
- if (!m) return 0;
333
- const wd = m[2];
334
- const map = { MO: 1, TU: 2, WE: 3, TH: 4, FR: 5, SA: 6, SU: 7 };
335
- return map[wd] ?? 0;
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
- const map = { 1: "MO", 2: "TU", 3: "WE", 4: "TH", 5: "FR", 6: "SA", 7: "SU" };
365
- parts.push(`BYDAY=${rule.byWeekday.map((d) => map[d]).join(",")}`);
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-VNIUIQA4.js.map
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-ZQZF5EXW.js";
3
+ } from "./chunk-DFWTCRS3.js";
4
4
  import {
5
5
  add
6
- } from "./chunk-TSLPIURC.js";
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
- { disambiguation: "compatible" }
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
- return jan.offset !== v.offset;
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 > endV.year || cursorZdt.year === endV.year && (cursorZdt.month > endV.month || cursorZdt.month === endV.month && cursorZdt.day > endV.day)) break;
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-H7YQX25T.js.map
235
+ //# sourceMappingURL=chunk-64UB3WDT.js.map