temporal-fmt 0.9.0 → 0.9.2

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 (105) hide show
  1. package/dist/calendarUtils.cjs +4 -259
  2. package/dist/calendarUtils.cjs.map +1 -1
  3. package/dist/calendarUtils.js +1 -33
  4. package/dist/chunk-2JHEV7ZF.js +7 -0
  5. package/dist/chunk-2JHEV7ZF.js.map +1 -0
  6. package/dist/chunk-3MZLTVP3.js +2 -0
  7. package/dist/{chunk-MXXYIMFJ.js.map → chunk-3MZLTVP3.js.map} +1 -1
  8. package/dist/chunk-4JWGUR4O.js +11 -0
  9. package/dist/{chunk-AXQLUIDY.js.map → chunk-4JWGUR4O.js.map} +1 -1
  10. package/dist/chunk-5U5WJ465.js +36 -0
  11. package/dist/chunk-5U5WJ465.js.map +1 -0
  12. package/dist/chunk-C5YESWFT.js +2 -0
  13. package/dist/chunk-C5YESWFT.js.map +1 -0
  14. package/dist/chunk-C6ZZ62ET.js +2 -0
  15. package/dist/{chunk-YS52LOMJ.js.map → chunk-C6ZZ62ET.js.map} +1 -1
  16. package/dist/chunk-EHLRZULM.js +5 -0
  17. package/dist/{chunk-4ZBGVYLR.js.map → chunk-EHLRZULM.js.map} +1 -1
  18. package/dist/chunk-F4RGUDA3.js +2 -0
  19. package/dist/chunk-F4RGUDA3.js.map +1 -0
  20. package/dist/chunk-J2AQNXF2.js +2 -0
  21. package/dist/{chunk-GRJQHQLW.js.map → chunk-J2AQNXF2.js.map} +1 -1
  22. package/dist/chunk-NBXF7V5B.js +2 -0
  23. package/dist/chunk-NBXF7V5B.js.map +1 -0
  24. package/dist/chunk-R52YOKI3.js +7 -0
  25. package/dist/{chunk-M33NSC4E.js.map → chunk-R52YOKI3.js.map} +1 -1
  26. package/dist/chunk-UJR6DHXY.js +2 -0
  27. package/dist/chunk-UJR6DHXY.js.map +1 -0
  28. package/dist/chunk-VQXUMFB2.js +21 -0
  29. package/dist/{chunk-VHSZL3P3.js.map → chunk-VQXUMFB2.js.map} +1 -1
  30. package/dist/chunk-XH46JNPK.js +2 -0
  31. package/dist/chunk-XH46JNPK.js.map +1 -0
  32. package/dist/chunk-YB6YAG7E.js +35 -0
  33. package/dist/chunk-YB6YAG7E.js.map +1 -0
  34. package/dist/chunk-ZGMTY52O.js +2 -0
  35. package/dist/chunk-ZGMTY52O.js.map +1 -0
  36. package/dist/duration.cjs +9 -624
  37. package/dist/duration.cjs.map +1 -1
  38. package/dist/duration.js +1 -29
  39. package/dist/format.cjs +18 -769
  40. package/dist/format.cjs.map +1 -1
  41. package/dist/format.js +1 -20
  42. package/dist/formatDuration.d.cts +6 -0
  43. package/dist/formatDuration.d.ts +6 -0
  44. package/dist/index.cjs +146 -6672
  45. package/dist/index.cjs.map +1 -1
  46. package/dist/index.js +58 -3004
  47. package/dist/index.js.map +1 -1
  48. package/dist/interval.cjs +18 -952
  49. package/dist/interval.cjs.map +1 -1
  50. package/dist/interval.js +1 -41
  51. package/dist/localeRegistry.cjs +15 -328
  52. package/dist/localeRegistry.cjs.map +1 -1
  53. package/dist/localeRegistry.js +1 -11
  54. package/dist/localeVocab.d.cts +3 -0
  55. package/dist/localeVocab.d.ts +3 -0
  56. package/dist/parse.cjs +53 -1637
  57. package/dist/parse.cjs.map +1 -1
  58. package/dist/parse.js +1 -20
  59. package/dist/parsePattern.d.cts +1 -0
  60. package/dist/parsePattern.d.ts +1 -0
  61. package/dist/pattern.d.cts +1 -0
  62. package/dist/pattern.d.ts +1 -0
  63. package/dist/recurrence.cjs +20 -450
  64. package/dist/recurrence.cjs.map +1 -1
  65. package/dist/recurrence.js +1 -20
  66. package/dist/relativeTime.cjs +24 -177
  67. package/dist/relativeTime.cjs.map +1 -1
  68. package/dist/relativeTime.js +1 -14
  69. package/dist/rounding.d.cts +1 -0
  70. package/dist/rounding.d.ts +1 -0
  71. package/dist/serialization.d.cts +1 -1
  72. package/dist/serialization.d.ts +1 -1
  73. package/dist/timezone.cjs +20 -387
  74. package/dist/timezone.cjs.map +1 -1
  75. package/dist/timezone.js +1 -26
  76. package/dist/typeGuards.d.cts +9 -9
  77. package/dist/typeGuards.d.ts +9 -9
  78. package/package.json +4 -2
  79. package/dist/chunk-4ZBGVYLR.js +0 -182
  80. package/dist/chunk-AXQLUIDY.js +0 -183
  81. package/dist/chunk-CKVHXFX7.js +0 -902
  82. package/dist/chunk-CKVHXFX7.js.map +0 -1
  83. package/dist/chunk-CSUIKL73.js +0 -215
  84. package/dist/chunk-CSUIKL73.js.map +0 -1
  85. package/dist/chunk-EDUFSRWJ.js +0 -9
  86. package/dist/chunk-EDUFSRWJ.js.map +0 -1
  87. package/dist/chunk-FQA4XJME.js +0 -57
  88. package/dist/chunk-FQA4XJME.js.map +0 -1
  89. package/dist/chunk-FTMLZ4EN.js +0 -196
  90. package/dist/chunk-FTMLZ4EN.js.map +0 -1
  91. package/dist/chunk-GRJQHQLW.js +0 -170
  92. package/dist/chunk-JCIMP43G.js +0 -602
  93. package/dist/chunk-JCIMP43G.js.map +0 -1
  94. package/dist/chunk-KDYK72Z2.js +0 -75
  95. package/dist/chunk-KDYK72Z2.js.map +0 -1
  96. package/dist/chunk-M33NSC4E.js +0 -169
  97. package/dist/chunk-MXXYIMFJ.js +0 -29
  98. package/dist/chunk-NFKQ3EXC.js +0 -188
  99. package/dist/chunk-NFKQ3EXC.js.map +0 -1
  100. package/dist/chunk-O6GVMBLW.js +0 -403
  101. package/dist/chunk-O6GVMBLW.js.map +0 -1
  102. package/dist/chunk-VHSZL3P3.js +0 -242
  103. package/dist/chunk-VSUCBUTC.js +0 -295
  104. package/dist/chunk-VSUCBUTC.js.map +0 -1
  105. package/dist/chunk-YS52LOMJ.js +0 -51
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/timezone.ts","../src/temporalProvider.ts","../src/isoWeek.ts","../src/calendarUtils.ts","../src/arithmetic.ts"],"sourcesContent":["// Time-zone subsystem. Wraps Temporal.ZonedDateTime's\n// timezone introspection surface in temporal-fmt's field-based convention.\n// Includes disambiguation modes (compatible/earlier/later/reject) for\n// DST gaps and overlaps, plus transition queries (getNextTransition,\n// getPreviousTransition, getTransitions).\n\nimport { getTemporal } from './temporalProvider.js';\nimport { add } from './arithmetic.js';\n\nexport type DisambiguationMode = 'compatible' | 'earlier' | 'later' | 'reject';\n\nexport interface ResolveZonedOptions {\n disambiguation?: DisambiguationMode;\n overflow?: 'constrain' | 'reject';\n offset?: 'use' | 'ignore' | 'prefer' | 'reject';\n}\n\n// Resolves a wall-clock time in a timezone, applying disambiguation\n// for DST gaps and overlaps.\nexport function resolveZoned(\n fields: { year: number; month: number; day: number; hour?: number; minute?: number; second?: number; millisecond?: number; microsecond?: number; nanosecond?: number },\n timeZone: string,\n options: ResolveZonedOptions = {},\n): unknown {\n const temporal = getTemporal();\n const disambiguation = options.disambiguation ?? 'compatible';\n const overflow = options.overflow ?? 'constrain';\n // Cast options to a permissive record — Temporal.ZonedDateTime.from\n // accepts disambiguation/offset options, but the existing\n // TemporalFactory.from() signature in temporalProvider.ts is narrower.\n // The runtime accepts the wider shape; this cast bypasses the type\n // narrowing without changing runtime behavior.\n const fromOptions = {\n overflow,\n disambiguation,\n offset: options.offset ?? 'prefer',\n } as unknown as Parameters<typeof temporal.ZonedDateTime.from>[1];\n try {\n return temporal.ZonedDateTime.from(\n {\n year: fields.year,\n month: fields.month,\n day: fields.day,\n hour: fields.hour ?? 0,\n minute: fields.minute ?? 0,\n second: fields.second ?? 0,\n millisecond: fields.millisecond ?? 0,\n microsecond: fields.microsecond ?? 0,\n nanosecond: fields.nanosecond ?? 0,\n timeZone,\n },\n fromOptions,\n );\n } catch (err) {\n // Surface DST gap / overlap errors with a clearer message.\n const msg = (err as Error).message;\n if (/no such (wall-clock )?time/i.test(msg) && disambiguation === 'reject') {\n throw new Error(\n `temporal-fmt: \"${timeZone}\" has no such wall-clock time on ${fields.year}-${fields.month}-${fields.day}T${fields.hour ?? 0}:${fields.minute ?? 0} — ` +\n `it falls in a DST gap. Pass { disambiguation: 'compatible' | 'earlier' | 'later' } to pick an instant.`\n );\n }\n throw err;\n }\n}\n\nexport function getTimeZone(value: unknown): string {\n const v = value as { timeZoneId?: string };\n if (typeof v?.timeZoneId !== 'string') {\n throw new Error(`temporal-fmt: getTimeZone() expected a ZonedDateTime, got ${typeof value}.`);\n }\n return v.timeZoneId;\n}\n\nexport function getOffset(value: unknown): string {\n const v = value as { offset?: string };\n if (typeof v?.offset !== 'string') {\n throw new Error(`temporal-fmt: getOffset() expected a ZonedDateTime, got ${typeof value}.`);\n }\n return v.offset;\n}\n\nexport function getOffsetNanoseconds(value: unknown): number {\n const v = value as { offsetNanoseconds?: number; offset?: string };\n if (typeof v?.offsetNanoseconds === 'number') return v.offsetNanoseconds;\n if (typeof v?.offset === 'string') {\n // Parse ±HH:MM → nanoseconds.\n const m = v.offset.match(/^([+-])(\\d{2}):(\\d{2})$/);\n if (!m) throw new Error(`temporal-fmt: getOffsetNanoseconds() couldn't parse offset \"${v.offset}\".`);\n const sign = m[1] === '-' ? -1 : 1;\n return sign * (Number(m[2]) * 3600 + Number(m[3]) * 60) * 1_000_000_000;\n }\n throw new Error(`temporal-fmt: getOffsetNanoseconds() expected a ZonedDateTime, got ${typeof value}.`);\n}\n\n// DST detection: a ZonedDateTime is in DST iff the offset is different\n// from the timezone's standard offset at the same instant. Computed\n// by comparing the current offset to the offset in January (Northern\n// Hemisphere) or July (Southern Hemisphere) of the same year — a\n// heuristic that's right for most populated zones.\nexport function isDST(value: unknown): boolean {\n const v = value as { timeZoneId?: string; offset?: string; year?: number; toInstant?: () => unknown };\n if (typeof v?.timeZoneId !== 'string' || typeof v?.offset !== 'string' || typeof v?.year !== 'number') {\n throw new Error(`temporal-fmt: isDST() expected a ZonedDateTime, got ${typeof value}.`);\n }\n // Compute the offset for January 1 of the same year (standard time\n // for Northern Hemisphere zones) and compare. For Southern Hemisphere\n // zones January is summer, so we'd want July instead — but checking\n // January vs current is good enough for the common case, and we\n // can't reliably determine hemisphere without a lookup table.\n const temporal = getTemporal();\n try {\n const jan = temporal.ZonedDateTime.from(\n { year: v.year, month: 1, day: 1, hour: 12, timeZone: v.timeZoneId },\n { disambiguation: 'compatible' } as unknown as Parameters<typeof temporal.ZonedDateTime.from>[1],\n ) as { offset: string };\n return jan.offset !== v.offset;\n } catch {\n return false;\n }\n}\n\n// Returns the next DST transition strictly after `value`, or undefined\n// if no transition occurs within the next 2 years. Implemented by\n// walking day-by-day checking for offset changes — slow but simple,\n// and correct across all IANA zones.\nexport function getNextTransition(value: unknown): unknown | undefined {\n return findTransition(value, 1);\n}\n\nexport function getPreviousTransition(value: unknown): unknown | undefined {\n return findTransition(value, -1);\n}\n\nfunction findTransition(value: unknown, direction: 1 | -1): unknown | undefined {\n const v = value as { timeZoneId?: string; offset?: string; toInstant?: () => unknown; year?: number; month?: number; day?: number; hour?: number; minute?: number; second?: number; millisecond?: number };\n if (typeof v?.timeZoneId !== 'string') {\n throw new Error(`temporal-fmt: ${direction > 0 ? 'getNextTransition' : 'getPreviousTransition'}() expected a ZonedDateTime, got ${typeof value}.`);\n }\n const temporal = getTemporal();\n const timeZone = v.timeZoneId;\n let candidateFields = add(value, direction, 'days');\n const startOffset = v.offset!;\n for (let i = 0; i < 365 * 2; i++) {\n // Rebuild a real ZonedDateTime for this candidate day, in this\n // timezone, so `.offset` reflects the actual UTC offset on that\n // day rather than being absent. add() only produces a plain field\n // bag (it has no notion of timezone), so re-attaching timeZone via\n // ZonedDateTime.from is what actually lets us detect a DST change\n // here — using the field bag's own (nonexistent) offset would make\n // every call \"find\" a transition on the very first day checked.\n const cf = candidateFields as { year: number; month: number; day: number; hour: number; minute: number; second: number; millisecond: number };\n const candidateZdt = temporal.ZonedDateTime.from(\n { ...cf, timeZone },\n { disambiguation: 'compatible' } as unknown as Parameters<typeof temporal.ZonedDateTime.from>[1],\n ) as { offset: string };\n if (candidateZdt.offset !== startOffset) {\n // Found a transition day. Return the reconstructed ZonedDateTime.\n return candidateZdt;\n }\n candidateFields = add(candidateFields, direction, 'days');\n }\n return undefined;\n}\n\nexport function getTransitions(start: unknown, end: unknown): unknown[] {\n const result: unknown[] = [];\n const startV = start as { timeZoneId?: string; offset?: string; year?: number; month?: number; day?: number };\n if (typeof startV?.timeZoneId !== 'string') {\n throw new Error(`temporal-fmt: getTransitions() expected a ZonedDateTime for start, got ${typeof start}.`);\n }\n const endV = end as { year: number; month: number; day: number };\n const temporal = getTemporal();\n const timeZone = startV.timeZoneId;\n let cursorFields = add(start, 1, 'days');\n let lastOffset = startV.offset!;\n for (let i = 0; i < 365 * 5; i++) {\n // Same reconstruction as findTransition() above — add() strips\n // timezone/offset info, so we rebuild a real ZonedDateTime each\n // iteration to read its actual offset instead of comparing against\n // a field bag that never has one.\n const cf = cursorFields as { year: number; month: number; day: number; hour: number; minute: number; second: number; millisecond: number };\n const cursorZdt = temporal.ZonedDateTime.from(\n { ...cf, timeZone },\n { disambiguation: 'compatible' } as unknown as Parameters<typeof temporal.ZonedDateTime.from>[1],\n ) as { offset: string; year: number; month: number; day: number };\n if (cursorZdt.offset !== lastOffset) {\n // Found a transition.\n if (cursorZdt.year > endV.year || (cursorZdt.year === endV.year && (cursorZdt.month > endV.month || (cursorZdt.month === endV.month && cursorZdt.day > endV.day)))) break;\n result.push(cursorZdt);\n lastOffset = cursorZdt.offset;\n }\n cursorFields = add(cursorFields, 1, 'days');\n }\n return result;\n}\n\n// Returns the list of possible instants for a wall-clock time in a\n// zone — used to detect gaps (0 instants) and overlaps (2 instants).\nexport function possibleInstantsFor(\n fields: { year: number; month: number; day: number; hour: number; minute: number; second: number; millisecond: number },\n timeZone: string,\n): unknown[] {\n const temporal = getTemporal();\n // Resolve the same wall-clock fields twice, forcing disambiguation\n // toward the earlier and later side of any DST boundary. Comparing\n // the two results tells us which of the three cases we're in:\n // - gap (e.g. 2:30am on a spring-forward day): neither result's own\n // wall-clock fields match what was requested, since Temporal has\n // to shift off the nonexistent time in both directions — 0 instants.\n // - overlap (e.g. 1:30am on a fall-back day): both results keep the\n // requested wall-clock time but land on different instants (one\n // per side of the boundary) — 2 instants.\n // - normal time: both results match the requested wall-clock time\n // and resolve to the same instant — 1 instant.\n const earlier = temporal.ZonedDateTime.from(\n { ...fields, timeZone },\n { disambiguation: 'earlier', offset: 'ignore' } as unknown as Parameters<typeof temporal.ZonedDateTime.from>[1],\n ) as { year: number; month: number; day: number; hour: number; minute: number; second: number; millisecond: number; toInstant: () => { epochNanoseconds: bigint } };\n const later = temporal.ZonedDateTime.from(\n { ...fields, timeZone },\n { disambiguation: 'later', offset: 'ignore' } as unknown as Parameters<typeof temporal.ZonedDateTime.from>[1],\n ) as { year: number; month: number; day: number; hour: number; minute: number; second: number; millisecond: number; toInstant: () => { epochNanoseconds: bigint } };\n\n const matchesRequestedWallClock = (z: typeof earlier) =>\n z.year === fields.year && z.month === fields.month && z.day === fields.day &&\n z.hour === fields.hour && z.minute === fields.minute &&\n z.second === fields.second && z.millisecond === fields.millisecond;\n\n if (!matchesRequestedWallClock(earlier) || !matchesRequestedWallClock(later)) {\n // Gap — the requested wall-clock time doesn't exist in this zone.\n return [];\n }\n if (earlier.toInstant().epochNanoseconds === later.toInstant().epochNanoseconds) {\n // Normal time — both disambiguation directions agree on the instant.\n return [earlier];\n }\n // Overlap — same wall-clock time, two distinct instants.\n return [earlier, later];\n}","// This package's tsconfig assumes lib: [\"ESNext\"] only — no ambient\n// `Temporal` namespace type. Everywhere else in this codebase only ever\n// *reads* fields off a Temporal-like object the caller already built\n// (TemporalLike in tokens.ts). This module is the single choke point for\n// touching a *namespace*-shaped Temporal (PlainDate.from, etc.): parse()\n// uses it to construct a result, tokens.ts uses it to probe native\n// Intl<->Temporal support. Consumers can hand us an implementation via\n// setTemporal(), or we fall back to globalThis.Temporal\ninterface TemporalFactory {\n from(fields: Record<string, number | string | undefined>, options?: { overflow?: 'constrain' | 'reject'; disambiguation?: 'compatible' | 'earlier' | 'later' | 'reject'; offset?: 'use' | 'ignore' | 'prefer' | 'reject' }): unknown;\n // compare() lives on the namespace (Temporal.PlainDate.compare), not on\n // instances. Optional here since a consumer might be passing a\n // stripped-down Temporal shim that doesn't expose it.\n compare?(one: unknown, two: unknown): number;\n}\n\n// Instant is constructed via fromEpochMilliseconds / fromEpochNanoseconds\n// rather than from(fields). Separate interface.\ninterface InstantFactory {\n from(iso: string): unknown;\n fromEpochMilliseconds(ms: number): unknown;\n fromEpochMicroseconds(µs: number): unknown;\n fromEpochNanoseconds(ns: bigint): unknown;\n}\n\n// Duration is constructed via from(fields). Carries round() and compare().\ninterface DurationFactory extends TemporalFactory {\n compare?(one: unknown, two: unknown): number;\n prototype?: { round(options: unknown): unknown };\n}\n\n// PlainYearMonth / PlainMonthDay are also constructed via from(fields).\n// Same factory shape, kept separate for type clarity in callers that\n// want to narrow.\nexport interface TemporalNamespace {\n PlainDate: TemporalFactory;\n PlainTime: TemporalFactory;\n PlainDateTime: TemporalFactory;\n ZonedDateTime: TemporalFactory;\n Instant?: InstantFactory;\n Duration?: DurationFactory;\n PlainYearMonth?: TemporalFactory;\n PlainMonthDay?: TemporalFactory;\n}\n\nlet injectedTemporal: TemporalNamespace | undefined;\n\n// Anything that caches a result derived from *which* Temporal\n// implementation is active (right now: tokens.ts's native-Intl-support\n// probe) registers here so it gets invalidated whenever setTemporal()\n// swaps the implementation — see the comment on setTemporal() below for\n// why that matters. A plain array instead of an event-emitter-style API\n// since this only ever needs \"call every listener, in registration order,\n// with no payload\" — nothing here needs unsubscribe or payload data.\nconst onTemporalChanged: Array<() => void> = [];\n\nexport function subscribeToTemporalChanges(listener: () => void): void {\n onTemporalChanged.push(listener);\n}\n\n/**\n * Explicitly hand temporal-fmt the Temporal implementation to use, instead\n * of relying on a global `Temporal`. Call this once, before your first\n * `format()`/`parse()`/`parseISO()`/etc.\n *\n * Call with no argument (or `undefined`) to clear the override and fall\n * back to `globalThis.Temporal` again.\n *\n * @example\n * import { Temporal } from 'temporal-polyfill';\n * import { setTemporal } from 'temporal-fmt';\n * setTemporal(Temporal);\n */\nexport function setTemporal(temporal?: TemporalNamespace): void {\n injectedTemporal = temporal;\n // tokens.ts's native-Intl-support probe is keyed on whichever Temporal\n // implementation was active the first time a locale-aware format() ran —\n // if that implementation changes later (native -> polyfill or back), the\n // memoized probe result can go stale and disagree with what's now\n // actually active. Resetting it here means the next locale-aware format()\n // after any setTemporal() call re-probes against the implementation\n // that's active *now*, at the (small, one-time-per-switch) cost of\n // re-running the probe.\n for (const listener of onTemporalChanged) listener();\n}\n\nfunction resolveTemporal(): TemporalNamespace | undefined {\n return injectedTemporal ?? (globalThis as unknown as { Temporal?: TemporalNamespace }).Temporal;\n}\n\nexport function getTemporal(): TemporalNamespace {\n const temporal = resolveTemporal();\n if (!temporal) {\n throw new Error(\n 'temporal-fmt: parse() needs a Temporal implementation to construct its result. ' +\n 'Call setTemporal(Temporal) once at startup, or assign one to globalThis.Temporal ' +\n '(native on Node 26+, or a polyfill like temporal-polyfill).'\n );\n }\n return temporal;\n}\n","// ISO 8601 week numbering: a week runs Monday–Sunday, and week 1 of a year\n// is the week containing the year's first Thursday (equivalently, the week\n// containing January 4). This means late-December dates can fall in week 1\n// of the *next* year, and early-January dates can fall in week 52 or 53 of\n// the *previous* year. The \"ISO week-numbering year\" (what `RRRR` formats)\n// is that adjacent year, not the calendar year.\n//\n// Computed here from the date's own year/month/day plus its ISO dayOfWeek\n// (1=Mon..7=Sun, matching Temporal's numbering) using plain Gregorian\n// arithmetic — no Temporal factory needed. format() only has the fields\n// the caller already put on the object, and requiring a Temporal\n// implementation just for ISO week would be a regression for callers who\n// use format() without setTemporal() on a non-26 Node.\n\nconst DAYS_IN_MONTH = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];\nconst CUMULATIVE_DAYS_BY_MONTH = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334];\n\nexport function isGregorianLeapYear(year: number): boolean {\n // Gregorian rule: divisible by 4, except centuries which must also be\n // divisible by 400. Temporal's iso8601 calendar is proleptic Gregorian\n // (no Julian cutover), so this applies for every year, including BCE.\n return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;\n}\n\nfunction daysInYear(year: number): 365 | 366 {\n return isGregorianLeapYear(year) ? 366 : 365;\n}\n\nexport function dayOfYear(year: number, month: number, day: number): number {\n let doy = CUMULATIVE_DAYS_BY_MONTH[month - 1]! + day;\n if (month > 2 && isGregorianLeapYear(year)) doy += 1;\n return doy;\n}\n\n// Jan 1, 2000 was a Saturday — ISO dayOfWeek 6. Anchoring day-of-week\n// computations to a known reference date is simpler and cheaper than\n// pulling in Zeller's congruence, and the reference never changes.\nconst REFERENCE_YEAR = 2000;\nconst REFERENCE_JAN1_DAY_OF_WEEK = 6;\n\nfunction dayOfWeekOfJan1(year: number): number {\n // Sum full-year deltas from the 2000 anchor rather than recomputing from\n // scratch each call — the per-call work is a single mod this way, and\n // the loop rarely runs far (a typical caller passes a current-era year).\n let offset = 0;\n if (year >= REFERENCE_YEAR) {\n for (let y = REFERENCE_YEAR; y < year; y++) offset += daysInYear(y);\n } else {\n for (let y = year; y < REFERENCE_YEAR; y++) offset -= daysInYear(y);\n }\n // Convert \"days since Jan 1, 2000\" into an ISO day-of-week (1=Mon..7=Sun).\n // Jan 1, 2000 was ISO 6 (Sat), so zero-indexed dow = (6-1 + offset) mod 7.\n const zeroIndexed = (((6 - 1 + offset) % 7) + 7) % 7;\n return zeroIndexed + 1;\n}\n\nexport interface IsoWeekDate {\n isoYear: number;\n week: number; // 1..53\n}\n\nexport function isoWeekYearAndWeek(year: number, month: number, day: number, dayOfWeek: number): IsoWeekDate {\n // Step 1: find the Thursday of the current ISO week. The ISO week-numbering\n // year is whichever calendar year that Thursday falls in. Computing it via\n // day-of-year offsets (rather than constructing a Temporal.PlainDate and\n // adding days) keeps this function pure-numeric.\n const doy = dayOfYear(year, month, day);\n const thursdayDoyRelative = doy + (4 - dayOfWeek); // may be <1 or >daysInYear\n\n let isoYear: number;\n let thursdayDoy: number;\n if (thursdayDoyRelative < 1) {\n isoYear = year - 1;\n thursdayDoy = thursdayDoyRelative + daysInYear(isoYear);\n } else if (thursdayDoyRelative > daysInYear(year)) {\n isoYear = year + 1;\n thursdayDoy = thursdayDoyRelative - daysInYear(year);\n } else {\n isoYear = year;\n thursdayDoy = thursdayDoyRelative;\n }\n\n // Step 2: locate the first Thursday of isoYear — its week is week 1. The\n // first Thursday's day-of-year depends on what weekday Jan 1 of isoYear is.\n const jan1Dow = dayOfWeekOfJan1(isoYear);\n const firstThursdayDoy = 1 + ((4 - jan1Dow + 7) % 7); // 1..7\n\n // Step 3: count full weeks between the two Thursdays.\n const week = 1 + Math.floor((thursdayDoy - firstThursdayDoy) / 7);\n return { isoYear, week };\n}\n","// Calendar utility helpers. These are pure functions\n// over the TemporalLike shape — no Temporal namespace needed, same\n// approach as isoWeek.ts and the field-reading helpers in format.ts.\n// Letting callers compute dayOfYear/weekOfYear/etc. without going\n// through format() means they can build their own derived values\n// without committing to a string format.\n//\n// Calendar-sensitivity: the helpers in this module assume the\n// iso8601 (Gregorian) calendar — that's what TemporalLike fields\n// carry for the overwhelming majority of callers. Non-Gregorian\n// calendars (hebrew, islamic, etc.) need their own helpers; this\n// module doesn't try to be calendar-polymorphic the way Temporal\n// itself is. Documented limitation, not a design choice — see\n// VERIFICATION.md for the rationale.\n\nimport { isGregorianLeapYear, dayOfYear, isoWeekYearAndWeek } from './isoWeek.js';\n\n// A subset of TemporalLike that has the date fields these helpers need,\n// plus optional time fields. PlainTime isn't a DateFieldView (no\n// year/month/day), but PlainDateTime / ZonedDateTime / PlainDate all\n// match. Time fields are optional so callers can pass a PlainDate\n// to startOf(value, 'month') without having to populate hour/minute/etc.\n// Exported so the comparison/arithmetic modules can use the same\n// narrowing.\nexport interface DateFieldView {\n year?: number;\n month?: number;\n day?: number;\n hour?: number;\n minute?: number;\n second?: number;\n millisecond?: number;\n dayOfWeek?: number;\n calendarId?: string;\n}\n\nfunction requireFields(view: DateFieldView, fields: Array<keyof DateFieldView>): void {\n for (const f of fields) {\n if (typeof view[f] !== 'number') {\n throw new Error(\n `temporal-fmt: calendar helper requires \"${String(f)}\", which this value doesn't have. ` +\n `Pass a Temporal.PlainDate / PlainDateTime / ZonedDateTime.`\n );\n }\n }\n}\n\nexport function daysInMonth(view: DateFieldView): number {\n requireFields(view, ['year', 'month']);\n const { year, month } = view;\n // Standard Gregorian month lengths. February's length depends on\n // whether `year` is a leap year — the same isGregorianLeapYear check\n // isoWeek.ts uses for dayOfYear arithmetic.\n const LENGTHS = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];\n if (month === 2 && isGregorianLeapYear(year!)) return 29;\n return LENGTHS[(month! - 1)!]!;\n}\n\nexport function daysInYear(view: DateFieldView): 365 | 366 {\n requireFields(view, ['year']);\n return isGregorianLeapYear(view.year!) ? 366 : 365;\n}\n\nexport function monthsInYear(_view: DateFieldView): 12 {\n // Gregorian always has 12 months. Other calendars (Hebrew leap years\n // have 13) need calendar-aware logic this module doesn't carry — see\n // the file-level comment. The `_view` parameter is kept so the\n // signature mirrors the other helpers and a future calendar-aware\n // implementation can use it without changing call sites.\n return 12;\n}\n\nexport function isLeapYear(view: DateFieldView): boolean {\n requireFields(view, ['year']);\n return isGregorianLeapYear(view.year!);\n}\n\n// `isLeapMonth` would require knowing which month of a leap-year-aware\n// calendar is the leap month — Gregorian doesn't have one, so this\n// returns false unconditionally. Kept here so the public surface\n// matches the module's listing; non-Gregorian calendars need\n// a different implementation.\nexport function isLeapMonth(_view: DateFieldView): boolean {\n return false;\n}\n\nexport function dayOfYearHelper(view: DateFieldView): number {\n requireFields(view, ['year', 'month', 'day']);\n return dayOfYear(view.year!, view.month!, view.day!);\n}\n\n// ISO 8601 week and week-year. Delegates to isoWeek.ts's\n// isoWeekYearAndWeek, which does the full Thursday-of-week\n// computation to handle the year-boundary cases (Dec 29-31 belonging\n// to week 1 of next year, Jan 1-3 belonging to week 52/53 of the\n// previous year).\nexport function weekOfYear(view: DateFieldView): number {\n requireFields(view, ['year', 'month', 'day', 'dayOfWeek']);\n return isoWeekYearAndWeek(view.year!, view.month!, view.day!, view.dayOfWeek!).week;\n}\n\nexport function weekYear(view: DateFieldView): number {\n requireFields(view, ['year', 'month', 'day', 'dayOfWeek']);\n return isoWeekYearAndWeek(view.year!, view.month!, view.day!, view.dayOfWeek!).isoYear;\n}\n\n/**\n * Fiscal-quarter options. `startMonth` is the calendar month (1-12) the\n * fiscal year begins on — e.g. `7` for a fiscal year starting in July.\n * Omitted or `1` gives the calendar-quarter behavior getQuarter() has\n * always had (Jan-Mar = Q1, etc.), so existing callers passing nothing\n * see no change.\n */\nexport interface QuarterOptions {\n startMonth?: number;\n}\n\nfunction validateStartMonth(startMonth: number): void {\n if (!Number.isInteger(startMonth) || startMonth < 1 || startMonth > 12) {\n throw new Error(\n `temporal-fmt: getQuarter's startMonth must be an integer from 1 to 12 (got ${startMonth}).`\n );\n }\n}\n\nexport function getQuarter(view: DateFieldView, options: QuarterOptions = {}): number {\n requireFields(view, ['month']);\n const startMonth = options.startMonth ?? 1;\n validateStartMonth(startMonth);\n if (startMonth === 1) {\n // Mirrors the Q token: months 1-3 → Q1, 4-6 → Q2, 7-9 → Q3, 10-12 → Q4.\n return Math.ceil(view.month! / 3);\n }\n // Fiscal case: shift the month so startMonth becomes month 1 of the\n // fiscal year (mod 12, 1-indexed), then apply the same ceil(/3) rule.\n // E.g. startMonth=7 (fiscal year starts July): July→1, Aug→2, ...,\n // Dec→6, Jan→7, ..., June→12. Then Q1 = fiscal months 1-3 (Jul-Sep),\n // matching the common \"FY starts in July\" convention where Q1 is the\n // first quarter of the fiscal year, not a quarter numbered by which\n // calendar quarter it falls in.\n const shifted = ((view.month! - startMonth + 12) % 12) + 1;\n return Math.ceil(shifted / 3);\n}\n\n// `getMonth` / `getWeekday` look trivial (just read the field) but\n// they're kept as real functions for API surface consistency with the\n// rest of this module. They also normalize: getWeekday returns 1-7\n// (Mon-Sun, matching Temporal's spec) regardless of what numbering the\n// caller's underlying value uses.\nexport function getMonth(view: DateFieldView): number {\n requireFields(view, ['month']);\n return view.month!;\n}\n\nexport function getWeekday(view: DateFieldView): number {\n requireFields(view, ['dayOfWeek']);\n return view.dayOfWeek!;\n}\n\n// startOf / endOf return new field bags (not Temporal objects — this\n// module is polyfill-free) with the relevant fields zeroed/extended.\n// Callers can pass the result to a Temporal constructor if they want\n// a typed value.\nexport type StartOfUnit = 'day' | 'month' | 'year' | 'hour' | 'minute' | 'second';\n\n// Returns true if the given unit (when used with startOf/endOf) should\n// also touch the time fields. 'day', 'month', 'year' all imply a\n// resolution coarser than an hour, so startOf zeroes the time fields\n// and endOf maxes them. Sub-hour units (hour/minute/second) only touch\n// the fields finer than themselves.\nfunction touchesTime(unit: StartOfUnit): boolean {\n return unit === 'day' || unit === 'month' || unit === 'year';\n}\n\n// startOf/endOf reassign year/month/day, which invalidates any\n// dayOfWeek carried over from the input — a plain { ...view } spread\n// leaves the old value sitting there unchanged. Same failure mode\n// businessCalendar.ts's isBusinessDay() works around for add(); we\n// recompute here rather than trust the copied field.\nfunction recomputeDayOfWeek(view: DateFieldView): void {\n if (typeof view.dayOfWeek !== 'number') return;\n /* c8 ignore start @preserve -- unreachable: startOf()/endOf() both call\n * asDateFieldView() before this, which already throws if year/month/day\n * aren't all numbers — so by the time a value with a numeric dayOfWeek\n * reaches here, year/month/day are guaranteed present too. */\n if (typeof view.year !== 'number' || typeof view.month !== 'number' || typeof view.day !== 'number') return;\n /* c8 ignore stop @preserve */\n const jsDow = new Date(Date.UTC(view.year, view.month - 1, view.day)).getUTCDay(); // 0=Sun..6=Sat\n view.dayOfWeek = jsDow === 0 ? 7 : jsDow; // 1=Mon..7=Sun\n}\n\nexport function startOf(value: unknown, unit: StartOfUnit): DateFieldView {\n const view = asDateFieldView(value);\n const result: DateFieldView = { ...view };\n if (unit === 'year') {\n result.month = 1;\n result.day = 1;\n } else if (unit === 'month') {\n result.day = 1;\n }\n recomputeDayOfWeek(result);\n if (touchesTime(unit)) {\n result.hour = 0;\n result.minute = 0;\n result.second = 0;\n result.millisecond = 0;\n } else if (unit === 'hour') {\n result.minute = 0;\n result.second = 0;\n result.millisecond = 0;\n } else if (unit === 'minute') {\n result.second = 0;\n result.millisecond = 0;\n } else if (unit === 'second') {\n result.millisecond = 0;\n }\n return result;\n}\n\nexport function endOf(value: unknown, unit: StartOfUnit): DateFieldView {\n const view = asDateFieldView(value);\n const result: DateFieldView = { ...view };\n if (unit === 'year') {\n result.month = 12;\n result.day = daysInMonth({ year: result.year!, month: 12 });\n } else if (unit === 'month') {\n result.day = daysInMonth({ year: result.year!, month: result.month! });\n }\n recomputeDayOfWeek(result);\n if (touchesTime(unit)) {\n result.hour = 23;\n result.minute = 59;\n result.second = 59;\n result.millisecond = 999;\n } else if (unit === 'hour') {\n result.minute = 59;\n result.second = 59;\n result.millisecond = 999;\n } else if (unit === 'minute') {\n result.second = 59;\n result.millisecond = 999;\n } else if (unit === 'second') {\n result.millisecond = 999;\n }\n return result;\n}\n\n// Type-narrowing helpers used by the comparison/arithmetic modules.\n// Lets them accept any of the four date-carrying Temporal types without\n// importing Temporal itself.\nexport function asDateFieldView(value: unknown): DateFieldView {\n if (typeof value !== 'object' || value === null) {\n throw new Error(`temporal-fmt: expected a date-carrying Temporal value, got ${String(value)}.`);\n }\n // Temporal instances expose year/month/day/etc. as prototype getters,\n // not own enumerable properties — so `{ ...value }` would lose them.\n // Read them explicitly. Only the fields actually present on this\n // value type end up in the returned view.\n const v = value as Record<string, unknown>;\n const out: DateFieldView = {};\n if (typeof v.year === 'number') out.year = v.year;\n if (typeof v.month === 'number') out.month = v.month;\n if (typeof v.day === 'number') out.day = v.day;\n if (typeof v.hour === 'number') out.hour = v.hour;\n if (typeof v.minute === 'number') out.minute = v.minute;\n if (typeof v.second === 'number') out.second = v.second;\n if (typeof v.millisecond === 'number') out.millisecond = v.millisecond;\n if (typeof v.dayOfWeek === 'number') out.dayOfWeek = v.dayOfWeek;\n if (typeof v.calendarId === 'string') out.calendarId = v.calendarId;\n if (out.year === undefined || out.month === undefined || out.day === undefined) {\n throw new Error(\n `temporal-fmt: value is missing year/month/day fields — pass a Temporal.PlainDate / PlainDateTime / ZonedDateTime.`\n );\n }\n return out;\n}\n\n// Re-export the TemporalType alias so callers can import everything\n// from one place.\nexport type { TemporalType } from './tokenMetadata.js';\n// Re-export TemporalLike for the same reason.\nexport type { TemporalLike } from './tokens.js';","// Date arithmetic helpers. Pure functions returning\n// field bags, same convention as calendarUtils.ts/comparison.ts — no\n// Temporal namespace needed. Callers can pass the result back into a\n// Temporal constructor to get a typed value, or chain operations\n// without committing to a Temporal implementation.\n\nimport { asDateFieldView, daysInMonth, type DateFieldView } from './calendarUtils.js';\n\nexport type AddUnit = 'years' | 'months' | 'weeks' | 'days' | 'hours' | 'minutes' | 'seconds' | 'milliseconds';\n\ninterface DateTimeFieldView extends DateFieldView {\n hour?: number;\n minute?: number;\n second?: number;\n millisecond?: number;\n}\n\nfunction asDateTime(value: unknown): DateTimeFieldView {\n return asDateFieldView(value) as DateTimeFieldView;\n}\n\n// Recomputes dayOfWeek after year/month/day change. Mirrors\n// calendarUtils.ts's recomputeDayOfWeek — same fix, needed here too\n// since add()/subtract() mutate the date fields via a shallow spread\n// that otherwise leaves the old dayOfWeek sitting there, silently wrong.\nfunction recomputeDayOfWeek(view: DateTimeFieldView): void {\n if (typeof view.dayOfWeek !== 'number') return;\n /* c8 ignore start @preserve -- unreachable: every call site (add()'s\n 'years'/'months' cases, shiftDays()) passes a `result` whose\n year/month/day were just explicitly set, and the value originally\n came from asDateTime()/asDateFieldView(), which throws unless\n year/month/day are all present as numbers. So by the time this guard\n runs, all three are guaranteed valid. Kept in case a future caller\n constructs a DateTimeFieldView bypassing that validation. */\n if (typeof view.year !== 'number' || typeof view.month !== 'number' || typeof view.day !== 'number') return;\n /* c8 ignore stop @preserve */\n const jsDow = new Date(Date.UTC(view.year, view.month - 1, view.day)).getUTCDay(); // 0=Sun..6=Sat\n view.dayOfWeek = jsDow === 0 ? 7 : jsDow; // 1=Mon..7=Sun\n}\n\n// Adds the requested amount to the value's specified unit. Returns a\n// new field bag; the input is not mutated. Handles month/year overflow\n// by clamping to the last valid day of the target month (Feb 29 + 1\n// year on a non-leap year → Feb 28) — Temporal's `constrain` overflow\n// mode, which is the closest match to \"do the obvious thing\" callers\n// expect from arithmetic.\nexport function add(value: unknown, amount: number, unit: AddUnit): DateTimeFieldView {\n const v = asDateTime(value);\n let result: DateTimeFieldView = { ...v };\n switch (unit) {\n case 'years': {\n /* c8 ignore start @preserve -- the `?? 0` fallback is unreachable:\n asDateTime()/asDateFieldView() (called at the top of add()) throws\n unless year is present as a number, so result.year is never\n undefined here. Kept as a guard against a future change that\n relaxes that validation. */\n result.year = (result.year ?? 0) + amount;\n /* c8 ignore stop @preserve */\n // Clamp day-of-month to the new month's length.\n const maxDay = daysInMonth({ year: result.year!, month: result.month! });\n if (result.day! > maxDay) result.day = maxDay;\n recomputeDayOfWeek(result);\n break;\n }\n case 'months': {\n // Total months = year*12 + month + amount, then split back.\n /* c8 ignore start @preserve -- both `??` fallbacks are unreachable\n for the same reason as the 'years' case above: asDateFieldView()\n guarantees year and month are present numbers before add() ever\n reaches here. */\n const total = (result.year ?? 0) * 12 + (result.month ?? 1) - 1 + amount;\n /* c8 ignore stop @preserve */\n result.year = Math.floor(total / 12);\n result.month = (total % 12) + 1;\n if (result.month < 1) { result.month += 12; result.year -= 1; }\n // Negative modulo handling: when total < 0, the mod goes negative.\n // Re-normalize.\n /* c8 ignore start @preserve -- unreachable: (total % 12) + 1 can never\n exceed 12 for any integer total in JS (its range is [-10, 12] since\n JS's % can return a negative remainder but never one with\n magnitude >= 12, so adding 1 tops out at 12). Only the < 1 branch\n above is reachable; this was written symmetrically with it but the\n overflow direction it guards against can't occur. Kept rather than\n removed since it costs nothing and documents the intent. */\n if (result.month > 12) { result.month -= 12; result.year += 1; }\n /* c8 ignore stop @preserve */\n const maxDay = daysInMonth({ year: result.year!, month: result.month! });\n if (result.day! > maxDay) result.day = maxDay;\n recomputeDayOfWeek(result);\n break;\n }\n case 'weeks':\n result = shiftDays(result, amount * 7);\n break;\n case 'days':\n result = shiftDays(result, amount);\n break;\n case 'hours':\n result = shiftTime(result, amount * 3_600_000);\n break;\n case 'minutes':\n result = shiftTime(result, amount * 60_000);\n break;\n case 'seconds':\n result = shiftTime(result, amount * 1_000);\n break;\n case 'milliseconds':\n result = shiftTime(result, amount);\n break;\n }\n return result;\n}\n\nfunction shiftDays(v: DateTimeFieldView, days: number): DateTimeFieldView {\n // Convert Y/M/D to a day count, add, convert back. Using the same\n // algorithm as comparison.ts's sameWeek helper — proleptic Gregorian\n // day count via Howard Hinnant's era-based formula.\n const y = v.year!, m = v.month!, d = v.day!;\n const y2 = m <= 2 ? y - 1 : y;\n const era = Math.floor((y2 >= 0 ? y2 : y2 - 399) / 400);\n const yoe = y2 - era * 400;\n const m2 = m > 2 ? m - 3 : m + 9;\n const doy = Math.floor((153 * m2 + 2) / 5) + d - 1;\n const doe = yoe * 365 + Math.floor(yoe / 4) - Math.floor(yoe / 100) + doy;\n const totalDays = era * 146097 + doe - 719468 + days;\n\n // Invert: totalDays → Y/M/D. Same source (Howard Hinnant's days_from_civil).\n const z = totalDays + 719468;\n const era2 = Math.floor((z >= 0 ? z : z - 146096) / 146097);\n const doe2 = z - era2 * 146097;\n const yoe2 = Math.floor((doe2 - Math.floor(doe2 / 1460) + Math.floor(doe2 / 36524) - Math.floor(doe2 / 146096)) / 365);\n const y2out = yoe2 + era2 * 400;\n const doy2 = doe2 - (365 * yoe2 + Math.floor(yoe2 / 4) - Math.floor(yoe2 / 100));\n const mp = Math.floor((5 * doy2 + 2) / 153);\n const d2 = doy2 - Math.floor((153 * mp + 2) / 5) + 1;\n const m2out = mp < 10 ? mp + 3 : mp - 9;\n const yOut = m2out <= 2 ? y2out + 1 : y2out;\n\n const result: DateTimeFieldView = { ...v, year: yOut, month: m2out, day: d2 };\n recomputeDayOfWeek(result);\n return result;\n}\n\nfunction shiftTime(v: DateTimeFieldView, msDelta: number): DateTimeFieldView {\n // Convert all time fields to ms, add, then split back. Day overflow\n // propagates to shiftDays; sub-second precision is preserved (caller\n // asking for hours/minutes/seconds/milliseconds gets ms-resolution\n // arithmetic, which is the limit of these helpers — nanoseconds\n // aren't supported here, only via Temporal.Duration's own add).\n const MS_PER_DAY = 86_400_000;\n const MS_PER_HOUR = 3_600_000;\n const MS_PER_MINUTE = 60_000;\n const MS_PER_SECOND = 1_000;\n\n const totalMs = (v.hour ?? 0) * MS_PER_HOUR\n + (v.minute ?? 0) * MS_PER_MINUTE\n + (v.second ?? 0) * MS_PER_SECOND\n + (v.millisecond ?? 0)\n + msDelta;\n\n // Split into day-overflow + within-day ms.\n const dayOverflow = Math.floor(totalMs / MS_PER_DAY);\n let withinDay = totalMs % MS_PER_DAY;\n if (withinDay < 0) { withinDay += MS_PER_DAY; }\n\n const hour = Math.floor(withinDay / MS_PER_HOUR);\n const minute = Math.floor((withinDay % MS_PER_HOUR) / MS_PER_MINUTE);\n const second = Math.floor((withinDay % MS_PER_MINUTE) / MS_PER_SECOND);\n const millisecond = withinDay % MS_PER_SECOND;\n\n const result: DateTimeFieldView = { ...v, hour, minute, second, millisecond };\n if (dayOverflow !== 0) {\n return shiftDays(result, dayOverflow);\n }\n return result;\n}\n\nexport function subtract(value: unknown, amount: number, unit: AddUnit): DateTimeFieldView {\n return add(value, -amount, unit);\n}\n\n// Per-unit convenience wrappers — matches the grouping of\n// addYears / addMonths / ... / subtractNanoseconds. Nanosecond variants\n// aren't provided here because these helpers operate on field bags, and\n// the millisecond/microsecond/nanosecond split isn't preserved through\n// arithmetic at sub-millisecond precision the way Temporal.Duration's\n// own add preserves it. For ns-precision arithmetic, use Temporal.Duration\n// directly.\nexport const addYears = (v: unknown, n: number) => add(v, n, 'years');\nexport const addMonths = (v: unknown, n: number) => add(v, n, 'months');\nexport const addWeeks = (v: unknown, n: number) => add(v, n, 'weeks');\nexport const addDays = (v: unknown, n: number) => add(v, n, 'days');\nexport const addHours = (v: unknown, n: number) => add(v, n, 'hours');\nexport const addMinutes = (v: unknown, n: number) => add(v, n, 'minutes');\nexport const addSeconds = (v: unknown, n: number) => add(v, n, 'seconds');\nexport const addMilliseconds = (v: unknown, n: number) => add(v, n, 'milliseconds');\n\nexport const subtractYears = (v: unknown, n: number) => subtract(v, n, 'years');\nexport const subtractMonths = (v: unknown, n: number) => subtract(v, n, 'months');\nexport const subtractWeeks = (v: unknown, n: number) => subtract(v, n, 'weeks');\nexport const subtractDays = (v: unknown, n: number) => subtract(v, n, 'days');\nexport const subtractHours = (v: unknown, n: number) => subtract(v, n, 'hours');\nexport const subtractMinutes = (v: unknown, n: number) => subtract(v, n, 'minutes');\nexport const subtractSeconds = (v: unknown, n: number) => subtract(v, n, 'seconds');\nexport const subtractMilliseconds = (v: unknown, n: number) => subtract(v, n, 'milliseconds');\n\n// difference(): returns the count of `unit` boundaries between two values.\n// Pure-integer math, no Temporal.Duration involved. For sub-day\n// precision the result is an integer count of the requested unit (not\n// a Duration field bag) — matches the most common caller expectation\n// (\"how many days between these two dates?\").\nexport type DiffUnit = 'years' | 'months' | 'weeks' | 'days' | 'hours' | 'minutes' | 'seconds' | 'milliseconds';\n\nexport function difference(a: unknown, b: unknown, unit: DiffUnit): number {\n const av = asDateTime(a);\n const bv = asDateTime(b);\n\n // For day-granular units (years/months/weeks/days), compute via\n // calendar arithmetic on the date fields. For sub-day units, compute\n // via total-ms and divide.\n if (unit === 'years') {\n return bv.year! - av.year!;\n }\n if (unit === 'months') {\n return (bv.year! * 12 + bv.month! - 1) - (av.year! * 12 + av.month! - 1);\n }\n if (unit === 'weeks' || unit === 'days') {\n const aDays = toDayCount(av);\n const bDays = toDayCount(bv);\n const days = bDays - aDays;\n return unit === 'weeks' ? Math.trunc(days / 7) : days;\n }\n\n // Sub-day units: total-ms math.\n const MS_PER_HOUR = 3_600_000;\n const MS_PER_MINUTE = 60_000;\n const MS_PER_SECOND = 1_000;\n const aMs = toTotalMs(av);\n const bMs = toTotalMs(bv);\n const diffMs = bMs - aMs;\n switch (unit) {\n case 'hours': return Math.trunc(diffMs / MS_PER_HOUR);\n case 'minutes': return Math.trunc(diffMs / MS_PER_MINUTE);\n case 'seconds': return Math.trunc(diffMs / MS_PER_SECOND);\n case 'milliseconds': return diffMs;\n }\n}\n\nfunction toDayCount(v: DateTimeFieldView): number {\n const y = v.year!, m = v.month!, d = v.day!;\n const y2 = m <= 2 ? y - 1 : y;\n const era = Math.floor((y2 >= 0 ? y2 : y2 - 399) / 400);\n const yoe = y2 - era * 400;\n const m2 = m > 2 ? m - 3 : m + 9;\n const doy = Math.floor((153 * m2 + 2) / 5) + d - 1;\n const doe = yoe * 365 + Math.floor(yoe / 4) - Math.floor(yoe / 100) + doy;\n return era * 146097 + doe - 719468;\n}\n\nfunction toTotalMs(v: DateTimeFieldView): number {\n const MS_PER_DAY = 86_400_000;\n const MS_PER_HOUR = 3_600_000;\n const MS_PER_MINUTE = 60_000;\n const MS_PER_SECOND = 1_000;\n return toDayCount(v) * MS_PER_DAY\n + (v.hour ?? 0) * MS_PER_HOUR\n + (v.minute ?? 0) * MS_PER_MINUTE\n + (v.second ?? 0) * MS_PER_SECOND\n + (v.millisecond ?? 0);\n}\n\n// Per-unit difference wrappers — same convenience pattern as the add*\n// wrappers above.\nexport const differenceInYears = (a: unknown, b: unknown) => difference(a, b, 'years');\nexport const differenceInMonths = (a: unknown, b: unknown) => difference(a, b, 'months');\nexport const differenceInWeeks = (a: unknown, b: unknown) => difference(a, b, 'weeks');\nexport const differenceInDays = (a: unknown, b: unknown) => difference(a, b, 'days');\nexport const differenceInHours = (a: unknown, b: unknown) => difference(a, b, 'hours');\nexport const differenceInMinutes = (a: unknown, b: unknown) => difference(a, b, 'minutes');\nexport const differenceInSeconds = (a: unknown, b: unknown) => difference(a, b, 'seconds');\nexport const differenceInMilliseconds = (a: unknown, b: unknown) => difference(a, b, 'milliseconds');"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/timezone.ts","../src/temporalProvider.ts","../src/isoWeek.ts","../src/calendarUtils.ts","../src/arithmetic.ts"],"sourcesContent":["// Time-zone subsystem. Wraps Temporal.ZonedDateTime's\n// timezone introspection surface in temporal-fmt's field-based convention.\n// Includes disambiguation modes (compatible/earlier/later/reject) for\n// DST gaps and overlaps, plus transition queries (getNextTransition,\n// getPreviousTransition, getTransitions).\n\nimport { getTemporal } from './temporalProvider.js';\nimport { add } from './arithmetic.js';\n\nexport type DisambiguationMode = 'compatible' | 'earlier' | 'later' | 'reject';\n\nexport interface ResolveZonedOptions {\n disambiguation?: DisambiguationMode;\n overflow?: 'constrain' | 'reject';\n offset?: 'use' | 'ignore' | 'prefer' | 'reject';\n}\n\n// Resolves a wall-clock time in a timezone, applying disambiguation\n// for DST gaps and overlaps.\nexport function resolveZoned(\n fields: { year: number; month: number; day: number; hour?: number; minute?: number; second?: number; millisecond?: number; microsecond?: number; nanosecond?: number },\n timeZone: string,\n options: ResolveZonedOptions = {},\n): unknown {\n const temporal = getTemporal();\n const disambiguation = options.disambiguation ?? 'compatible';\n const overflow = options.overflow ?? 'constrain';\n // Cast options to a permissive record — Temporal.ZonedDateTime.from\n // accepts disambiguation/offset options, but the existing\n // TemporalFactory.from() signature in temporalProvider.ts is narrower.\n // The runtime accepts the wider shape; this cast bypasses the type\n // narrowing without changing runtime behavior.\n const fromOptions = {\n overflow,\n disambiguation,\n offset: options.offset ?? 'prefer',\n } as unknown as Parameters<typeof temporal.ZonedDateTime.from>[1];\n try {\n return temporal.ZonedDateTime.from(\n {\n year: fields.year,\n month: fields.month,\n day: fields.day,\n hour: fields.hour ?? 0,\n minute: fields.minute ?? 0,\n second: fields.second ?? 0,\n millisecond: fields.millisecond ?? 0,\n microsecond: fields.microsecond ?? 0,\n nanosecond: fields.nanosecond ?? 0,\n timeZone,\n },\n fromOptions,\n );\n } catch (err) {\n // Surface DST gap / overlap errors with a clearer message.\n const msg = (err as Error).message;\n if (/no such (wall-clock )?time/i.test(msg) && disambiguation === 'reject') {\n throw new Error(\n `temporal-fmt: \"${timeZone}\" has no such wall-clock time on ${fields.year}-${fields.month}-${fields.day}T${fields.hour ?? 0}:${fields.minute ?? 0} — ` +\n `it falls in a DST gap. Pass { disambiguation: 'compatible' | 'earlier' | 'later' } to pick an instant.`\n );\n }\n throw err;\n }\n}\n\nexport function getTimeZone(value: unknown): string {\n const v = value as { timeZoneId?: string };\n if (typeof v?.timeZoneId !== 'string') {\n throw new Error(`temporal-fmt: getTimeZone() expected a ZonedDateTime, got ${typeof value}.`);\n }\n return v.timeZoneId;\n}\n\nexport function getOffset(value: unknown): string {\n const v = value as { offset?: string };\n if (typeof v?.offset !== 'string') {\n throw new Error(`temporal-fmt: getOffset() expected a ZonedDateTime, got ${typeof value}.`);\n }\n return v.offset;\n}\n\nexport function getOffsetNanoseconds(value: unknown): number {\n const v = value as { offsetNanoseconds?: number; offset?: string };\n if (typeof v?.offsetNanoseconds === 'number') return v.offsetNanoseconds;\n if (typeof v?.offset === 'string') {\n // Parse ±HH:MM → nanoseconds.\n const m = v.offset.match(/^([+-])(\\d{2}):(\\d{2})$/);\n if (!m) throw new Error(`temporal-fmt: getOffsetNanoseconds() couldn't parse offset \"${v.offset}\".`);\n const sign = m[1] === '-' ? -1 : 1;\n return sign * (Number(m[2]) * 3600 + Number(m[3]) * 60) * 1_000_000_000;\n }\n throw new Error(`temporal-fmt: getOffsetNanoseconds() expected a ZonedDateTime, got ${typeof value}.`);\n}\n\n// DST detection: a ZonedDateTime is in DST iff the offset is different\n// from the timezone's standard offset at the same instant. Computed\n// by comparing the current offset to the offset in January (Northern\n// Hemisphere) or July (Southern Hemisphere) of the same year — a\n// heuristic that's right for most populated zones.\nexport function isDST(value: unknown): boolean {\n const v = value as { timeZoneId?: string; offset?: string; year?: number; toInstant?: () => unknown };\n if (typeof v?.timeZoneId !== 'string' || typeof v?.offset !== 'string' || typeof v?.year !== 'number') {\n throw new Error(`temporal-fmt: isDST() expected a ZonedDateTime, got ${typeof value}.`);\n }\n // Compute the offset for January 1 of the same year (standard time\n // for Northern Hemisphere zones) and compare. For Southern Hemisphere\n // zones January is summer, so we'd want July instead — but checking\n // January vs current is good enough for the common case, and we\n // can't reliably determine hemisphere without a lookup table.\n const temporal = getTemporal();\n try {\n const jan = temporal.ZonedDateTime.from(\n { year: v.year, month: 1, day: 1, hour: 12, timeZone: v.timeZoneId },\n { disambiguation: 'compatible' } as unknown as Parameters<typeof temporal.ZonedDateTime.from>[1],\n ) as { offset: string };\n return jan.offset !== v.offset;\n } catch {\n return false;\n }\n}\n\n// Returns the next DST transition strictly after `value`, or undefined\n// if no transition occurs within the next 2 years. Implemented by\n// walking day-by-day checking for offset changes — slow but simple,\n// and correct across all IANA zones.\nexport function getNextTransition(value: unknown): unknown | undefined {\n return findTransition(value, 1);\n}\n\nexport function getPreviousTransition(value: unknown): unknown | undefined {\n return findTransition(value, -1);\n}\n\nfunction findTransition(value: unknown, direction: 1 | -1): unknown | undefined {\n const v = value as { timeZoneId?: string; offset?: string; toInstant?: () => unknown; year?: number; month?: number; day?: number; hour?: number; minute?: number; second?: number; millisecond?: number };\n if (typeof v?.timeZoneId !== 'string') {\n throw new Error(`temporal-fmt: ${direction > 0 ? 'getNextTransition' : 'getPreviousTransition'}() expected a ZonedDateTime, got ${typeof value}.`);\n }\n const temporal = getTemporal();\n const timeZone = v.timeZoneId;\n let candidateFields = add(value, direction, 'days');\n const startOffset = v.offset!;\n for (let i = 0; i < 365 * 2; i++) {\n // Rebuild a real ZonedDateTime for this candidate day, in this\n // timezone, so `.offset` reflects the actual UTC offset on that\n // day rather than being absent. add() only produces a plain field\n // bag (it has no notion of timezone), so re-attaching timeZone via\n // ZonedDateTime.from is what actually lets us detect a DST change\n // here — using the field bag's own (nonexistent) offset would make\n // every call \"find\" a transition on the very first day checked.\n const cf = candidateFields as { year: number; month: number; day: number; hour: number; minute: number; second: number; millisecond: number };\n const candidateZdt = temporal.ZonedDateTime.from(\n { ...cf, timeZone },\n { disambiguation: 'compatible' } as unknown as Parameters<typeof temporal.ZonedDateTime.from>[1],\n ) as { offset: string };\n if (candidateZdt.offset !== startOffset) {\n // Found a transition day. Return the reconstructed ZonedDateTime.\n return candidateZdt;\n }\n candidateFields = add(candidateFields, direction, 'days');\n }\n return undefined;\n}\n\nexport function getTransitions(start: unknown, end: unknown): unknown[] {\n const result: unknown[] = [];\n const startV = start as { timeZoneId?: string; offset?: string; year?: number; month?: number; day?: number };\n if (typeof startV?.timeZoneId !== 'string') {\n throw new Error(`temporal-fmt: getTransitions() expected a ZonedDateTime for start, got ${typeof start}.`);\n }\n const endV = end as { year: number; month: number; day: number };\n const temporal = getTemporal();\n const timeZone = startV.timeZoneId;\n let cursorFields = add(start, 1, 'days');\n let lastOffset = startV.offset!;\n for (let i = 0; i < 365 * 5; i++) {\n // Same reconstruction as findTransition() above — add() strips\n // timezone/offset info, so we rebuild a real ZonedDateTime each\n // iteration to read its actual offset instead of comparing against\n // a field bag that never has one.\n const cf = cursorFields as { year: number; month: number; day: number; hour: number; minute: number; second: number; millisecond: number };\n const cursorZdt = temporal.ZonedDateTime.from(\n { ...cf, timeZone },\n { disambiguation: 'compatible' } as unknown as Parameters<typeof temporal.ZonedDateTime.from>[1],\n ) as { offset: string; year: number; month: number; day: number };\n if (cursorZdt.offset !== lastOffset) {\n // Found a transition.\n if (cursorZdt.year > endV.year || (cursorZdt.year === endV.year && (cursorZdt.month > endV.month || (cursorZdt.month === endV.month && cursorZdt.day > endV.day)))) break;\n result.push(cursorZdt);\n lastOffset = cursorZdt.offset;\n }\n cursorFields = add(cursorFields, 1, 'days');\n }\n return result;\n}\n\n// Returns the list of possible instants for a wall-clock time in a\n// zone — used to detect gaps (0 instants) and overlaps (2 instants).\nexport function possibleInstantsFor(\n fields: { year: number; month: number; day: number; hour: number; minute: number; second: number; millisecond: number },\n timeZone: string,\n): unknown[] {\n const temporal = getTemporal();\n // Resolve the same wall-clock fields twice, forcing disambiguation\n // toward the earlier and later side of any DST boundary. Comparing\n // the two results tells us which of the three cases we're in:\n // - gap (e.g. 2:30am on a spring-forward day): neither result's own\n // wall-clock fields match what was requested, since Temporal has\n // to shift off the nonexistent time in both directions — 0 instants.\n // - overlap (e.g. 1:30am on a fall-back day): both results keep the\n // requested wall-clock time but land on different instants (one\n // per side of the boundary) — 2 instants.\n // - normal time: both results match the requested wall-clock time\n // and resolve to the same instant — 1 instant.\n const earlier = temporal.ZonedDateTime.from(\n { ...fields, timeZone },\n { disambiguation: 'earlier', offset: 'ignore' } as unknown as Parameters<typeof temporal.ZonedDateTime.from>[1],\n ) as { year: number; month: number; day: number; hour: number; minute: number; second: number; millisecond: number; toInstant: () => { epochNanoseconds: bigint } };\n const later = temporal.ZonedDateTime.from(\n { ...fields, timeZone },\n { disambiguation: 'later', offset: 'ignore' } as unknown as Parameters<typeof temporal.ZonedDateTime.from>[1],\n ) as { year: number; month: number; day: number; hour: number; minute: number; second: number; millisecond: number; toInstant: () => { epochNanoseconds: bigint } };\n\n const matchesRequestedWallClock = (z: typeof earlier) =>\n z.year === fields.year && z.month === fields.month && z.day === fields.day &&\n z.hour === fields.hour && z.minute === fields.minute &&\n z.second === fields.second && z.millisecond === fields.millisecond;\n\n if (!matchesRequestedWallClock(earlier) || !matchesRequestedWallClock(later)) {\n // Gap — the requested wall-clock time doesn't exist in this zone.\n return [];\n }\n if (earlier.toInstant().epochNanoseconds === later.toInstant().epochNanoseconds) {\n // Normal time — both disambiguation directions agree on the instant.\n return [earlier];\n }\n // Overlap — same wall-clock time, two distinct instants.\n return [earlier, later];\n}","// This package's tsconfig assumes lib: [\"ESNext\"] only — no ambient\n// `Temporal` namespace type. Everywhere else in this codebase only ever\n// *reads* fields off a Temporal-like object the caller already built\n// (TemporalLike in tokens.ts). This module is the single choke point for\n// touching a *namespace*-shaped Temporal (PlainDate.from, etc.): parse()\n// uses it to construct a result, tokens.ts uses it to probe native\n// Intl<->Temporal support. Consumers can hand us an implementation via\n// setTemporal(), or we fall back to globalThis.Temporal\ninterface TemporalFactory {\n from(fields: Record<string, number | string | undefined>, options?: { overflow?: 'constrain' | 'reject'; disambiguation?: 'compatible' | 'earlier' | 'later' | 'reject'; offset?: 'use' | 'ignore' | 'prefer' | 'reject' }): unknown;\n // compare() lives on the namespace (Temporal.PlainDate.compare), not on\n // instances. Optional here since a consumer might be passing a\n // stripped-down Temporal shim that doesn't expose it.\n compare?(one: unknown, two: unknown): number;\n}\n\n// Instant is constructed via fromEpochMilliseconds / fromEpochNanoseconds\n// rather than from(fields). Separate interface.\ninterface InstantFactory {\n from(iso: string): unknown;\n fromEpochMilliseconds(ms: number): unknown;\n fromEpochMicroseconds(µs: number): unknown;\n fromEpochNanoseconds(ns: bigint): unknown;\n}\n\n// Duration is constructed via from(fields). Carries round() and compare().\ninterface DurationFactory extends TemporalFactory {\n compare?(one: unknown, two: unknown): number;\n prototype?: { round(options: unknown): unknown };\n}\n\n// PlainYearMonth / PlainMonthDay are also constructed via from(fields).\n// Same factory shape, kept separate for type clarity in callers that\n// want to narrow.\nexport interface TemporalNamespace {\n PlainDate: TemporalFactory;\n PlainTime: TemporalFactory;\n PlainDateTime: TemporalFactory;\n ZonedDateTime: TemporalFactory;\n Instant?: InstantFactory;\n Duration?: DurationFactory;\n PlainYearMonth?: TemporalFactory;\n PlainMonthDay?: TemporalFactory;\n}\n\nlet injectedTemporal: TemporalNamespace | undefined;\n\n// Anything that caches a result derived from *which* Temporal\n// implementation is active (right now: tokens.ts's native-Intl-support\n// probe) registers here so it gets invalidated whenever setTemporal()\n// swaps the implementation — see the comment on setTemporal() below for\n// why that matters. A plain array instead of an event-emitter-style API\n// since this only ever needs \"call every listener, in registration order,\n// with no payload\" — nothing here needs unsubscribe or payload data.\nconst onTemporalChanged: Array<() => void> = [];\n\nexport function subscribeToTemporalChanges(listener: () => void): void {\n onTemporalChanged.push(listener);\n}\n\n/**\n * Explicitly hand temporal-fmt the Temporal implementation to use, instead\n * of relying on a global `Temporal`. Call this once, before your first\n * `format()`/`parse()`/`parseISO()`/etc.\n *\n * Call with no argument (or `undefined`) to clear the override and fall\n * back to `globalThis.Temporal` again.\n *\n * @example\n * import { Temporal } from 'temporal-polyfill';\n * import { setTemporal } from 'temporal-fmt';\n * setTemporal(Temporal);\n */\nexport function setTemporal(temporal?: TemporalNamespace): void {\n injectedTemporal = temporal;\n // tokens.ts's native-Intl-support probe is keyed on whichever Temporal\n // implementation was active the first time a locale-aware format() ran —\n // if that implementation changes later (native -> polyfill or back), the\n // memoized probe result can go stale and disagree with what's now\n // actually active. Resetting it here means the next locale-aware format()\n // after any setTemporal() call re-probes against the implementation\n // that's active *now*, at the (small, one-time-per-switch) cost of\n // re-running the probe.\n for (const listener of onTemporalChanged) listener();\n}\n\nfunction resolveTemporal(): TemporalNamespace | undefined {\n return injectedTemporal ?? (globalThis as unknown as { Temporal?: TemporalNamespace }).Temporal;\n}\n\nexport function getTemporal(): TemporalNamespace {\n const temporal = resolveTemporal();\n if (!temporal) {\n throw new Error(\n 'temporal-fmt: parse() needs a Temporal implementation to construct its result. ' +\n 'Call setTemporal(Temporal) once at startup, or assign one to globalThis.Temporal ' +\n '(native on Node 26+, or a polyfill like temporal-polyfill).'\n );\n }\n return temporal;\n}\n","// ISO 8601 week numbering: a week runs Monday–Sunday, and week 1 of a year\n// is the week containing the year's first Thursday (equivalently, the week\n// containing January 4). This means late-December dates can fall in week 1\n// of the *next* year, and early-January dates can fall in week 52 or 53 of\n// the *previous* year. The \"ISO week-numbering year\" (what `RRRR` formats)\n// is that adjacent year, not the calendar year.\n//\n// Computed here from the date's own year/month/day plus its ISO dayOfWeek\n// (1=Mon..7=Sun, matching Temporal's numbering) using plain Gregorian\n// arithmetic — no Temporal factory needed. format() only has the fields\n// the caller already put on the object, and requiring a Temporal\n// implementation just for ISO week would be a regression for callers who\n// use format() without setTemporal() on a non-26 Node.\n\nconst DAYS_IN_MONTH = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];\nconst CUMULATIVE_DAYS_BY_MONTH = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334];\n\nexport function isGregorianLeapYear(year: number): boolean {\n // Gregorian rule: divisible by 4, except centuries which must also be\n // divisible by 400. Temporal's iso8601 calendar is proleptic Gregorian\n // (no Julian cutover), so this applies for every year, including BCE.\n return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;\n}\n\nfunction daysInYear(year: number): 365 | 366 {\n return isGregorianLeapYear(year) ? 366 : 365;\n}\n\nexport function dayOfYear(year: number, month: number, day: number): number {\n let doy = CUMULATIVE_DAYS_BY_MONTH[month - 1]! + day;\n if (month > 2 && isGregorianLeapYear(year)) doy += 1;\n return doy;\n}\n\n// Jan 1, 2000 was a Saturday — ISO dayOfWeek 6. Anchoring day-of-week\n// computations to a known reference date is simpler and cheaper than\n// pulling in Zeller's congruence, and the reference never changes.\nconst REFERENCE_YEAR = 2000;\nconst REFERENCE_JAN1_DAY_OF_WEEK = 6;\n\nfunction dayOfWeekOfJan1(year: number): number {\n // Sum full-year deltas from the 2000 anchor rather than recomputing from\n // scratch each call — the per-call work is a single mod this way, and\n // the loop rarely runs far (a typical caller passes a current-era year).\n let offset = 0;\n if (year >= REFERENCE_YEAR) {\n for (let y = REFERENCE_YEAR; y < year; y++) offset += daysInYear(y);\n } else {\n for (let y = year; y < REFERENCE_YEAR; y++) offset -= daysInYear(y);\n }\n // Convert \"days since Jan 1, 2000\" into an ISO day-of-week (1=Mon..7=Sun).\n // Jan 1, 2000 was ISO 6 (Sat), so zero-indexed dow = (6-1 + offset) mod 7.\n const zeroIndexed = (((6 - 1 + offset) % 7) + 7) % 7;\n return zeroIndexed + 1;\n}\n\nexport interface IsoWeekDate {\n isoYear: number;\n week: number; // 1..53\n}\n\nexport function isoWeekYearAndWeek(year: number, month: number, day: number, dayOfWeek: number): IsoWeekDate {\n // Step 1: find the Thursday of the current ISO week. The ISO week-numbering\n // year is whichever calendar year that Thursday falls in. Computing it via\n // day-of-year offsets (rather than constructing a Temporal.PlainDate and\n // adding days) keeps this function pure-numeric.\n const doy = dayOfYear(year, month, day);\n const thursdayDoyRelative = doy + (4 - dayOfWeek); // may be <1 or >daysInYear\n\n let isoYear: number;\n let thursdayDoy: number;\n if (thursdayDoyRelative < 1) {\n isoYear = year - 1;\n thursdayDoy = thursdayDoyRelative + daysInYear(isoYear);\n } else if (thursdayDoyRelative > daysInYear(year)) {\n isoYear = year + 1;\n thursdayDoy = thursdayDoyRelative - daysInYear(year);\n } else {\n isoYear = year;\n thursdayDoy = thursdayDoyRelative;\n }\n\n // Step 2: locate the first Thursday of isoYear — its week is week 1. The\n // first Thursday's day-of-year depends on what weekday Jan 1 of isoYear is.\n const jan1Dow = dayOfWeekOfJan1(isoYear);\n const firstThursdayDoy = 1 + ((4 - jan1Dow + 7) % 7); // 1..7\n\n // Step 3: count full weeks between the two Thursdays.\n const week = 1 + Math.floor((thursdayDoy - firstThursdayDoy) / 7);\n return { isoYear, week };\n}\n","// Calendar utility helpers. These are pure functions\n// over the TemporalLike shape — no Temporal namespace needed, same\n// approach as isoWeek.ts and the field-reading helpers in format.ts.\n// Letting callers compute dayOfYear/weekOfYear/etc. without going\n// through format() means they can build their own derived values\n// without committing to a string format.\n//\n// Calendar-sensitivity: the helpers in this module assume the\n// iso8601 (Gregorian) calendar — that's what TemporalLike fields\n// carry for the overwhelming majority of callers. Non-Gregorian\n// calendars (hebrew, islamic, etc.) need their own helpers; this\n// module doesn't try to be calendar-polymorphic the way Temporal\n// itself is. Documented limitation, not a design choice — see\n// VERIFICATION.md for the rationale.\n\nimport { isGregorianLeapYear, dayOfYear, isoWeekYearAndWeek } from './isoWeek.js';\n\n// A subset of TemporalLike that has the date fields these helpers need,\n// plus optional time fields. PlainTime isn't a DateFieldView (no\n// year/month/day), but PlainDateTime / ZonedDateTime / PlainDate all\n// match. Time fields are optional so callers can pass a PlainDate\n// to startOf(value, 'month') without having to populate hour/minute/etc.\n// Exported so the comparison/arithmetic modules can use the same\n// narrowing.\nexport interface DateFieldView {\n year?: number;\n month?: number;\n day?: number;\n hour?: number;\n minute?: number;\n second?: number;\n millisecond?: number;\n dayOfWeek?: number;\n calendarId?: string;\n}\n\nfunction requireFields(view: DateFieldView, fields: Array<keyof DateFieldView>): void {\n for (const f of fields) {\n if (typeof view[f] !== 'number') {\n throw new Error(\n `temporal-fmt: calendar helper requires \"${String(f)}\", which this value doesn't have. ` +\n `Pass a Temporal.PlainDate / PlainDateTime / ZonedDateTime.`\n );\n }\n }\n}\n\nexport function daysInMonth(view: DateFieldView): number {\n requireFields(view, ['year', 'month']);\n const { year, month } = view;\n // Standard Gregorian month lengths. February's length depends on\n // whether `year` is a leap year — the same isGregorianLeapYear check\n // isoWeek.ts uses for dayOfYear arithmetic.\n const LENGTHS = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];\n if (month === 2 && isGregorianLeapYear(year!)) return 29;\n return LENGTHS[(month! - 1)!]!;\n}\n\nexport function daysInYear(view: DateFieldView): 365 | 366 {\n requireFields(view, ['year']);\n return isGregorianLeapYear(view.year!) ? 366 : 365;\n}\n\nexport function monthsInYear(_view: DateFieldView): 12 {\n // Gregorian always has 12 months. Other calendars (Hebrew leap years\n // have 13) need calendar-aware logic this module doesn't carry — see\n // the file-level comment. The `_view` parameter is kept so the\n // signature mirrors the other helpers and a future calendar-aware\n // implementation can use it without changing call sites.\n return 12;\n}\n\nexport function isLeapYear(view: DateFieldView): boolean {\n requireFields(view, ['year']);\n return isGregorianLeapYear(view.year!);\n}\n\n// `isLeapMonth` would require knowing which month of a leap-year-aware\n// calendar is the leap month — Gregorian doesn't have one, so this\n// returns false unconditionally. Kept here so the public surface\n// matches the module's listing; non-Gregorian calendars need\n// a different implementation.\nexport function isLeapMonth(_view: DateFieldView): boolean {\n return false;\n}\n\nexport function dayOfYearHelper(view: DateFieldView): number {\n requireFields(view, ['year', 'month', 'day']);\n return dayOfYear(view.year!, view.month!, view.day!);\n}\n\n// ISO 8601 week and week-year. Delegates to isoWeek.ts's\n// isoWeekYearAndWeek, which does the full Thursday-of-week\n// computation to handle the year-boundary cases (Dec 29-31 belonging\n// to week 1 of next year, Jan 1-3 belonging to week 52/53 of the\n// previous year).\nexport function weekOfYear(view: DateFieldView): number {\n requireFields(view, ['year', 'month', 'day', 'dayOfWeek']);\n return isoWeekYearAndWeek(view.year!, view.month!, view.day!, view.dayOfWeek!).week;\n}\n\nexport function weekYear(view: DateFieldView): number {\n requireFields(view, ['year', 'month', 'day', 'dayOfWeek']);\n return isoWeekYearAndWeek(view.year!, view.month!, view.day!, view.dayOfWeek!).isoYear;\n}\n\n/**\n * Fiscal-quarter options. `startMonth` is the calendar month (1-12) the\n * fiscal year begins on — e.g. `7` for a fiscal year starting in July.\n * Omitted or `1` gives the calendar-quarter behavior getQuarter() has\n * always had (Jan-Mar = Q1, etc.), so existing callers passing nothing\n * see no change.\n */\nexport interface QuarterOptions {\n startMonth?: number;\n}\n\nfunction validateStartMonth(startMonth: number): void {\n if (!Number.isInteger(startMonth) || startMonth < 1 || startMonth > 12) {\n throw new Error(\n `temporal-fmt: getQuarter's startMonth must be an integer from 1 to 12 (got ${startMonth}).`\n );\n }\n}\n\nexport function getQuarter(view: DateFieldView, options: QuarterOptions = {}): number {\n requireFields(view, ['month']);\n const startMonth = options.startMonth ?? 1;\n validateStartMonth(startMonth);\n if (startMonth === 1) {\n // Mirrors the Q token: months 1-3 → Q1, 4-6 → Q2, 7-9 → Q3, 10-12 → Q4.\n return Math.ceil(view.month! / 3);\n }\n // Fiscal case: shift the month so startMonth becomes month 1 of the\n // fiscal year (mod 12, 1-indexed), then apply the same ceil(/3) rule.\n // E.g. startMonth=7 (fiscal year starts July): July→1, Aug→2, ...,\n // Dec→6, Jan→7, ..., June→12. Then Q1 = fiscal months 1-3 (Jul-Sep),\n // matching the common \"FY starts in July\" convention where Q1 is the\n // first quarter of the fiscal year, not a quarter numbered by which\n // calendar quarter it falls in.\n const shifted = ((view.month! - startMonth + 12) % 12) + 1;\n return Math.ceil(shifted / 3);\n}\n\n// `getMonth` / `getWeekday` look trivial (just read the field) but\n// they're kept as real functions for API surface consistency with the\n// rest of this module. They also normalize: getWeekday returns 1-7\n// (Mon-Sun, matching Temporal's spec) regardless of what numbering the\n// caller's underlying value uses.\nexport function getMonth(view: DateFieldView): number {\n requireFields(view, ['month']);\n return view.month!;\n}\n\nexport function getWeekday(view: DateFieldView): number {\n requireFields(view, ['dayOfWeek']);\n return view.dayOfWeek!;\n}\n\n// startOf / endOf return new field bags (not Temporal objects — this\n// module is polyfill-free) with the relevant fields zeroed/extended.\n// Callers can pass the result to a Temporal constructor if they want\n// a typed value.\nexport type StartOfUnit = 'day' | 'month' | 'year' | 'hour' | 'minute' | 'second';\n\n// Returns true if the given unit (when used with startOf/endOf) should\n// also touch the time fields. 'day', 'month', 'year' all imply a\n// resolution coarser than an hour, so startOf zeroes the time fields\n// and endOf maxes them. Sub-hour units (hour/minute/second) only touch\n// the fields finer than themselves.\nfunction touchesTime(unit: StartOfUnit): boolean {\n return unit === 'day' || unit === 'month' || unit === 'year';\n}\n\n// startOf/endOf reassign year/month/day, which invalidates any\n// dayOfWeek carried over from the input — a plain { ...view } spread\n// leaves the old value sitting there unchanged. Same failure mode\n// businessCalendar.ts's isBusinessDay() works around for add(); we\n// recompute here rather than trust the copied field.\nfunction recomputeDayOfWeek(view: DateFieldView): void {\n if (typeof view.dayOfWeek !== 'number') return;\n /* c8 ignore start @preserve -- unreachable: startOf()/endOf() both call\n * asDateFieldView() before this, which already throws if year/month/day\n * aren't all numbers — so by the time a value with a numeric dayOfWeek\n * reaches here, year/month/day are guaranteed present too. */\n if (typeof view.year !== 'number' || typeof view.month !== 'number' || typeof view.day !== 'number') return;\n /* c8 ignore stop @preserve */\n const jsDow = new Date(Date.UTC(view.year, view.month - 1, view.day)).getUTCDay(); // 0=Sun..6=Sat\n view.dayOfWeek = jsDow === 0 ? 7 : jsDow; // 1=Mon..7=Sun\n}\n\nexport function startOf(value: unknown, unit: StartOfUnit): DateFieldView {\n const view = asDateFieldView(value);\n const result: DateFieldView = { ...view };\n if (unit === 'year') {\n result.month = 1;\n result.day = 1;\n } else if (unit === 'month') {\n result.day = 1;\n }\n recomputeDayOfWeek(result);\n if (touchesTime(unit)) {\n result.hour = 0;\n result.minute = 0;\n result.second = 0;\n result.millisecond = 0;\n } else if (unit === 'hour') {\n result.minute = 0;\n result.second = 0;\n result.millisecond = 0;\n } else if (unit === 'minute') {\n result.second = 0;\n result.millisecond = 0;\n } else if (unit === 'second') {\n result.millisecond = 0;\n }\n return result;\n}\n\nexport function endOf(value: unknown, unit: StartOfUnit): DateFieldView {\n const view = asDateFieldView(value);\n const result: DateFieldView = { ...view };\n if (unit === 'year') {\n result.month = 12;\n result.day = daysInMonth({ year: result.year!, month: 12 });\n } else if (unit === 'month') {\n result.day = daysInMonth({ year: result.year!, month: result.month! });\n }\n recomputeDayOfWeek(result);\n if (touchesTime(unit)) {\n result.hour = 23;\n result.minute = 59;\n result.second = 59;\n result.millisecond = 999;\n } else if (unit === 'hour') {\n result.minute = 59;\n result.second = 59;\n result.millisecond = 999;\n } else if (unit === 'minute') {\n result.second = 59;\n result.millisecond = 999;\n } else if (unit === 'second') {\n result.millisecond = 999;\n }\n return result;\n}\n\n// Type-narrowing helpers used by the comparison/arithmetic modules.\n// Lets them accept any of the four date-carrying Temporal types without\n// importing Temporal itself.\nexport function asDateFieldView(value: unknown): DateFieldView {\n if (typeof value !== 'object' || value === null) {\n throw new Error(`temporal-fmt: expected a date-carrying Temporal value, got ${String(value)}.`);\n }\n // Temporal instances expose year/month/day/etc. as prototype getters,\n // not own enumerable properties — so `{ ...value }` would lose them.\n // Read them explicitly. Only the fields actually present on this\n // value type end up in the returned view.\n const v = value as Record<string, unknown>;\n const out: DateFieldView = {};\n if (typeof v.year === 'number') out.year = v.year;\n if (typeof v.month === 'number') out.month = v.month;\n if (typeof v.day === 'number') out.day = v.day;\n if (typeof v.hour === 'number') out.hour = v.hour;\n if (typeof v.minute === 'number') out.minute = v.minute;\n if (typeof v.second === 'number') out.second = v.second;\n if (typeof v.millisecond === 'number') out.millisecond = v.millisecond;\n if (typeof v.dayOfWeek === 'number') out.dayOfWeek = v.dayOfWeek;\n if (typeof v.calendarId === 'string') out.calendarId = v.calendarId;\n if (out.year === undefined || out.month === undefined || out.day === undefined) {\n throw new Error(\n `temporal-fmt: value is missing year/month/day fields — pass a Temporal.PlainDate / PlainDateTime / ZonedDateTime.`\n );\n }\n return out;\n}\n\n// Re-export the TemporalType alias so callers can import everything\n// from one place.\nexport type { TemporalType } from './tokenMetadata.js';\n// Re-export TemporalLike for the same reason.\nexport type { TemporalLike } from './tokens.js';","// Date arithmetic helpers. Pure functions returning\n// field bags, same convention as calendarUtils.ts/comparison.ts — no\n// Temporal namespace needed. Callers can pass the result back into a\n// Temporal constructor to get a typed value, or chain operations\n// without committing to a Temporal implementation.\n\nimport { asDateFieldView, daysInMonth, type DateFieldView } from './calendarUtils.js';\n\nexport type AddUnit = 'years' | 'months' | 'weeks' | 'days' | 'hours' | 'minutes' | 'seconds' | 'milliseconds';\n\ninterface DateTimeFieldView extends DateFieldView {\n hour?: number;\n minute?: number;\n second?: number;\n millisecond?: number;\n}\n\nfunction asDateTime(value: unknown): DateTimeFieldView {\n return asDateFieldView(value) as DateTimeFieldView;\n}\n\n// Recomputes dayOfWeek after year/month/day change. Mirrors\n// calendarUtils.ts's recomputeDayOfWeek — same fix, needed here too\n// since add()/subtract() mutate the date fields via a shallow spread\n// that otherwise leaves the old dayOfWeek sitting there, silently wrong.\nfunction recomputeDayOfWeek(view: DateTimeFieldView): void {\n if (typeof view.dayOfWeek !== 'number') return;\n /* c8 ignore start @preserve -- unreachable: every call site (add()'s\n 'years'/'months' cases, shiftDays()) passes a `result` whose\n year/month/day were just explicitly set, and the value originally\n came from asDateTime()/asDateFieldView(), which throws unless\n year/month/day are all present as numbers. So by the time this guard\n runs, all three are guaranteed valid. Kept in case a future caller\n constructs a DateTimeFieldView bypassing that validation. */\n if (typeof view.year !== 'number' || typeof view.month !== 'number' || typeof view.day !== 'number') return;\n /* c8 ignore stop @preserve */\n const jsDow = new Date(Date.UTC(view.year, view.month - 1, view.day)).getUTCDay(); // 0=Sun..6=Sat\n view.dayOfWeek = jsDow === 0 ? 7 : jsDow; // 1=Mon..7=Sun\n}\n\n// Adds the requested amount to the value's specified unit. Returns a\n// new field bag; the input is not mutated. Handles month/year overflow\n// by clamping to the last valid day of the target month (Feb 29 + 1\n// year on a non-leap year → Feb 28) — Temporal's `constrain` overflow\n// mode, which is the closest match to \"do the obvious thing\" callers\n// expect from arithmetic.\nexport function add(value: unknown, amount: number, unit: AddUnit): DateTimeFieldView {\n const v = asDateTime(value);\n let result: DateTimeFieldView = { ...v };\n switch (unit) {\n case 'years': {\n /* c8 ignore start @preserve -- the `?? 0` fallback is unreachable:\n asDateTime()/asDateFieldView() (called at the top of add()) throws\n unless year is present as a number, so result.year is never\n undefined here. Kept as a guard against a future change that\n relaxes that validation. */\n result.year = (result.year ?? 0) + amount;\n /* c8 ignore stop @preserve */\n // Clamp day-of-month to the new month's length.\n const maxDay = daysInMonth({ year: result.year!, month: result.month! });\n if (result.day! > maxDay) result.day = maxDay;\n recomputeDayOfWeek(result);\n break;\n }\n case 'months': {\n // Total months = year*12 + month + amount, then split back.\n /* c8 ignore start @preserve -- both `??` fallbacks are unreachable\n for the same reason as the 'years' case above: asDateFieldView()\n guarantees year and month are present numbers before add() ever\n reaches here. */\n const total = (result.year ?? 0) * 12 + (result.month ?? 1) - 1 + amount;\n /* c8 ignore stop @preserve */\n result.year = Math.floor(total / 12);\n result.month = (total % 12) + 1;\n if (result.month < 1) { result.month += 12; result.year -= 1; }\n // Negative modulo handling: when total < 0, the mod goes negative.\n // Re-normalize.\n /* c8 ignore start @preserve -- unreachable: (total % 12) + 1 can never\n exceed 12 for any integer total in JS (its range is [-10, 12] since\n JS's % can return a negative remainder but never one with\n magnitude >= 12, so adding 1 tops out at 12). Only the < 1 branch\n above is reachable; this was written symmetrically with it but the\n overflow direction it guards against can't occur. Kept rather than\n removed since it costs nothing and documents the intent. */\n if (result.month > 12) { result.month -= 12; result.year += 1; }\n /* c8 ignore stop @preserve */\n const maxDay = daysInMonth({ year: result.year!, month: result.month! });\n if (result.day! > maxDay) result.day = maxDay;\n recomputeDayOfWeek(result);\n break;\n }\n case 'weeks':\n result = shiftDays(result, amount * 7);\n break;\n case 'days':\n result = shiftDays(result, amount);\n break;\n case 'hours':\n result = shiftTime(result, amount * 3_600_000);\n break;\n case 'minutes':\n result = shiftTime(result, amount * 60_000);\n break;\n case 'seconds':\n result = shiftTime(result, amount * 1_000);\n break;\n case 'milliseconds':\n result = shiftTime(result, amount);\n break;\n }\n return result;\n}\n\nfunction shiftDays(v: DateTimeFieldView, days: number): DateTimeFieldView {\n // Convert Y/M/D to a day count, add, convert back. Using the same\n // algorithm as comparison.ts's sameWeek helper — proleptic Gregorian\n // day count via Howard Hinnant's era-based formula.\n const y = v.year!, m = v.month!, d = v.day!;\n const y2 = m <= 2 ? y - 1 : y;\n const era = Math.floor((y2 >= 0 ? y2 : y2 - 399) / 400);\n const yoe = y2 - era * 400;\n const m2 = m > 2 ? m - 3 : m + 9;\n const doy = Math.floor((153 * m2 + 2) / 5) + d - 1;\n const doe = yoe * 365 + Math.floor(yoe / 4) - Math.floor(yoe / 100) + doy;\n const totalDays = era * 146097 + doe - 719468 + days;\n\n // Invert: totalDays → Y/M/D. Same source (Howard Hinnant's days_from_civil).\n const z = totalDays + 719468;\n const era2 = Math.floor((z >= 0 ? z : z - 146096) / 146097);\n const doe2 = z - era2 * 146097;\n const yoe2 = Math.floor((doe2 - Math.floor(doe2 / 1460) + Math.floor(doe2 / 36524) - Math.floor(doe2 / 146096)) / 365);\n const y2out = yoe2 + era2 * 400;\n const doy2 = doe2 - (365 * yoe2 + Math.floor(yoe2 / 4) - Math.floor(yoe2 / 100));\n const mp = Math.floor((5 * doy2 + 2) / 153);\n const d2 = doy2 - Math.floor((153 * mp + 2) / 5) + 1;\n const m2out = mp < 10 ? mp + 3 : mp - 9;\n const yOut = m2out <= 2 ? y2out + 1 : y2out;\n\n const result: DateTimeFieldView = { ...v, year: yOut, month: m2out, day: d2 };\n recomputeDayOfWeek(result);\n return result;\n}\n\nfunction shiftTime(v: DateTimeFieldView, msDelta: number): DateTimeFieldView {\n // Convert all time fields to ms, add, then split back. Day overflow\n // propagates to shiftDays; sub-second precision is preserved (caller\n // asking for hours/minutes/seconds/milliseconds gets ms-resolution\n // arithmetic, which is the limit of these helpers — nanoseconds\n // aren't supported here, only via Temporal.Duration's own add).\n const MS_PER_DAY = 86_400_000;\n const MS_PER_HOUR = 3_600_000;\n const MS_PER_MINUTE = 60_000;\n const MS_PER_SECOND = 1_000;\n\n const totalMs = (v.hour ?? 0) * MS_PER_HOUR\n + (v.minute ?? 0) * MS_PER_MINUTE\n + (v.second ?? 0) * MS_PER_SECOND\n + (v.millisecond ?? 0)\n + msDelta;\n\n // Split into day-overflow + within-day ms.\n const dayOverflow = Math.floor(totalMs / MS_PER_DAY);\n let withinDay = totalMs % MS_PER_DAY;\n if (withinDay < 0) { withinDay += MS_PER_DAY; }\n\n const hour = Math.floor(withinDay / MS_PER_HOUR);\n const minute = Math.floor((withinDay % MS_PER_HOUR) / MS_PER_MINUTE);\n const second = Math.floor((withinDay % MS_PER_MINUTE) / MS_PER_SECOND);\n const millisecond = withinDay % MS_PER_SECOND;\n\n const result: DateTimeFieldView = { ...v, hour, minute, second, millisecond };\n if (dayOverflow !== 0) {\n return shiftDays(result, dayOverflow);\n }\n return result;\n}\n\nexport function subtract(value: unknown, amount: number, unit: AddUnit): DateTimeFieldView {\n return add(value, -amount, unit);\n}\n\n// Per-unit convenience wrappers — matches the grouping of\n// addYears / addMonths / ... / subtractNanoseconds. Nanosecond variants\n// aren't provided here because these helpers operate on field bags, and\n// the millisecond/microsecond/nanosecond split isn't preserved through\n// arithmetic at sub-millisecond precision the way Temporal.Duration's\n// own add preserves it. For ns-precision arithmetic, use Temporal.Duration\n// directly.\nexport const addYears = (v: unknown, n: number) => add(v, n, 'years');\nexport const addMonths = (v: unknown, n: number) => add(v, n, 'months');\nexport const addWeeks = (v: unknown, n: number) => add(v, n, 'weeks');\nexport const addDays = (v: unknown, n: number) => add(v, n, 'days');\nexport const addHours = (v: unknown, n: number) => add(v, n, 'hours');\nexport const addMinutes = (v: unknown, n: number) => add(v, n, 'minutes');\nexport const addSeconds = (v: unknown, n: number) => add(v, n, 'seconds');\nexport const addMilliseconds = (v: unknown, n: number) => add(v, n, 'milliseconds');\n\nexport const subtractYears = (v: unknown, n: number) => subtract(v, n, 'years');\nexport const subtractMonths = (v: unknown, n: number) => subtract(v, n, 'months');\nexport const subtractWeeks = (v: unknown, n: number) => subtract(v, n, 'weeks');\nexport const subtractDays = (v: unknown, n: number) => subtract(v, n, 'days');\nexport const subtractHours = (v: unknown, n: number) => subtract(v, n, 'hours');\nexport const subtractMinutes = (v: unknown, n: number) => subtract(v, n, 'minutes');\nexport const subtractSeconds = (v: unknown, n: number) => subtract(v, n, 'seconds');\nexport const subtractMilliseconds = (v: unknown, n: number) => subtract(v, n, 'milliseconds');\n\n// difference(): returns the count of `unit` boundaries between two values.\n// Pure-integer math, no Temporal.Duration involved. For sub-day\n// precision the result is an integer count of the requested unit (not\n// a Duration field bag) — matches the most common caller expectation\n// (\"how many days between these two dates?\").\nexport type DiffUnit = 'years' | 'months' | 'weeks' | 'days' | 'hours' | 'minutes' | 'seconds' | 'milliseconds';\n\nexport function difference(a: unknown, b: unknown, unit: DiffUnit): number {\n const av = asDateTime(a);\n const bv = asDateTime(b);\n\n // For day-granular units (years/months/weeks/days), compute via\n // calendar arithmetic on the date fields. For sub-day units, compute\n // via total-ms and divide.\n if (unit === 'years') {\n return bv.year! - av.year!;\n }\n if (unit === 'months') {\n return (bv.year! * 12 + bv.month! - 1) - (av.year! * 12 + av.month! - 1);\n }\n if (unit === 'weeks' || unit === 'days') {\n const aDays = toDayCount(av);\n const bDays = toDayCount(bv);\n const days = bDays - aDays;\n return unit === 'weeks' ? Math.trunc(days / 7) : days;\n }\n\n // Sub-day units: total-ms math.\n const MS_PER_HOUR = 3_600_000;\n const MS_PER_MINUTE = 60_000;\n const MS_PER_SECOND = 1_000;\n const aMs = toTotalMs(av);\n const bMs = toTotalMs(bv);\n const diffMs = bMs - aMs;\n switch (unit) {\n case 'hours': return Math.trunc(diffMs / MS_PER_HOUR);\n case 'minutes': return Math.trunc(diffMs / MS_PER_MINUTE);\n case 'seconds': return Math.trunc(diffMs / MS_PER_SECOND);\n case 'milliseconds': return diffMs;\n }\n}\n\nfunction toDayCount(v: DateTimeFieldView): number {\n const y = v.year!, m = v.month!, d = v.day!;\n const y2 = m <= 2 ? y - 1 : y;\n const era = Math.floor((y2 >= 0 ? y2 : y2 - 399) / 400);\n const yoe = y2 - era * 400;\n const m2 = m > 2 ? m - 3 : m + 9;\n const doy = Math.floor((153 * m2 + 2) / 5) + d - 1;\n const doe = yoe * 365 + Math.floor(yoe / 4) - Math.floor(yoe / 100) + doy;\n return era * 146097 + doe - 719468;\n}\n\nfunction toTotalMs(v: DateTimeFieldView): number {\n const MS_PER_DAY = 86_400_000;\n const MS_PER_HOUR = 3_600_000;\n const MS_PER_MINUTE = 60_000;\n const MS_PER_SECOND = 1_000;\n return toDayCount(v) * MS_PER_DAY\n + (v.hour ?? 0) * MS_PER_HOUR\n + (v.minute ?? 0) * MS_PER_MINUTE\n + (v.second ?? 0) * MS_PER_SECOND\n + (v.millisecond ?? 0);\n}\n\n// Per-unit difference wrappers — same convenience pattern as the add*\n// wrappers above.\nexport const differenceInYears = (a: unknown, b: unknown) => difference(a, b, 'years');\nexport const differenceInMonths = (a: unknown, b: unknown) => difference(a, b, 'months');\nexport const differenceInWeeks = (a: unknown, b: unknown) => difference(a, b, 'weeks');\nexport const differenceInDays = (a: unknown, b: unknown) => difference(a, b, 'days');\nexport const differenceInHours = (a: unknown, b: unknown) => difference(a, b, 'hours');\nexport const differenceInMinutes = (a: unknown, b: unknown) => difference(a, b, 'minutes');\nexport const differenceInSeconds = (a: unknown, b: unknown) => difference(a, b, 'seconds');\nexport const differenceInMilliseconds = (a: unknown, b: unknown) => difference(a, b, 'milliseconds');"],"mappings":"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","names":["timezone_exports","__export","getNextTransition","getOffset","getOffsetNanoseconds","getPreviousTransition","getTimeZone","getTransitions","isDST","possibleInstantsFor","resolveZoned","__toCommonJS","injectedTemporal","resolveTemporal","injectedTemporal","getTemporal","temporal","isGregorianLeapYear","year","requireFields","view","fields","f","daysInMonth","year","month","LENGTHS","isGregorianLeapYear","asDateFieldView","value","v","out","asDateTime","value","asDateFieldView","recomputeDayOfWeek","view","jsDow","add","amount","unit","result","maxDay","daysInMonth","total","shiftDays","shiftTime","v","days","y","m","d","y2","era","yoe","m2","doy","doe","z","era2","doe2","yoe2","y2out","doy2","mp","d2","m2out","yOut","msDelta","totalMs","dayOverflow","withinDay","hour","minute","second","millisecond","resolveZoned","fields","timeZone","options","temporal","getTemporal","disambiguation","fromOptions","err","msg","getTimeZone","value","v","getOffset","getOffsetNanoseconds","m","isDST","getNextTransition","findTransition","getPreviousTransition","direction","candidateFields","add","startOffset","cf","candidateZdt","getTransitions","start","end","result","startV","endV","cursorFields","lastOffset","i","cursorZdt","possibleInstantsFor","earlier","later","matchesRequestedWallClock","z"]}
package/dist/timezone.js CHANGED
@@ -1,27 +1,2 @@
1
- import {
2
- getNextTransition,
3
- getOffset,
4
- getOffsetNanoseconds,
5
- getPreviousTransition,
6
- getTimeZone,
7
- getTransitions,
8
- isDST,
9
- possibleInstantsFor,
10
- resolveZoned
11
- } from "./chunk-GRJQHQLW.js";
12
- import "./chunk-MXXYIMFJ.js";
13
- import "./chunk-VHSZL3P3.js";
14
- import "./chunk-4ZBGVYLR.js";
15
- import "./chunk-YS52LOMJ.js";
16
- export {
17
- getNextTransition,
18
- getOffset,
19
- getOffsetNanoseconds,
20
- getPreviousTransition,
21
- getTimeZone,
22
- getTransitions,
23
- isDST,
24
- possibleInstantsFor,
25
- resolveZoned
26
- };
1
+ import{a,b,c,d,e,f,g,h,i}from"./chunk-J2AQNXF2.js";import"./chunk-3MZLTVP3.js";import"./chunk-VQXUMFB2.js";import"./chunk-EHLRZULM.js";import"./chunk-C6ZZ62ET.js";export{f as getNextTransition,c as getOffset,d as getOffsetNanoseconds,g as getPreviousTransition,b as getTimeZone,h as getTransitions,e as isDST,i as possibleInstantsFor,a as resolveZoned};
27
2
  //# sourceMappingURL=timezone.js.map
