@venizia/ignis-helpers 0.2.2-1 → 0.2.2-3

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 (195) hide show
  1. package/dist/cjs/modules/temporal/abstract.d.ts +295 -0
  2. package/dist/cjs/modules/temporal/abstract.d.ts.map +1 -0
  3. package/dist/cjs/modules/temporal/abstract.js +330 -0
  4. package/dist/cjs/modules/temporal/abstract.js.map +1 -0
  5. package/dist/cjs/modules/temporal/adapters/dayjs.d.ts +1 -1
  6. package/dist/cjs/modules/temporal/adapters/dayjs.d.ts.map +1 -1
  7. package/dist/cjs/modules/temporal/adapters/dayjs.js +3 -3
  8. package/dist/cjs/modules/temporal/adapters/dayjs.js.map +1 -1
  9. package/dist/cjs/modules/temporal/adapters/intl.d.ts +1 -1
  10. package/dist/cjs/modules/temporal/adapters/intl.d.ts.map +1 -1
  11. package/dist/cjs/modules/temporal/adapters/intl.js +7 -7
  12. package/dist/cjs/modules/temporal/adapters/intl.js.map +1 -1
  13. package/dist/cjs/modules/temporal/adapters/luxon.d.ts +1 -1
  14. package/dist/cjs/modules/temporal/adapters/luxon.d.ts.map +1 -1
  15. package/dist/cjs/modules/temporal/adapters/luxon.js +3 -3
  16. package/dist/cjs/modules/temporal/adapters/luxon.js.map +1 -1
  17. package/dist/cjs/modules/temporal/adapters/native.d.ts +3 -1
  18. package/dist/cjs/modules/temporal/adapters/native.d.ts.map +1 -1
  19. package/dist/cjs/modules/temporal/adapters/native.js +13 -5
  20. package/dist/cjs/modules/temporal/adapters/native.js.map +1 -1
  21. package/dist/cjs/modules/temporal/calendar/calendar.d.ts +56 -0
  22. package/dist/cjs/modules/temporal/calendar/calendar.d.ts.map +1 -0
  23. package/dist/cjs/modules/temporal/calendar/calendar.js +166 -0
  24. package/dist/cjs/modules/temporal/calendar/calendar.js.map +1 -0
  25. package/dist/cjs/modules/temporal/calendar/index.d.ts +2 -0
  26. package/dist/cjs/modules/temporal/calendar/index.d.ts.map +1 -0
  27. package/dist/cjs/modules/temporal/calendar/index.js +18 -0
  28. package/dist/cjs/modules/temporal/calendar/index.js.map +1 -0
  29. package/dist/cjs/modules/temporal/common/constants.d.ts +14 -3
  30. package/dist/cjs/modules/temporal/common/constants.d.ts.map +1 -1
  31. package/dist/cjs/modules/temporal/common/constants.js +23 -4
  32. package/dist/cjs/modules/temporal/common/constants.js.map +1 -1
  33. package/dist/cjs/modules/temporal/common/types.d.ts +258 -5
  34. package/dist/cjs/modules/temporal/common/types.d.ts.map +1 -1
  35. package/dist/cjs/modules/temporal/{duration.d.ts → duration/duration.d.ts} +9 -2
  36. package/dist/cjs/modules/temporal/duration/duration.d.ts.map +1 -0
  37. package/dist/cjs/modules/temporal/duration/duration.js +135 -0
  38. package/dist/cjs/modules/temporal/duration/duration.js.map +1 -0
  39. package/dist/cjs/modules/temporal/duration/index.d.ts +2 -0
  40. package/dist/cjs/modules/temporal/duration/index.d.ts.map +1 -0
  41. package/dist/cjs/modules/temporal/duration/index.js +18 -0
  42. package/dist/cjs/modules/temporal/duration/index.js.map +1 -0
  43. package/dist/cjs/modules/temporal/helper.d.ts +105 -77
  44. package/dist/cjs/modules/temporal/helper.d.ts.map +1 -1
  45. package/dist/cjs/modules/temporal/helper.js +209 -258
  46. package/dist/cjs/modules/temporal/helper.js.map +1 -1
  47. package/dist/cjs/modules/temporal/index.d.ts +1 -0
  48. package/dist/cjs/modules/temporal/index.d.ts.map +1 -1
  49. package/dist/cjs/modules/temporal/index.js +1 -0
  50. package/dist/cjs/modules/temporal/index.js.map +1 -1
  51. package/dist/cjs/modules/temporal/locale/index.d.ts +2 -0
  52. package/dist/cjs/modules/temporal/locale/index.d.ts.map +1 -0
  53. package/dist/cjs/modules/temporal/locale/index.js +18 -0
  54. package/dist/cjs/modules/temporal/locale/index.js.map +1 -0
  55. package/dist/{esm/modules/temporal → cjs/modules/temporal/locale}/locale.d.ts +3 -2
  56. package/dist/cjs/modules/temporal/locale/locale.d.ts.map +1 -0
  57. package/dist/cjs/modules/temporal/{locale.js → locale/locale.js} +3 -3
  58. package/dist/cjs/modules/temporal/locale/locale.js.map +1 -0
  59. package/dist/cjs/modules/temporal/pattern/common/index.d.ts +2 -0
  60. package/dist/cjs/modules/temporal/pattern/common/index.d.ts.map +1 -0
  61. package/dist/cjs/modules/temporal/pattern/common/index.js +18 -0
  62. package/dist/cjs/modules/temporal/pattern/common/index.js.map +1 -0
  63. package/dist/cjs/modules/temporal/pattern/common/types.d.ts +26 -0
  64. package/dist/cjs/modules/temporal/pattern/common/types.d.ts.map +1 -0
  65. package/dist/cjs/modules/temporal/pattern/common/types.js +3 -0
  66. package/dist/cjs/modules/temporal/pattern/common/types.js.map +1 -0
  67. package/dist/cjs/modules/temporal/pattern/index.d.ts +4 -0
  68. package/dist/cjs/modules/temporal/pattern/index.d.ts.map +1 -0
  69. package/dist/cjs/modules/temporal/pattern/index.js +20 -0
  70. package/dist/cjs/modules/temporal/pattern/index.js.map +1 -0
  71. package/dist/{esm/modules/temporal → cjs/modules/temporal/pattern}/pattern.d.ts +2 -1
  72. package/dist/cjs/modules/temporal/pattern/pattern.d.ts.map +1 -0
  73. package/dist/cjs/modules/temporal/{pattern.js → pattern/pattern.js} +19 -14
  74. package/dist/cjs/modules/temporal/pattern/pattern.js.map +1 -0
  75. package/dist/cjs/modules/temporal/pattern/tokens.d.ts +59 -0
  76. package/dist/cjs/modules/temporal/pattern/tokens.d.ts.map +1 -0
  77. package/dist/cjs/modules/temporal/pattern/tokens.js +195 -0
  78. package/dist/cjs/modules/temporal/pattern/tokens.js.map +1 -0
  79. package/dist/esm/modules/temporal/abstract.d.ts +295 -0
  80. package/dist/esm/modules/temporal/abstract.d.ts.map +1 -0
  81. package/dist/esm/modules/temporal/abstract.js +326 -0
  82. package/dist/esm/modules/temporal/abstract.js.map +1 -0
  83. package/dist/esm/modules/temporal/adapters/dayjs.d.ts +1 -1
  84. package/dist/esm/modules/temporal/adapters/dayjs.d.ts.map +1 -1
  85. package/dist/esm/modules/temporal/adapters/dayjs.js +3 -3
  86. package/dist/esm/modules/temporal/adapters/dayjs.js.map +1 -1
  87. package/dist/esm/modules/temporal/adapters/intl.d.ts +1 -1
  88. package/dist/esm/modules/temporal/adapters/intl.d.ts.map +1 -1
  89. package/dist/esm/modules/temporal/adapters/intl.js +7 -7
  90. package/dist/esm/modules/temporal/adapters/intl.js.map +1 -1
  91. package/dist/esm/modules/temporal/adapters/luxon.d.ts +1 -1
  92. package/dist/esm/modules/temporal/adapters/luxon.d.ts.map +1 -1
  93. package/dist/esm/modules/temporal/adapters/luxon.js +3 -3
  94. package/dist/esm/modules/temporal/adapters/luxon.js.map +1 -1
  95. package/dist/esm/modules/temporal/adapters/native.d.ts +3 -1
  96. package/dist/esm/modules/temporal/adapters/native.d.ts.map +1 -1
  97. package/dist/esm/modules/temporal/adapters/native.js +13 -5
  98. package/dist/esm/modules/temporal/adapters/native.js.map +1 -1
  99. package/dist/esm/modules/temporal/calendar/calendar.d.ts +56 -0
  100. package/dist/esm/modules/temporal/calendar/calendar.d.ts.map +1 -0
  101. package/dist/esm/modules/temporal/calendar/calendar.js +162 -0
  102. package/dist/esm/modules/temporal/calendar/calendar.js.map +1 -0
  103. package/dist/esm/modules/temporal/calendar/index.d.ts +2 -0
  104. package/dist/esm/modules/temporal/calendar/index.d.ts.map +1 -0
  105. package/dist/esm/modules/temporal/calendar/index.js +2 -0
  106. package/dist/esm/modules/temporal/calendar/index.js.map +1 -0
  107. package/dist/esm/modules/temporal/common/constants.d.ts +14 -3
  108. package/dist/esm/modules/temporal/common/constants.d.ts.map +1 -1
  109. package/dist/esm/modules/temporal/common/constants.js +21 -3
  110. package/dist/esm/modules/temporal/common/constants.js.map +1 -1
  111. package/dist/esm/modules/temporal/common/types.d.ts +258 -5
  112. package/dist/esm/modules/temporal/common/types.d.ts.map +1 -1
  113. package/dist/esm/modules/temporal/{duration.d.ts → duration/duration.d.ts} +9 -2
  114. package/dist/esm/modules/temporal/duration/duration.d.ts.map +1 -0
  115. package/dist/esm/modules/temporal/duration/duration.js +131 -0
  116. package/dist/esm/modules/temporal/duration/duration.js.map +1 -0
  117. package/dist/esm/modules/temporal/duration/index.d.ts +2 -0
  118. package/dist/esm/modules/temporal/duration/index.d.ts.map +1 -0
  119. package/dist/esm/modules/temporal/duration/index.js +2 -0
  120. package/dist/esm/modules/temporal/duration/index.js.map +1 -0
  121. package/dist/esm/modules/temporal/helper.d.ts +105 -77
  122. package/dist/esm/modules/temporal/helper.d.ts.map +1 -1
  123. package/dist/esm/modules/temporal/helper.js +214 -263
  124. package/dist/esm/modules/temporal/helper.js.map +1 -1
  125. package/dist/esm/modules/temporal/index.d.ts +1 -0
  126. package/dist/esm/modules/temporal/index.d.ts.map +1 -1
  127. package/dist/esm/modules/temporal/index.js +1 -0
  128. package/dist/esm/modules/temporal/index.js.map +1 -1
  129. package/dist/esm/modules/temporal/locale/index.d.ts +2 -0
  130. package/dist/esm/modules/temporal/locale/index.d.ts.map +1 -0
  131. package/dist/esm/modules/temporal/locale/index.js +2 -0
  132. package/dist/esm/modules/temporal/locale/index.js.map +1 -0
  133. package/dist/{cjs/modules/temporal → esm/modules/temporal/locale}/locale.d.ts +3 -2
  134. package/dist/esm/modules/temporal/locale/locale.d.ts.map +1 -0
  135. package/dist/esm/modules/temporal/{locale.js → locale/locale.js} +3 -3
  136. package/dist/esm/modules/temporal/locale/locale.js.map +1 -0
  137. package/dist/esm/modules/temporal/pattern/common/index.d.ts +2 -0
  138. package/dist/esm/modules/temporal/pattern/common/index.d.ts.map +1 -0
  139. package/dist/esm/modules/temporal/pattern/common/index.js +2 -0
  140. package/dist/esm/modules/temporal/pattern/common/index.js.map +1 -0
  141. package/dist/esm/modules/temporal/pattern/common/types.d.ts +26 -0
  142. package/dist/esm/modules/temporal/pattern/common/types.d.ts.map +1 -0
  143. package/dist/esm/modules/temporal/pattern/common/types.js +2 -0
  144. package/dist/esm/modules/temporal/pattern/common/types.js.map +1 -0
  145. package/dist/esm/modules/temporal/pattern/index.d.ts +4 -0
  146. package/dist/esm/modules/temporal/pattern/index.d.ts.map +1 -0
  147. package/dist/esm/modules/temporal/pattern/index.js +4 -0
  148. package/dist/esm/modules/temporal/pattern/index.js.map +1 -0
  149. package/dist/{cjs/modules/temporal → esm/modules/temporal/pattern}/pattern.d.ts +2 -1
  150. package/dist/esm/modules/temporal/pattern/pattern.d.ts.map +1 -0
  151. package/dist/esm/modules/temporal/{pattern.js → pattern/pattern.js} +20 -15
  152. package/dist/esm/modules/temporal/pattern/pattern.js.map +1 -0
  153. package/dist/esm/modules/temporal/pattern/tokens.d.ts +59 -0
  154. package/dist/esm/modules/temporal/pattern/tokens.d.ts.map +1 -0
  155. package/dist/esm/modules/temporal/pattern/tokens.js +191 -0
  156. package/dist/esm/modules/temporal/pattern/tokens.js.map +1 -0
  157. package/package.json +2 -2
  158. package/dist/cjs/modules/temporal/adapters/guards.d.ts +0 -4
  159. package/dist/cjs/modules/temporal/adapters/guards.d.ts.map +0 -1
  160. package/dist/cjs/modules/temporal/adapters/guards.js +0 -14
  161. package/dist/cjs/modules/temporal/adapters/guards.js.map +0 -1
  162. package/dist/cjs/modules/temporal/calendar.d.ts +0 -52
  163. package/dist/cjs/modules/temporal/calendar.d.ts.map +0 -1
  164. package/dist/cjs/modules/temporal/calendar.js +0 -151
  165. package/dist/cjs/modules/temporal/calendar.js.map +0 -1
  166. package/dist/cjs/modules/temporal/duration.d.ts.map +0 -1
  167. package/dist/cjs/modules/temporal/duration.js +0 -64
  168. package/dist/cjs/modules/temporal/duration.js.map +0 -1
  169. package/dist/cjs/modules/temporal/locale.d.ts.map +0 -1
  170. package/dist/cjs/modules/temporal/locale.js.map +0 -1
  171. package/dist/cjs/modules/temporal/pattern.d.ts.map +0 -1
  172. package/dist/cjs/modules/temporal/pattern.js.map +0 -1
  173. package/dist/cjs/modules/temporal/tokens.d.ts +0 -78
  174. package/dist/cjs/modules/temporal/tokens.d.ts.map +0 -1
  175. package/dist/cjs/modules/temporal/tokens.js +0 -145
  176. package/dist/cjs/modules/temporal/tokens.js.map +0 -1
  177. package/dist/esm/modules/temporal/adapters/guards.d.ts +0 -4
  178. package/dist/esm/modules/temporal/adapters/guards.d.ts.map +0 -1
  179. package/dist/esm/modules/temporal/adapters/guards.js +0 -10
  180. package/dist/esm/modules/temporal/adapters/guards.js.map +0 -1
  181. package/dist/esm/modules/temporal/calendar.d.ts +0 -52
  182. package/dist/esm/modules/temporal/calendar.d.ts.map +0 -1
  183. package/dist/esm/modules/temporal/calendar.js +0 -138
  184. package/dist/esm/modules/temporal/calendar.js.map +0 -1
  185. package/dist/esm/modules/temporal/duration.d.ts.map +0 -1
  186. package/dist/esm/modules/temporal/duration.js +0 -60
  187. package/dist/esm/modules/temporal/duration.js.map +0 -1
  188. package/dist/esm/modules/temporal/locale.d.ts.map +0 -1
  189. package/dist/esm/modules/temporal/locale.js.map +0 -1
  190. package/dist/esm/modules/temporal/pattern.d.ts.map +0 -1
  191. package/dist/esm/modules/temporal/pattern.js.map +0 -1
  192. package/dist/esm/modules/temporal/tokens.d.ts +0 -78
  193. package/dist/esm/modules/temporal/tokens.d.ts.map +0 -1
  194. package/dist/esm/modules/temporal/tokens.js +0 -133
  195. package/dist/esm/modules/temporal/tokens.js.map +0 -1
@@ -1,14 +1,10 @@
1
1
  import { HTTP } from '../../common/constants/http.js';
2
- import { BaseHelper } from '../base.js';
3
- import { getError, isApplicationError } from '../error/index.js';
4
- import { isTemporalNamespace } from './adapters/guards.js';
5
- import { IntlTemporalAdapter } from './adapters/intl.js';
6
- import { NativeTemporalAdapter } from './adapters/native.js';
7
- import { epochAtOffset, EXACT_UNIT_MILLISECONDS, isRealDateTime, isSupportedYear, MAX_TEMPORAL_YEAR, MIN_TEMPORAL_YEAR, shiftWallClock, truncateTo, wallClockAt, wallClockOf, } from './calendar.js';
8
- import { DEFAULT_TEMPORAL_LOCALE, DEFAULT_TEMPORAL_PATTERN, DEFAULT_TEMPORAL_TIME_ZONE, TemporalUnits, } from './common/constants.js';
9
- import { TemporalDuration } from './duration.js';
10
- import { TemporalLocale } from './locale.js';
11
- import { TemporalPattern } from './pattern.js';
2
+ import { getError } from '../error/index.js';
3
+ import { AbstractTemporalHelper } from './abstract.js';
4
+ import { TemporalCalendar } from './calendar/index.js';
5
+ import { DEFAULT_TEMPORAL_PATTERN, TemporalInclusivities, TemporalUnits } from './common/constants.js';
6
+ import { TemporalDuration } from './duration/index.js';
7
+ import { TemporalPattern } from './pattern/index.js';
12
8
  /** `2026-09-19`, `2026-09-19T12:00`, `2026-09-19 12:00:00.021+07:00`, `...Z` - an offset only after a time. */