@@ -28,15 +28,15 @@ interface TemporalInstance {
28
28
  timeZoneId?: string;
29
29
  monthCode?: string;
30
30
  }
31
- export declare function isPlainDate(value: unknown): value is TemporalInstance;
32
- export declare function isPlainTime(value: unknown): value is TemporalInstance;
33
- export declare function isPlainDateTime(value: unknown): value is TemporalInstance;
34
- export declare function isZonedDateTime(value: unknown): value is TemporalInstance;
35
- export declare function isInstant(value: unknown): value is TemporalInstance;
36
- export declare function isPlainYearMonth(value: unknown): value is TemporalInstance;
37
- export declare function isPlainMonthDay(value: unknown): value is TemporalInstance;
38
- export declare function isDuration(value: unknown): value is Record<string, unknown>;
39
- export declare function isTemporal(value: unknown): value is TemporalInstance;
31
+ export declare const isPlainDate: (value: unknown) => value is TemporalInstance;
32
+ export declare const isPlainTime: (value: unknown) => value is TemporalInstance;
33
+ export declare const isPlainDateTime: (value: unknown) => value is TemporalInstance;
34
+ export declare const isZonedDateTime: (value: unknown) => value is TemporalInstance;
35
+ export declare const isInstant: (value: unknown) => value is TemporalInstance;
36
+ export declare const isPlainYearMonth: (value: unknown) => value is TemporalInstance;
37
+ export declare const isPlainMonthDay: (value: unknown) => value is TemporalInstance;
38
+ export declare const isDuration: (value: unknown) => value is Record<string, unknown>;
39
+ export declare const isTemporal: (value: unknown) => value is TemporalInstance;
40
40
  export declare function assertTemporal(value: unknown): asserts value is TemporalInstance;