13
9
  const ISO_8601 = /^(\d{4})-(\d{2})-(\d{2})(?:[T ](\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{1,9}))?)?(Z|[+-]\d{2}(?::?\d{2}(?::?\d{2})?)?)?)?$/i;
14
10
  /** The offset of an ISO 8601 value: `+07`, `+07:00`, `+0700`, `+07:06:40`. */
@@ -17,7 +13,22 @@ const DAY_MILLISECONDS = 86_400_000;
17
13
  /** 0001-01-01T00:00:00.000Z and 9999-12-31T23:59:59.999Z. */
18
14
  const MIN_INSTANT = -62_135_596_800_000;
19
15
  const MAX_INSTANT = 253_402_300_799_999;
20
- const MAX_KNOWN_TIME_ZONES = 256;
16
+ /** Months in each calendar unit `diff` counts by months. */
17
+ const MONTHS_IN = {
18
+ [TemporalUnits.MONTH]: 1,
19
+ [TemporalUnits.QUARTER]: 3,
20
+ [TemporalUnits.YEAR]: 12,
21
+ };
22
+ /** What each wall-clock field `set` takes. The day is clamped to the month separately. */
23
+ const FIELD_RANGES = {
24
+ year: [TemporalCalendar.MIN_YEAR, TemporalCalendar.MAX_YEAR],
25
+ month: [1, 12],
26
+ day: [1, 31],
27
+ hour: [0, 23],
28
+ minute: [0, 59],
29
+ second: [0, 59],
30
+ millisecond: [0, 999],
31
+ };
21
32
  /** `formatIntl` builds one formatter per locale, options and zone; capped so caller-fed options cannot grow it. */
22
33
  const MAX_INTL_FORMATTERS = 128;
23
34
  /** `relative` without a unit says it in the largest whole one, down to seconds. */
@@ -30,7 +41,6 @@ const RELATIVE_UNITS = [
30
41
  TemporalUnits.MINUTE,
31
42
  TemporalUnits.SECOND,
32
43
  ];
33
- const OUT_OF_RANGE = `outside the years ${MIN_TEMPORAL_YEAR}-${MAX_TEMPORAL_YEAR}`;
34
44
  /**
35
45
  * Dates in one time zone, through whichever library you choose: pass an adapter - the runtime's
36
46
  * `Temporal` (the default where the runtime has it, `Intl` everywhere else), your own dayjs, your own Luxon. The adapter only reports a zone's UTC
@@ -41,179 +51,40 @@ const OUT_OF_RANGE = `outside the years ${MIN_TEMPORAL_YEAR}-${MAX_TEMPORAL_YEAR
41
51
  * swapping the adapter never touches a call site. The zone is yours to set: without one this helper
42
52
  * computes in UTC, never in the host's zone. Years run from 1 to 9999.
43
53
  */
44
- export class TemporalHelper extends BaseHelper {
45
- /** Validated once per process: `Intl` answers the same for a zone name every time. */
46
- static { this.knownTimeZones = new Set(); }
54
+ export class TemporalHelper extends AbstractTemporalHelper {
47
55
  static { this.intlFormatters = new Map(); }
48
56
  /**
49
- * `locale` (default `en-US`) spells month and weekday names, AM/PM, relative time and durations,
50
- * unless a call passes its own.
57
+ * A date picker hands back a `Date` meaning "this wall clock in the host's zone". This returns the
58
+ * instant that shows the same year, month, day and time in the helper's zone. `sourceTz` defaults
59
+ * to the host's. A skipped wall time resolves forward, a repeated one to the earlier instant.
51
60
  */
52
- constructor(opts) {
53
- super({ scope: opts?.scope ?? TemporalHelper.name });
54
- this.timeZone = TemporalHelper.ensureTimeZone({
55
- timeZone: opts?.timeZone ?? DEFAULT_TEMPORAL_TIME_ZONE,
56
- statusCode: HTTP.ResultCodes.RS_5.InternalServerError,
61
+ fromWallClock(opts) {
62
+ return this.moveWallClock({
63
+ value: opts.value,
64
+ from: opts.sourceTz ?? TemporalHelper.getHostTz(),
65
+ to: this.resolveTz({ tz: opts.tz }),
57
66
  });
58
- this.locale = TemporalHelper.ensureLocale({ locale: opts?.locale ?? DEFAULT_TEMPORAL_LOCALE });
59
- this.adapter = opts?.adapter ?? TemporalHelper.defaultAdapter();
60
- }
61
- /** The runtime's `Temporal` where it has one; `Intl`, which every runtime has, everywhere else. */
62
- static defaultAdapter() {
63
- return isTemporalNamespace(Reflect.get(globalThis, 'Temporal'))
64
- ? new NativeTemporalAdapter()
65
- : new IntlTemporalAdapter();
66
- }
67
- static ensureLocale(opts) {
68
- TemporalLocale.of({ locale: opts.locale });
69
- return opts.locale;
70
- }
71
- /** A parse or input error the caller may treat as "not a date"; anything else is a bug and still throws. */
72
- static isRefusal(error) {
73
- return isApplicationError(error) && error.statusCode === HTTP.ResultCodes.RS_4.BadRequest;
74
- }
75
- static ensureTimeZone(opts) {
76
- const { timeZone, statusCode } = opts;
77
- if (TemporalHelper.knownTimeZones.has(timeZone)) {
78
- return timeZone;
79
- }
80
- try {
81
- new Intl.DateTimeFormat('en-US', { timeZone });
82
- }
83
- catch (error) {
84
- throw getError({
85
- statusCode,
86
- message: `[TemporalHelper] unknown time zone '${timeZone}' | ${error instanceof Error ? error.message : String(error)}`,
87
- });
88
- }
89
- if (TemporalHelper.knownTimeZones.size < MAX_KNOWN_TIME_ZONES) {
90
- TemporalHelper.knownTimeZones.add(timeZone);
91
- }
92
- return timeZone;
93
- }
94
- static ensureUnit(opts) {
95
- const { unit, amount } = opts;
96
- if (!TemporalUnits.isValid(unit)) {
97
- throw getError({
98
- statusCode: HTTP.ResultCodes.RS_4.BadRequest,
99
- message: `[TemporalHelper] unknown unit '${unit}' | Supported: ${[...TemporalUnits.SCHEME_SET].join(', ')}`,
100
- });
101
- }
102
- if (amount !== undefined && !Number.isInteger(amount)) {
103
- throw getError({
104
- statusCode: HTTP.ResultCodes.RS_4.BadRequest,
105
- message: `[TemporalHelper] amount must be an integer - received ${amount}`,
106
- });
107
- }
108
- }
109
- /** Every result passes here: an overflowing `add` is refused, never an Invalid Date. */
110
- static ensureInstant(opts) {
111
- const { epoch } = opts;
112
- if (!(epoch >= MIN_INSTANT && epoch <= MAX_INSTANT)) {
113
- throw getError({
114
- statusCode: HTTP.ResultCodes.RS_4.BadRequest,
115
- message: `[TemporalHelper] ${Number.isNaN(epoch) ? 'invalid date' : OUT_OF_RANGE} - received ${epoch}`,
116
- });
117
- }
118
- return new Date(epoch);
119
- }
120
- static ensureYear(opts) {
121
- if (!isSupportedYear(opts.parts.year)) {
122
- throw getError({
123
- statusCode: HTTP.ResultCodes.RS_4.BadRequest,
124
- message: `[TemporalHelper] year ${opts.parts.year} is ${OUT_OF_RANGE}`,
125
- });
126
- }
127
- }
128
- resolveTimeZone(opts) {
129
- return opts.timeZone === undefined
130
- ? this.timeZone
131
- : TemporalHelper.ensureTimeZone({
132
- timeZone: opts.timeZone,
133
- statusCode: HTTP.ResultCodes.RS_4.BadRequest,
134
- });
135
- }
136
- /** The adapter's one answer, rounded: an offset is whole milliseconds, a library's float may not be. */
137
- offsetAt(opts) {
138
- return Math.round(this.adapter.getOffsetMilliseconds({ value: new Date(opts.epoch), timeZone: opts.timeZone }));
139
- }
140
- zonedParts(opts) {
141
- const parts = wallClockAt({ epoch: opts.epoch, offsetMilliseconds: this.offsetAt(opts) });
142
- TemporalHelper.ensureYear({ parts });
143
- return parts;
144
67
  }
145
68
  /**
146
- * Every instant whose wall clock reads `parts` in the zone, earliest first: one as a rule, two
147
- * when the clock goes back, none when it jumps forward. `forward` is where a skipped time lands -
148
- * read with the offset from before the jump, so it moves past the gap.
69
+ * The reverse of `fromWallClock`, to feed a picker: a `Date` whose wall clock in `targetTz` (default:
70
+ * the host's) reads what the helper's zone reads for `value`.
149
71
  */
150
- instantsOf(opts) {
151
- const { parts, timeZone } = opts;
152
- const local = epochAtOffset({ parts, offsetMilliseconds: 0 });
153
- const before = this.offsetAt({ epoch: local - DAY_MILLISECONDS, timeZone });
154
- const after = this.offsetAt({ epoch: local + DAY_MILLISECONDS, timeZone });
155
- const offsets = before === after ? [before] : [before, after];
156
- const instants = [];
157
- for (const offset of offsets) {
158
- const candidate = local - offset;
159
- if (this.offsetAt({ epoch: candidate, timeZone }) === offset) {
160
- instants.push(candidate);
161
- }
162
- }
163
- instants.sort((left, right) => left - right);
164
- return { instants, forward: local - before };
165
- }
166
- /** The instant wall-clock `parts` name: a skipped time moves forward, a repeated one takes the earlier. */
167
- earliestOf(opts) {
168
- const { instants, forward } = this.instantsOf(opts);
169
- return instants[0] ?? forward;
170
- }
171
- /**
172
- * `[start, end)` of the unit holding `epoch`. A day or longer starts at its first instant. An hour
173
- * or less repeats when the clock goes back, so it starts at the latest start not after `epoch`,
174
- * and ends where the wall clock next shows either the following unit or this one's start again.
175
- */
176
- unitBounds(opts) {
177
- const { epoch, unit, timeZone } = opts;
178
- const startParts = truncateTo({ parts: this.zonedParts({ epoch, timeZone }), unit });
179
- const nextParts = shiftWallClock({ parts: startParts, amount: 1, unit });
180
- TemporalHelper.ensureYear({ parts: nextParts });
181
- const starts = this.instantsOf({ parts: startParts, timeZone });
182
- if (EXACT_UNIT_MILLISECONDS[unit] === undefined) {
183
- const start = starts.instants[0] ?? starts.forward;
184
- return { start, end: this.earliestOf({ parts: nextParts, timeZone }) };
185
- }
186
- const started = starts.instants.filter(instant => instant <= epoch);
187
- const start = started.at(-1) ?? starts.instants[0] ?? starts.forward;
188
- const nexts = this.instantsOf({ parts: nextParts, timeZone });
189
- const following = nexts.instants.find(instant => instant > start) ?? nexts.forward;
190
- const repeated = starts.instants.find(instant => instant > start);
191
- return { start, end: repeated === undefined ? following : Math.min(repeated, following) };
192
- }
193
- getTimeZone() {
194
- return this.timeZone;
195
- }
196
- getLocale() {
197
- return this.locale;
198
- }
199
- now() {
200
- return new Date();
201
- }
202
- /** The instant a value names. An ISO string without an offset is read as wall clock in the zone. */
203
- toDate(opts) {
204
- const { value } = opts;
205
- if (typeof value === 'string') {
206
- return this.parse({ value, timeZone: opts.timeZone });
207
- }
208
- return TemporalHelper.ensureInstant({
209
- epoch: value instanceof Date ? value.getTime() : value,
72
+ toWallClock(opts) {
73
+ return this.moveWallClock({
74
+ value: opts.value,
75
+ from: this.resolveTz({ tz: opts.tz }),
76
+ to: opts.targetTz ?? TemporalHelper.getHostTz(),
210
77
  });
211
78
  }
212
- /** The wall clock the value shows in the zone, with its ISO weekday and UTC offset. */
213
- parts(opts) {
214
- const timeZone = this.resolveTimeZone({ timeZone: opts.timeZone });
215
- const date = this.toDate({ value: opts.value, timeZone });
216
- return this.zonedParts({ epoch: date.getTime(), timeZone });
79
+ /** A helper like this one, with another locale or zone: same adapter, same `names`. */
80
+ clone(opts) {
81
+ return new TemporalHelper({
82
+ adapter: this.adapter,
83
+ tz: opts.tz ?? this.tz,
84
+ locale: opts.locale ?? this.locale,
85
+ names: this.names,
86
+ scope: this.scope,
87
+ });
217
88
  }
218
89
  /**
219
90
  * Reads a string. With a `pattern` (`YYYY YY MM M DD D HH H mm m ss s SSS Z ZZ`, text in
@@ -222,7 +93,7 @@ export class TemporalHelper extends BaseHelper {
222
93
  */
223
94
  parse(opts) {
224
95
  const { value, pattern } = opts;
225
- const timeZone = this.resolveTimeZone({ timeZone: opts.timeZone });
96
+ const tz = this.resolveTz({ tz: opts.tz });
226
97
  const read = pattern ? TemporalPattern.parse({ pattern, value }) : this.readIso({ value });
227
98
  if (!read) {
228
99
  throw getError({
@@ -232,15 +103,18 @@ export class TemporalHelper extends BaseHelper {
232
103
  : `[TemporalHelper] '${value}' is not ISO 8601 | Pass a pattern for any other shape`,
233
104
  });
234
105
  }
235
- if (!isRealDateTime({ parts: read.parts })) {
106
+ if (!TemporalCalendar.isRealDateTime({ parts: read.parts })) {
236
107
  throw getError({
237
108
  statusCode: HTTP.ResultCodes.RS_4.BadRequest,
238
109
  message: `[TemporalHelper] '${value}' is not a real date and time`,
239
110
  });
240
111
  }
241
112
  const epoch = read.offsetMilliseconds === undefined
242
- ? this.earliestOf({ parts: read.parts, timeZone })
243
- : epochAtOffset({ parts: read.parts, offsetMilliseconds: read.offsetMilliseconds });
113
+ ? this.earliestOf({ parts: read.parts, tz })
114
+ : TemporalCalendar.epochAtOffset({
115
+ parts: read.parts,
116
+ offsetMilliseconds: read.offsetMilliseconds,
117
+ });
244
118
  return TemporalHelper.ensureInstant({ epoch });
245
119
  }
246
120
  readIso(opts) {
@@ -277,9 +151,9 @@ export class TemporalHelper extends BaseHelper {
277
151
  /** `parse`, answering `null` where `parse` refuses the value. A pattern that does not compile still throws. */
278
152
  tryParse(opts) {
279
153
  // Outside the try: a bad zone is the caller's bug, as a broken pattern is.
280
- const timeZone = this.resolveTimeZone({ timeZone: opts.timeZone });
154
+ const tz = this.resolveTz({ tz: opts.tz });
281
155
  try {
282
- return this.parse({ ...opts, timeZone });
156
+ return this.parse({ ...opts, tz });
283
157
  }
284
158
  catch (error) {
285
159
  if (TemporalHelper.isRefusal(error)) {
@@ -290,35 +164,56 @@ export class TemporalHelper extends BaseHelper {
290
164
  }
291
165
  /** Whether the value names an instant in years 1-9999 - a string read as `parse` reads it. */
292
166
  isValid(opts) {
293
- const { value, pattern, timeZone } = opts;
167
+ const { value, pattern, tz } = opts;
294
168
  if (typeof value === 'string') {
295
- return this.tryParse({ value, pattern, timeZone }) !== null;
169
+ return this.tryParse({ value, pattern, tz }) !== null;
170
+ }
171
+ if (!(value instanceof Date) && typeof value !== 'number') {
172
+ return false;
296
173
  }
297
174
  const epoch = value instanceof Date ? value.getTime() : value;
298
175
  return epoch >= MIN_INSTANT && epoch <= MAX_INSTANT;
299
176
  }
300
177
  /**
301
- * Writes the value in the zone. Without a `pattern`: ISO 8601 with the zone's offset. The locale
302
- * tokens `MMMM MMM dddd ddd A a hh h LL L` are spelled in `locale`.
178
+ * Writes the value in the zone. Without a `pattern`: ISO 8601 with the zone's offset. The tokens
179
+ * `MMMM MMM dddd ddd dd A a hh h LL L` are spelled in `locale`. With a `fallback`, a value that is
180
+ * not a date - null included - writes the fallback; without one, it is a 400.
303
181
  */
304
182
  format(opts) {
183
+ const { value, fallback } = opts;
184
+ const tz = this.resolveTz({ tz: opts.tz });
185
+ const locale = opts.locale ?? this.locale;
186
+ let date;
187
+ if (fallback !== undefined) {
188
+ date = this.tryToDate({ value, tz });
189
+ }
190
+ else if (value === null || value === undefined) {
191
+ throw TemporalHelper.notADate({ value });
192
+ }
193
+ else {
194
+ date = this.toDate({ value, tz });
195
+ }
196
+ if (date === null) {
197
+ return fallback ?? '';
198
+ }
305
199
  return TemporalPattern.format({
306
200
  pattern: opts.pattern ?? DEFAULT_TEMPORAL_PATTERN,
307
- parts: this.parts({ value: opts.value, timeZone: opts.timeZone }),
308
- locale: opts.locale ?? this.locale,
201
+ parts: this.zonedParts({ epoch: date.getTime(), tz }),
202
+ locale,
203
+ names: this.namesOf({ locale }),
309
204
  });
310
205
  }
311
206
  /** Writes the value with `Intl.DateTimeFormat` options, in the zone - for what the pattern tokens cannot say. */
312
207
  formatIntl(opts) {
313
- const timeZone = this.resolveTimeZone({ timeZone: opts.timeZone });
208
+ const tz = this.resolveTz({ tz: opts.tz });
314
209
  const locale = opts.locale === undefined
315
210
  ? this.locale
316
211
  : TemporalHelper.ensureLocale({ locale: opts.locale });
317
- const date = this.toDate({ value: opts.value, timeZone });
318
- const key = `${locale}|${timeZone}|${JSON.stringify(opts.options ?? {})}`;
212
+ const date = this.toDate({ value: opts.value, tz });
213
+ const key = `${locale}|${tz}|${JSON.stringify(opts.options ?? {})}`;
319
214
  let formatter = TemporalHelper.intlFormatters.get(key);
320
215
  if (!formatter) {
321
- formatter = new Intl.DateTimeFormat(locale, { ...opts.options, timeZone });
216
+ formatter = new Intl.DateTimeFormat(locale, { ...opts.options, timeZone: tz });
322
217
  if (TemporalHelper.intlFormatters.size < MAX_INTL_FORMATTERS) {
323
218
  TemporalHelper.intlFormatters.set(key, formatter);
324
219
  }
@@ -333,19 +228,21 @@ export class TemporalHelper extends BaseHelper {
333
228
  add(opts) {
334
229
  const { amount, unit } = opts;
335
230
  TemporalHelper.ensureUnit({ unit, amount });
336
- const timeZone = this.resolveTimeZone({ timeZone: opts.timeZone });
337
- const date = this.toDate({ value: opts.value, timeZone });
231
+ const tz = this.resolveTz({ tz: opts.tz });
232
+ const date = this.toDate({ value: opts.value, tz });
338
233
  if (amount === 0) {
339
234
  return date;
340
235
  }
341
- const exact = EXACT_UNIT_MILLISECONDS[unit];
236
+ const exact = TemporalCalendar.EXACT_UNIT_MILLISECONDS[unit];
342
237
  if (exact !== undefined) {
343
238
  return TemporalHelper.ensureInstant({ epoch: date.getTime() + amount * exact });
344
239
  }
345
- const parts = wallClockOf({ parts: this.zonedParts({ epoch: date.getTime(), timeZone }) });
346
- const shifted = shiftWallClock({ parts, amount, unit });
240
+ const parts = TemporalCalendar.wallClockOf({
241
+ parts: this.zonedParts({ epoch: date.getTime(), tz }),
242
+ });
243
+ const shifted = TemporalCalendar.shift({ parts, amount, unit });
347
244
  TemporalHelper.ensureYear({ parts: shifted });
348
- return TemporalHelper.ensureInstant({ epoch: this.earliestOf({ parts: shifted, timeZone }) });
245
+ return TemporalHelper.ensureInstant({ epoch: this.earliestOf({ parts: shifted, tz }) });
349
246
  }
350
247
  subtract(opts) {
351
248
  return this.add({ ...opts, amount: -opts.amount });
@@ -354,24 +251,24 @@ export class TemporalHelper extends BaseHelper {
354
251
  startOf(opts) {
355
252
  const { unit } = opts;
356
253
  TemporalHelper.ensureUnit({ unit });
357
- const timeZone = this.resolveTimeZone({ timeZone: opts.timeZone });
358
- const date = this.toDate({ value: opts.value, timeZone });
254
+ const tz = this.resolveTz({ tz: opts.tz });
255
+ const date = this.toDate({ value: opts.value, tz });
359
256
  if (unit === TemporalUnits.MILLISECOND) {
360
257
  return date;
361
258
  }
362
- const { start } = this.unitBounds({ epoch: date.getTime(), unit, timeZone });
259
+ const { start } = this.unitBounds({ epoch: date.getTime(), unit, tz });
363
260
  return TemporalHelper.ensureInstant({ epoch: start });
364
261
  }
365
262
  /** The last millisecond of the unit containing the value, in the zone. */
366
263
  endOf(opts) {
367
264
  const { unit } = opts;
368
265
  TemporalHelper.ensureUnit({ unit });
369
- const timeZone = this.resolveTimeZone({ timeZone: opts.timeZone });
370
- const date = this.toDate({ value: opts.value, timeZone });
266
+ const tz = this.resolveTz({ tz: opts.tz });
267
+ const date = this.toDate({ value: opts.value, tz });
371
268
  if (unit === TemporalUnits.MILLISECOND) {
372
269
  return date;
373
270
  }
374
- const { end } = this.unitBounds({ epoch: date.getTime(), unit, timeZone });
271
+ const { end } = this.unitBounds({ epoch: date.getTime(), unit, tz });
375
272
  return TemporalHelper.ensureInstant({ epoch: end - 1 });
376
273
  }
377
274
  /** Monday to Friday, read on the wall clock of the zone. */
@@ -389,70 +286,118 @@ export class TemporalHelper extends BaseHelper {
389
286
  value: opts.value,
390
287
  amount: opts.step,
391
288
  unit: TemporalUnits.DAY,
392
- timeZone: opts.timeZone,
289
+ tz: opts.tz,
393
290
  });
394
- while (!this.isWeekday({ value: candidate, timeZone: opts.timeZone })) {
291
+ while (!this.isWeekday({ value: candidate, tz: opts.tz })) {
395
292
  candidate = this.add({
396
293
  value: candidate,
397
294
  amount: opts.step,
398
295
  unit: TemporalUnits.DAY,
399
- timeZone: opts.timeZone,
296
+ tz: opts.tz,
400
297
  });
401
298
  }
402
299
  return candidate;
403
300
  }
301
+ /**
302
+ * The value with wall-clock fields replaced in the zone - `{ hour: 9, minute: 0 }` is 09:00 that day.
303
+ * `month` is 1-12. The day is clamped to the month's last day, so setting February on the 31st
304
+ * lands on the 28th or 29th. A wall time a daylight-saving jump skips resolves forward, as `parse` does.
305
+ */
306
+ set(opts) {
307
+ const tz = this.resolveTz({ tz: opts.tz });
308
+ const date = this.toDate({ value: opts.value, tz });
309
+ const wall = TemporalCalendar.wallClockOf({
310
+ parts: this.zonedParts({ epoch: date.getTime(), tz }),
311
+ });
312
+ const next = { ...wall };
313
+ for (const [field, [min, max]] of Object.entries(FIELD_RANGES)) {
314
+ const given = Reflect.get(opts, field);
315
+ if (given === undefined) {
316
+ continue;
317
+ }
318
+ if (typeof given !== 'number' || !Number.isInteger(given) || given < min || given > max) {
319
+ throw getError({
320
+ statusCode: HTTP.ResultCodes.RS_4.BadRequest,
321
+ message: `[TemporalHelper] ${field} must be an integer from ${min} to ${max} - received ${String(given)}`,
322
+ });
323
+ }
324
+ Reflect.set(next, field, given);
325
+ }
326
+ next.day = Math.min(next.day, TemporalCalendar.daysInMonth({ year: next.year, month: next.month }));
327
+ return TemporalHelper.ensureInstant({ epoch: this.earliestOf({ parts: next, tz }) });
328
+ }
329
+ /** `value` is before `other` - at the unit's granularity in the zone when `unit` is given. */
330
+ isBefore(opts) {
331
+ return this.compare(opts) < 0;
332
+ }
333
+ isAfter(opts) {
334
+ return this.compare(opts) > 0;
335
+ }
336
+ /** In the same unit - `unit: 'day'` is the same calendar day in the zone. */
337
+ isSame(opts) {
338
+ return this.compare(opts) === 0;
339
+ }
340
+ isSameOrBefore(opts) {
341
+ return this.compare(opts) <= 0;
342
+ }
343
+ isSameOrAfter(opts) {
344
+ return this.compare(opts) >= 0;
345
+ }
346
+ /**
347
+ * Whether `value` lies between `from` and `to`, in either order. `inclusivity` says which ends count:
348
+ * `()` (the default) neither, `[]` both, `[)` the start, `(]` the end.
349
+ */
350
+ isBetween(opts) {
351
+ const { value, from, to, unit, inclusivity = TemporalInclusivities.EXCLUSIVE, tz } = opts;
352
+ if (!TemporalInclusivities.isValid(inclusivity)) {
353
+ throw getError({
354
+ statusCode: HTTP.ResultCodes.RS_4.BadRequest,
355
+ message: `[TemporalHelper] unknown inclusivity '${inclusivity}' | Supported: ${[...TemporalInclusivities.SCHEME_SET].join(', ')}`,
356
+ });
357
+ }
358
+ const isStartIncluded = inclusivity.startsWith('[');
359
+ const isEndIncluded = inclusivity.endsWith(']');
360
+ const fromOrder = this.compare({ value, other: from, unit, tz });
361
+ const toOrder = this.compare({ value, other: to, unit, tz });
362
+ const isAfterStart = isStartIncluded ? fromOrder >= 0 : fromOrder > 0;
363
+ const isBeforeEnd = isEndIncluded ? toOrder <= 0 : toOrder < 0;
364
+ // The range given backwards: `to` is the earlier end.
365
+ const isAfterEnd = isEndIncluded ? toOrder >= 0 : toOrder > 0;
366
+ const isBeforeStart = isStartIncluded ? fromOrder <= 0 : fromOrder < 0;
367
+ return (isAfterStart && isBeforeEnd) || (isAfterEnd && isBeforeStart);
368
+ }
404
369
  /**
405
370
  * How many whole units `value` is past `other` - negative when it is before - truncated toward
406
- * zero. Hours and smaller count elapsed time. Days and larger count the calendar in the zone, as
407
- * `add` moves it: the answer is the largest `n` that `add` can move `other` by without passing
408
- * `value`, so `diff(add(x, n), x)` is `n` wherever the zone skips no whole day.
371
+ * zero, counted as dayjs counts. Hours and smaller are elapsed time. Days and weeks are calendar
372
+ * days in the zone: the wall clocks' difference, so a 23-hour daylight-saving day is one day.
373
+ * Months, quarters and years are anchored on the date with the later day of the month, then
374
+ * truncated, so `diff(a, b)` is always `-diff(b, a)`.
409
375
  */
410
376
  diff(opts) {
411
377
  const { unit } = opts;
412
378
  TemporalHelper.ensureUnit({ unit });
413
- const timeZone = this.resolveTimeZone({ timeZone: opts.timeZone });
414
- const value = this.toDate({ value: opts.value, timeZone }).getTime();
415
- const other = this.toDate({ value: opts.other, timeZone }).getTime();
416
- const exact = EXACT_UNIT_MILLISECONDS[unit];
379
+ const tz = this.resolveTz({ tz: opts.tz });
380
+ const value = this.toDate({ value: opts.value, tz }).getTime();
381
+ const other = this.toDate({ value: opts.other, tz }).getTime();
382
+ // `+ 0` turns a truncated `-0` into `0`.
383
+ const exact = TemporalCalendar.EXACT_UNIT_MILLISECONDS[unit];
417
384
  if (exact !== undefined) {
418
- // `+ 0` turns a truncated `-0` into `0`.
419
385
  return Math.trunc((value - other) / exact) + 0;
420
386
  }
421
- if (value === other) {
422
- return 0;
423
- }
424
- const later = this.zonedParts({ epoch: value, timeZone });
425
- const earlier = this.zonedParts({ epoch: other, timeZone });
426
- // A first guess from the wall clocks, settled by `add` itself: back while it passes `value`, then
427
- // on while the next step does not - a zone that repeats or skips a whole day can put it either side.
428
- let guess;
429
- if (unit === TemporalUnits.MONTH || unit === TemporalUnits.YEAR) {
430
- const months = (later.year - earlier.year) * 12 + (later.month - earlier.month);
431
- guess = unit === TemporalUnits.YEAR ? Math.trunc(months / 12) : months;
432
- }
433
- else {
434
- const days = Math.round((epochAtOffset({ parts: wallClockOf({ parts: later }), offsetMilliseconds: 0 }) -
435
- epochAtOffset({ parts: wallClockOf({ parts: earlier }), offsetMilliseconds: 0 })) /
436
- DAY_MILLISECONDS);
437
- guess = unit === TemporalUnits.WEEK ? Math.trunc(days / 7) : Math.trunc(days);
438
- }
439
- const direction = Math.sign(value - other);
440
- const start = wallClockOf({ parts: earlier });
441
- const passes = (amount) => {
442
- // A move past years 1-9999 passes every value inside them, and `add` would refuse it.
443
- if (!isSupportedYear(shiftWallClock({ parts: start, amount, unit }).year)) {
444
- return true;
445
- }
446
- const moved = this.add({ value: other, amount, unit, timeZone }).getTime();
447
- return direction > 0 ? moved > value : moved < value;
448
- };
449
- while (guess !== 0 && passes(guess)) {
450
- guess -= direction;
451
- }
452
- while (!passes(guess + direction)) {
453
- guess += direction;
454
- }
455
- return guess + 0;
387
+ const months = MONTHS_IN[unit];
388
+ if (months !== undefined) {
389
+ return Math.trunc(this.monthGap({ value, other, tz }) / months) + 0;
390
+ }
391
+ const wallClocks = TemporalCalendar.epochAtOffset({
392
+ parts: TemporalCalendar.wallClockOf({ parts: this.zonedParts({ epoch: value, tz }) }),
393
+ offsetMilliseconds: 0,
394
+ }) -
395
+ TemporalCalendar.epochAtOffset({
396
+ parts: TemporalCalendar.wallClockOf({ parts: this.zonedParts({ epoch: other, tz }) }),
397
+ offsetMilliseconds: 0,
398
+ });
399
+ const days = wallClocks / DAY_MILLISECONDS;
400
+ return Math.trunc(unit === TemporalUnits.WEEK ? days / 7 : days) + 0;
456
401
  }
457
402
  /**
458
403
  * `-1`, `0` or `1` as `value` is before, in, or after the unit that holds `other`, in the zone.
@@ -460,13 +405,13 @@ export class TemporalHelper extends BaseHelper {
460
405
  */
461
406
  compare(opts) {
462
407
  const { unit } = opts;
463
- const timeZone = this.resolveTimeZone({ timeZone: opts.timeZone });
408
+ const tz = this.resolveTz({ tz: opts.tz });
464
409
  const value = unit === undefined
465
- ? this.toDate({ value: opts.value, timeZone })
466
- : this.startOf({ value: opts.value, unit, timeZone });
410
+ ? this.toDate({ value: opts.value, tz })
411
+ : this.startOf({ value: opts.value, unit, tz });
467
412
  const other = unit === undefined
468
- ? this.toDate({ value: opts.other, timeZone })
469
- : this.startOf({ value: opts.other, unit, timeZone });
413
+ ? this.toDate({ value: opts.other, tz })
414
+ : this.startOf({ value: opts.other, unit, tz });
470
415
  const delta = value.getTime() - other.getTime();
471
416
  return delta < 0 ? -1 : delta > 0 ? 1 : 0;
472
417
  }
@@ -478,12 +423,12 @@ export class TemporalHelper extends BaseHelper {
478
423
  */
479
424
  relative(opts) {
480
425
  const { unit, numeric = 'always', style = 'long' } = opts;
481
- const timeZone = this.resolveTimeZone({ timeZone: opts.timeZone });
426
+ const tz = this.resolveTz({ tz: opts.tz });
482
427
  const locale = opts.locale === undefined
483
428
  ? this.locale
484
429
  : TemporalHelper.ensureLocale({ locale: opts.locale });
485
- const value = this.toDate({ value: opts.value, timeZone });
486
- const base = opts.base === undefined ? this.now() : this.toDate({ value: opts.base, timeZone });
430
+ const value = this.toDate({ value: opts.value, tz });
431
+ const base = opts.base === undefined ? this.now() : this.toDate({ value: opts.base, tz });
487
432
  let amount = 0;
488
433
  let said = TemporalUnits.SECOND;
489
434
  if (unit !== undefined) {
@@ -495,16 +440,16 @@ export class TemporalHelper extends BaseHelper {
495
440
  });
496
441
  }
497
442
  amount = this.diff({
498
- value: this.startOf({ value, unit, timeZone }),
499
- other: this.startOf({ value: base, unit, timeZone }),
443
+ value: this.startOf({ value, unit, tz }),
444
+ other: this.startOf({ value: base, unit, tz }),
500
445
  unit,
501
- timeZone,
446
+ tz,
502
447
  });
503
448
  said = unit;
504
449
  }
505
450
  else {
506
451
  for (const candidate of RELATIVE_UNITS) {
507
- const counted = this.diff({ value, other: base, unit: candidate, timeZone });
452
+ const counted = this.diff({ value, other: base, unit: candidate, tz });
508
453
  if (counted !== 0 || candidate === TemporalUnits.SECOND) {
509
454
  amount = counted;
510
455
  said = candidate;
@@ -526,7 +471,13 @@ export class TemporalHelper extends BaseHelper {
526
471
  const locale = opts.locale === undefined
527
472
  ? this.locale
528
473
  : TemporalHelper.ensureLocale({ locale: opts.locale });
529
- return TemporalDuration.format({ milliseconds: opts.milliseconds, style: opts.style, locale });
474
+ return TemporalDuration.format({
475
+ milliseconds: opts.milliseconds,
476
+ style: opts.style,
477
+ pattern: opts.pattern,
478
+ maxUnits: opts.maxUnits,
479
+ locale,
480
+ });
530
481
  }
531
482
  }
532
483
  //# sourceMappingURL=helper.js.map