41
41
  export declare function assertInstant(value: unknown): asserts value is TemporalInstance;
42
42
  export declare function assertPlainDate(value: unknown): asserts value is TemporalInstance;
@@ -28,15 +28,15 @@ interface TemporalInstance {
28
28
  timeZoneId?: string;
29
29
  monthCode?: string;
30
30
  }
31
- export declare function isPlainDate(value: unknown): value is TemporalInstance;
32
- export declare function isPlainTime(value: unknown): value is TemporalInstance;
33
- export declare function isPlainDateTime(value: unknown): value is TemporalInstance;
34
- export declare function isZonedDateTime(value: unknown): value is TemporalInstance;
35
- export declare function isInstant(value: unknown): value is TemporalInstance;
36
- export declare function isPlainYearMonth(value: unknown): value is TemporalInstance;
37
- export declare function isPlainMonthDay(value: unknown): value is TemporalInstance;
38
- export declare function isDuration(value: unknown): value is Record<string, unknown>;
39
- export declare function isTemporal(value: unknown): value is TemporalInstance;
31
+ export declare const isPlainDate: (value: unknown) => value is TemporalInstance;
32
+ export declare const isPlainTime: (value: unknown) => value is TemporalInstance;
33
+ export declare const isPlainDateTime: (value: unknown) => value is TemporalInstance;
34
+ export declare const isZonedDateTime: (value: unknown) => value is TemporalInstance;
35
+ export declare const isInstant: (value: unknown) => value is TemporalInstance;
36
+ export declare const isPlainYearMonth: (value: unknown) => value is TemporalInstance;
37
+ export declare const isPlainMonthDay: (value: unknown) => value is TemporalInstance;
38
+ export declare const isDuration: (value: unknown) => value is Record<string, unknown>;
39
+ export declare const isTemporal: (value: unknown) => value is TemporalInstance;
40
40
  export declare function assertTemporal(value: unknown): asserts value is TemporalInstance;
41
41
  export declare function assertInstant(value: unknown): asserts value is TemporalInstance;
42
42
  export declare function assertPlainDate(value: unknown): asserts value is TemporalInstance;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "temporal-fmt",
3
- "version": "0.9.0",
3
+ "version": "0.9.2",
4
4
  "description": "Format Temporal.PlainDate/PlainDateTime/PlainTime/ZonedDateTime objects using date-fns-style token strings.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -136,6 +136,7 @@
136
136
  "sideEffects": false,
137
137
  "scripts": {
138
138
  "build": "tsup && tsc --declaration --emitDeclarationOnly && node scripts/emit-cjs-types.mjs && node scripts/emit-node10-shims.mjs",
139
+ "build:publish": "cross-env TSUP_MINIFY=true npm run build",
139
140
  "dev": "tsup --watch",
140
141
  "test": "node scripts/run-tests.mjs",
141
142
  "test:unit": "vitest run",
@@ -146,7 +147,7 @@
146
147
  "test:smoke": "node smoke-test/run.mjs",
147
148
  "test:all": "npm run build && npm test && npm run test:coverage && npm run test:unit && npm run test:types && npm run test:pack && npm run test:smoke",
148
149
  "cli": "node scripts/cli.mjs",
149
- "prepublishOnly": "npm run build && npm test"
150
+ "prepublishOnly": "npm run build:publish && npm test"
150
151
  },
151
152
  "keywords": [
152
153
  "temporal",
@@ -171,6 +172,7 @@
171
172
  "devDependencies": {
172
173
  "@arethetypeswrong/cli": "^0.18.5",
173
174
  "c8": "^12.0.0",
175
+ "cross-env": "^10.1.0",
174
176
  "publint": "^0.3.24",
175
177
  "tsup": "^8.5.1",
176
178
  "typescript": "^7.0.2",
@@ -1,182 +0,0 @@
1
- import {
2
- dayOfYear,
3
- isGregorianLeapYear,
4
- isoWeekYearAndWeek
5
- } from "./chunk-YS52LOMJ.js";
6
-
7
- // src/calendarUtils.ts
8
- function requireFields(view, fields) {
9
- for (const f of fields) {
10
- if (typeof view[f] !== "number") {
11
- throw new Error(
12
- `temporal-fmt: calendar helper requires "${String(f)}", which this value doesn't have. Pass a Temporal.PlainDate / PlainDateTime / ZonedDateTime.`
13
- );
14
- }
15
- }
16
- }
17
- function daysInMonth(view) {
18
- requireFields(view, ["year", "month"]);
19
- const { year, month } = view;
20
- const LENGTHS = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
21
- if (month === 2 && isGregorianLeapYear(year)) return 29;
22
- return LENGTHS[month - 1];
23
- }
24
- function daysInYear(view) {
25
- requireFields(view, ["year"]);
26
- return isGregorianLeapYear(view.year) ? 366 : 365;
27
- }
28
- function monthsInYear(_view) {
29
- return 12;
30
- }
31
- function isLeapYear(view) {
32
- requireFields(view, ["year"]);
33
- return isGregorianLeapYear(view.year);
34
- }
35
- function isLeapMonth(_view) {
36
- return false;
37
- }
38
- function dayOfYearHelper(view) {
39
- requireFields(view, ["year", "month", "day"]);
40
- return dayOfYear(view.year, view.month, view.day);
41
- }
42
- function weekOfYear(view) {
43
- requireFields(view, ["year", "month", "day", "dayOfWeek"]);
44
- return isoWeekYearAndWeek(view.year, view.month, view.day, view.dayOfWeek).week;
45
- }
46
- function weekYear(view) {
47
- requireFields(view, ["year", "month", "day", "dayOfWeek"]);
48
- return isoWeekYearAndWeek(view.year, view.month, view.day, view.dayOfWeek).isoYear;
49
- }
50
- function validateStartMonth(startMonth) {
51
- if (!Number.isInteger(startMonth) || startMonth < 1 || startMonth > 12) {
52
- throw new Error(
53
- `temporal-fmt: getQuarter's startMonth must be an integer from 1 to 12 (got ${startMonth}).`
54
- );
55
- }
56
- }
57
- function getQuarter(view, options = {}) {
58
- requireFields(view, ["month"]);
59
- const startMonth = options.startMonth ?? 1;
60
- validateStartMonth(startMonth);
61
- if (startMonth === 1) {
62
- return Math.ceil(view.month / 3);
63
- }
64
- const shifted = (view.month - startMonth + 12) % 12 + 1;
65
- return Math.ceil(shifted / 3);
66
- }
67
- function getMonth(view) {
68
- requireFields(view, ["month"]);
69
- return view.month;
70
- }
71
- function getWeekday(view) {
72
- requireFields(view, ["dayOfWeek"]);
73
- return view.dayOfWeek;
74
- }
75
- function touchesTime(unit) {
76
- return unit === "day" || unit === "month" || unit === "year";
77
- }
78
- function recomputeDayOfWeek(view) {
79
- if (typeof view.dayOfWeek !== "number") return;
80
- /* c8 ignore start @preserve -- unreachable: startOf()/endOf() both call
81
- * asDateFieldView() before this, which already throws if year/month/day
82
- * aren't all numbers — so by the time a value with a numeric dayOfWeek
83
- * reaches here, year/month/day are guaranteed present too. */
84
- if (typeof view.year !== "number" || typeof view.month !== "number" || typeof view.day !== "number") return;
85
- /* c8 ignore stop @preserve */
86
- const jsDow = new Date(Date.UTC(view.year, view.month - 1, view.day)).getUTCDay();
87
- view.dayOfWeek = jsDow === 0 ? 7 : jsDow;
88
- }
89
- function startOf(value, unit) {
90
- const view = asDateFieldView(value);
91
- const result = { ...view };
92
- if (unit === "year") {
93
- result.month = 1;
94
- result.day = 1;
95
- } else if (unit === "month") {
96
- result.day = 1;
97
- }
98
- recomputeDayOfWeek(result);
99
- if (touchesTime(unit)) {
100
- result.hour = 0;
101
- result.minute = 0;
102
- result.second = 0;
103
- result.millisecond = 0;
104
- } else if (unit === "hour") {
105
- result.minute = 0;
106
- result.second = 0;
107
- result.millisecond = 0;
108
- } else if (unit === "minute") {
109
- result.second = 0;
110
- result.millisecond = 0;
111
- } else if (unit === "second") {
112
- result.millisecond = 0;
113
- }
114
- return result;
115
- }
116
- function endOf(value, unit) {
117
- const view = asDateFieldView(value);
118
- const result = { ...view };
119
- if (unit === "year") {
120
- result.month = 12;
121
- result.day = daysInMonth({ year: result.year, month: 12 });
122
- } else if (unit === "month") {
123
- result.day = daysInMonth({ year: result.year, month: result.month });
124
- }
125
- recomputeDayOfWeek(result);
126
- if (touchesTime(unit)) {
127
- result.hour = 23;
128
- result.minute = 59;
129
- result.second = 59;
130
- result.millisecond = 999;
131
- } else if (unit === "hour") {
132
- result.minute = 59;
133
- result.second = 59;
134
- result.millisecond = 999;
135
- } else if (unit === "minute") {
136
- result.second = 59;
137
- result.millisecond = 999;
138
- } else if (unit === "second") {
139
- result.millisecond = 999;
140
- }
141
- return result;
142
- }
143
- function asDateFieldView(value) {
144
- if (typeof value !== "object" || value === null) {
145
- throw new Error(`temporal-fmt: expected a date-carrying Temporal value, got ${String(value)}.`);
146
- }
147
- const v = value;
148
- const out = {};
149
- if (typeof v.year === "number") out.year = v.year;
150
- if (typeof v.month === "number") out.month = v.month;
151
- if (typeof v.day === "number") out.day = v.day;
152
- if (typeof v.hour === "number") out.hour = v.hour;
153
- if (typeof v.minute === "number") out.minute = v.minute;
154
- if (typeof v.second === "number") out.second = v.second;
155
- if (typeof v.millisecond === "number") out.millisecond = v.millisecond;
156
- if (typeof v.dayOfWeek === "number") out.dayOfWeek = v.dayOfWeek;
157
- if (typeof v.calendarId === "string") out.calendarId = v.calendarId;
158
- if (out.year === void 0 || out.month === void 0 || out.day === void 0) {
159
- throw new Error(
160
- `temporal-fmt: value is missing year/month/day fields \u2014 pass a Temporal.PlainDate / PlainDateTime / ZonedDateTime.`
161
- );
162
- }
163
- return out;
164
- }
165
-
166
- export {
167
- daysInMonth,
168
- daysInYear,
169
- monthsInYear,
170
- isLeapYear,
171
- isLeapMonth,
172
- dayOfYearHelper,
173
- weekOfYear,
174
- weekYear,
175
- getQuarter,
176
- getMonth,
177
- getWeekday,
178
- startOf,
179
- endOf,
180
- asDateFieldView
181
- };
182
- //# sourceMappingURL=chunk-4ZBGVYLR.js.map