@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.
- package/dist/cjs/modules/temporal/abstract.d.ts +295 -0
- package/dist/cjs/modules/temporal/abstract.d.ts.map +1 -0
- package/dist/cjs/modules/temporal/abstract.js +330 -0
- package/dist/cjs/modules/temporal/abstract.js.map +1 -0
- package/dist/cjs/modules/temporal/adapters/dayjs.d.ts +1 -1
- package/dist/cjs/modules/temporal/adapters/dayjs.d.ts.map +1 -1
- package/dist/cjs/modules/temporal/adapters/dayjs.js +3 -3
- package/dist/cjs/modules/temporal/adapters/dayjs.js.map +1 -1
- package/dist/cjs/modules/temporal/adapters/intl.d.ts +1 -1
- package/dist/cjs/modules/temporal/adapters/intl.d.ts.map +1 -1
- package/dist/cjs/modules/temporal/adapters/intl.js +7 -7
- package/dist/cjs/modules/temporal/adapters/intl.js.map +1 -1
- package/dist/cjs/modules/temporal/adapters/luxon.d.ts +1 -1
- package/dist/cjs/modules/temporal/adapters/luxon.d.ts.map +1 -1
- package/dist/cjs/modules/temporal/adapters/luxon.js +3 -3
- package/dist/cjs/modules/temporal/adapters/luxon.js.map +1 -1
- package/dist/cjs/modules/temporal/adapters/native.d.ts +3 -1
- package/dist/cjs/modules/temporal/adapters/native.d.ts.map +1 -1
- package/dist/cjs/modules/temporal/adapters/native.js +13 -5
- package/dist/cjs/modules/temporal/adapters/native.js.map +1 -1
- package/dist/cjs/modules/temporal/calendar/calendar.d.ts +56 -0
- package/dist/cjs/modules/temporal/calendar/calendar.d.ts.map +1 -0
- package/dist/cjs/modules/temporal/calendar/calendar.js +166 -0
- package/dist/cjs/modules/temporal/calendar/calendar.js.map +1 -0
- package/dist/cjs/modules/temporal/calendar/index.d.ts +2 -0
- package/dist/cjs/modules/temporal/calendar/index.d.ts.map +1 -0
- package/dist/cjs/modules/temporal/calendar/index.js +18 -0
- package/dist/cjs/modules/temporal/calendar/index.js.map +1 -0
- package/dist/cjs/modules/temporal/common/constants.d.ts +14 -3
- package/dist/cjs/modules/temporal/common/constants.d.ts.map +1 -1
- package/dist/cjs/modules/temporal/common/constants.js +23 -4
- package/dist/cjs/modules/temporal/common/constants.js.map +1 -1
- package/dist/cjs/modules/temporal/common/types.d.ts +258 -5
- package/dist/cjs/modules/temporal/common/types.d.ts.map +1 -1
- package/dist/cjs/modules/temporal/{duration.d.ts → duration/duration.d.ts} +9 -2
- package/dist/cjs/modules/temporal/duration/duration.d.ts.map +1 -0
- package/dist/cjs/modules/temporal/duration/duration.js +135 -0
- package/dist/cjs/modules/temporal/duration/duration.js.map +1 -0
- package/dist/cjs/modules/temporal/duration/index.d.ts +2 -0
- package/dist/cjs/modules/temporal/duration/index.d.ts.map +1 -0
- package/dist/cjs/modules/temporal/duration/index.js +18 -0
- package/dist/cjs/modules/temporal/duration/index.js.map +1 -0
- package/dist/cjs/modules/temporal/helper.d.ts +105 -77
- package/dist/cjs/modules/temporal/helper.d.ts.map +1 -1
- package/dist/cjs/modules/temporal/helper.js +209 -258
- package/dist/cjs/modules/temporal/helper.js.map +1 -1
- package/dist/cjs/modules/temporal/index.d.ts +1 -0
- package/dist/cjs/modules/temporal/index.d.ts.map +1 -1
- package/dist/cjs/modules/temporal/index.js +1 -0
- package/dist/cjs/modules/temporal/index.js.map +1 -1
- package/dist/cjs/modules/temporal/locale/index.d.ts +2 -0
- package/dist/cjs/modules/temporal/locale/index.d.ts.map +1 -0
- package/dist/cjs/modules/temporal/locale/index.js +18 -0
- package/dist/cjs/modules/temporal/locale/index.js.map +1 -0
- package/dist/{esm/modules/temporal → cjs/modules/temporal/locale}/locale.d.ts +3 -2
- package/dist/cjs/modules/temporal/locale/locale.d.ts.map +1 -0
- package/dist/cjs/modules/temporal/{locale.js → locale/locale.js} +3 -3
- package/dist/cjs/modules/temporal/locale/locale.js.map +1 -0
- package/dist/cjs/modules/temporal/pattern/common/index.d.ts +2 -0
- package/dist/cjs/modules/temporal/pattern/common/index.d.ts.map +1 -0
- package/dist/cjs/modules/temporal/pattern/common/index.js +18 -0
- package/dist/cjs/modules/temporal/pattern/common/index.js.map +1 -0
- package/dist/cjs/modules/temporal/pattern/common/types.d.ts +26 -0
- package/dist/cjs/modules/temporal/pattern/common/types.d.ts.map +1 -0
- package/dist/cjs/modules/temporal/pattern/common/types.js +3 -0
- package/dist/cjs/modules/temporal/pattern/common/types.js.map +1 -0
- package/dist/cjs/modules/temporal/pattern/index.d.ts +4 -0
- package/dist/cjs/modules/temporal/pattern/index.d.ts.map +1 -0
- package/dist/cjs/modules/temporal/pattern/index.js +20 -0
- package/dist/cjs/modules/temporal/pattern/index.js.map +1 -0
- package/dist/{esm/modules/temporal → cjs/modules/temporal/pattern}/pattern.d.ts +2 -1
- package/dist/cjs/modules/temporal/pattern/pattern.d.ts.map +1 -0
- package/dist/cjs/modules/temporal/{pattern.js → pattern/pattern.js} +19 -14
- package/dist/cjs/modules/temporal/pattern/pattern.js.map +1 -0
- package/dist/cjs/modules/temporal/pattern/tokens.d.ts +59 -0
- package/dist/cjs/modules/temporal/pattern/tokens.d.ts.map +1 -0
- package/dist/cjs/modules/temporal/pattern/tokens.js +195 -0
- package/dist/cjs/modules/temporal/pattern/tokens.js.map +1 -0
- package/dist/esm/modules/temporal/abstract.d.ts +295 -0
- package/dist/esm/modules/temporal/abstract.d.ts.map +1 -0
- package/dist/esm/modules/temporal/abstract.js +326 -0
- package/dist/esm/modules/temporal/abstract.js.map +1 -0
- package/dist/esm/modules/temporal/adapters/dayjs.d.ts +1 -1
- package/dist/esm/modules/temporal/adapters/dayjs.d.ts.map +1 -1
- package/dist/esm/modules/temporal/adapters/dayjs.js +3 -3
- package/dist/esm/modules/temporal/adapters/dayjs.js.map +1 -1
- package/dist/esm/modules/temporal/adapters/intl.d.ts +1 -1
- package/dist/esm/modules/temporal/adapters/intl.d.ts.map +1 -1
- package/dist/esm/modules/temporal/adapters/intl.js +7 -7
- package/dist/esm/modules/temporal/adapters/intl.js.map +1 -1
- package/dist/esm/modules/temporal/adapters/luxon.d.ts +1 -1
- package/dist/esm/modules/temporal/adapters/luxon.d.ts.map +1 -1
- package/dist/esm/modules/temporal/adapters/luxon.js +3 -3
- package/dist/esm/modules/temporal/adapters/luxon.js.map +1 -1
- package/dist/esm/modules/temporal/adapters/native.d.ts +3 -1
- package/dist/esm/modules/temporal/adapters/native.d.ts.map +1 -1
- package/dist/esm/modules/temporal/adapters/native.js +13 -5
- package/dist/esm/modules/temporal/adapters/native.js.map +1 -1
- package/dist/esm/modules/temporal/calendar/calendar.d.ts +56 -0
- package/dist/esm/modules/temporal/calendar/calendar.d.ts.map +1 -0
- package/dist/esm/modules/temporal/calendar/calendar.js +162 -0
- package/dist/esm/modules/temporal/calendar/calendar.js.map +1 -0
- package/dist/esm/modules/temporal/calendar/index.d.ts +2 -0
- package/dist/esm/modules/temporal/calendar/index.d.ts.map +1 -0
- package/dist/esm/modules/temporal/calendar/index.js +2 -0
- package/dist/esm/modules/temporal/calendar/index.js.map +1 -0
- package/dist/esm/modules/temporal/common/constants.d.ts +14 -3
- package/dist/esm/modules/temporal/common/constants.d.ts.map +1 -1
- package/dist/esm/modules/temporal/common/constants.js +21 -3
- package/dist/esm/modules/temporal/common/constants.js.map +1 -1
- package/dist/esm/modules/temporal/common/types.d.ts +258 -5
- package/dist/esm/modules/temporal/common/types.d.ts.map +1 -1
- package/dist/esm/modules/temporal/{duration.d.ts → duration/duration.d.ts} +9 -2
- package/dist/esm/modules/temporal/duration/duration.d.ts.map +1 -0
- package/dist/esm/modules/temporal/duration/duration.js +131 -0
- package/dist/esm/modules/temporal/duration/duration.js.map +1 -0
- package/dist/esm/modules/temporal/duration/index.d.ts +2 -0
- package/dist/esm/modules/temporal/duration/index.d.ts.map +1 -0
- package/dist/esm/modules/temporal/duration/index.js +2 -0
- package/dist/esm/modules/temporal/duration/index.js.map +1 -0
- package/dist/esm/modules/temporal/helper.d.ts +105 -77
- package/dist/esm/modules/temporal/helper.d.ts.map +1 -1
- package/dist/esm/modules/temporal/helper.js +214 -263
- package/dist/esm/modules/temporal/helper.js.map +1 -1
- package/dist/esm/modules/temporal/index.d.ts +1 -0
- package/dist/esm/modules/temporal/index.d.ts.map +1 -1
- package/dist/esm/modules/temporal/index.js +1 -0
- package/dist/esm/modules/temporal/index.js.map +1 -1
- package/dist/esm/modules/temporal/locale/index.d.ts +2 -0
- package/dist/esm/modules/temporal/locale/index.d.ts.map +1 -0
- package/dist/esm/modules/temporal/locale/index.js +2 -0
- package/dist/esm/modules/temporal/locale/index.js.map +1 -0
- package/dist/{cjs/modules/temporal → esm/modules/temporal/locale}/locale.d.ts +3 -2
- package/dist/esm/modules/temporal/locale/locale.d.ts.map +1 -0
- package/dist/esm/modules/temporal/{locale.js → locale/locale.js} +3 -3
- package/dist/esm/modules/temporal/locale/locale.js.map +1 -0
- package/dist/esm/modules/temporal/pattern/common/index.d.ts +2 -0
- package/dist/esm/modules/temporal/pattern/common/index.d.ts.map +1 -0
- package/dist/esm/modules/temporal/pattern/common/index.js +2 -0
- package/dist/esm/modules/temporal/pattern/common/index.js.map +1 -0
- package/dist/esm/modules/temporal/pattern/common/types.d.ts +26 -0
- package/dist/esm/modules/temporal/pattern/common/types.d.ts.map +1 -0
- package/dist/esm/modules/temporal/pattern/common/types.js +2 -0
- package/dist/esm/modules/temporal/pattern/common/types.js.map +1 -0
- package/dist/esm/modules/temporal/pattern/index.d.ts +4 -0
- package/dist/esm/modules/temporal/pattern/index.d.ts.map +1 -0
- package/dist/esm/modules/temporal/pattern/index.js +4 -0
- package/dist/esm/modules/temporal/pattern/index.js.map +1 -0
- package/dist/{cjs/modules/temporal → esm/modules/temporal/pattern}/pattern.d.ts +2 -1
- package/dist/esm/modules/temporal/pattern/pattern.d.ts.map +1 -0
- package/dist/esm/modules/temporal/{pattern.js → pattern/pattern.js} +20 -15
- package/dist/esm/modules/temporal/pattern/pattern.js.map +1 -0
- package/dist/esm/modules/temporal/pattern/tokens.d.ts +59 -0
- package/dist/esm/modules/temporal/pattern/tokens.d.ts.map +1 -0
- package/dist/esm/modules/temporal/pattern/tokens.js +191 -0
- package/dist/esm/modules/temporal/pattern/tokens.js.map +1 -0
- package/package.json +2 -2
- package/dist/cjs/modules/temporal/adapters/guards.d.ts +0 -4
- package/dist/cjs/modules/temporal/adapters/guards.d.ts.map +0 -1
- package/dist/cjs/modules/temporal/adapters/guards.js +0 -14
- package/dist/cjs/modules/temporal/adapters/guards.js.map +0 -1
- package/dist/cjs/modules/temporal/calendar.d.ts +0 -52
- package/dist/cjs/modules/temporal/calendar.d.ts.map +0 -1
- package/dist/cjs/modules/temporal/calendar.js +0 -151
- package/dist/cjs/modules/temporal/calendar.js.map +0 -1
- package/dist/cjs/modules/temporal/duration.d.ts.map +0 -1
- package/dist/cjs/modules/temporal/duration.js +0 -64
- package/dist/cjs/modules/temporal/duration.js.map +0 -1
- package/dist/cjs/modules/temporal/locale.d.ts.map +0 -1
- package/dist/cjs/modules/temporal/locale.js.map +0 -1
- package/dist/cjs/modules/temporal/pattern.d.ts.map +0 -1
- package/dist/cjs/modules/temporal/pattern.js.map +0 -1
- package/dist/cjs/modules/temporal/tokens.d.ts +0 -78
- package/dist/cjs/modules/temporal/tokens.d.ts.map +0 -1
- package/dist/cjs/modules/temporal/tokens.js +0 -145
- package/dist/cjs/modules/temporal/tokens.js.map +0 -1
- package/dist/esm/modules/temporal/adapters/guards.d.ts +0 -4
- package/dist/esm/modules/temporal/adapters/guards.d.ts.map +0 -1
- package/dist/esm/modules/temporal/adapters/guards.js +0 -10
- package/dist/esm/modules/temporal/adapters/guards.js.map +0 -1
- package/dist/esm/modules/temporal/calendar.d.ts +0 -52
- package/dist/esm/modules/temporal/calendar.d.ts.map +0 -1
- package/dist/esm/modules/temporal/calendar.js +0 -138
- package/dist/esm/modules/temporal/calendar.js.map +0 -1
- package/dist/esm/modules/temporal/duration.d.ts.map +0 -1
- package/dist/esm/modules/temporal/duration.js +0 -60
- package/dist/esm/modules/temporal/duration.js.map +0 -1
- package/dist/esm/modules/temporal/locale.d.ts.map +0 -1
- package/dist/esm/modules/temporal/locale.js.map +0 -1
- package/dist/esm/modules/temporal/pattern.d.ts.map +0 -1
- package/dist/esm/modules/temporal/pattern.js.map +0 -1
- package/dist/esm/modules/temporal/tokens.d.ts +0 -78
- package/dist/esm/modules/temporal/tokens.d.ts.map +0 -1
- package/dist/esm/modules/temporal/tokens.js +0 -133
- 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 {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
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
|
-
|
|
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
|
|
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
|
-
*
|
|
50
|
-
*
|
|
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
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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
|
-
*
|
|
147
|
-
*
|
|
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
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
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
|
-
/**
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
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
|
|
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,
|
|
243
|
-
: epochAtOffset({
|
|
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
|
|
154
|
+
const tz = this.resolveTz({ tz: opts.tz });
|
|
281
155
|
try {
|
|
282
|
-
return this.parse({ ...opts,
|
|
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,
|
|
167
|
+
const { value, pattern, tz } = opts;
|
|
294
168
|
if (typeof value === 'string') {
|
|
295
|
-
return this.tryParse({ value, pattern,
|
|
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
|
|
302
|
-
*
|
|
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.
|
|
308
|
-
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
|
|
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,
|
|
318
|
-
const key = `${locale}|${
|
|
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
|
|
337
|
-
const date = this.toDate({ value: opts.value,
|
|
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({
|
|
346
|
-
|
|
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,
|
|
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
|
|
358
|
-
const date = this.toDate({ value: opts.value,
|
|
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,
|
|
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
|
|
370
|
-
const date = this.toDate({ value: opts.value,
|
|
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,
|
|
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
|
-
|
|
289
|
+
tz: opts.tz,
|
|
393
290
|
});
|
|
394
|
-
while (!this.isWeekday({ value: candidate,
|
|
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
|
-
|
|
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
|
|
407
|
-
*
|
|
408
|
-
*
|
|
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
|
|
414
|
-
const value = this.toDate({ value: opts.value,
|
|
415
|
-
const other = this.toDate({ value: opts.other,
|
|
416
|
-
|
|
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
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
const
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
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
|
|
408
|
+
const tz = this.resolveTz({ tz: opts.tz });
|
|
464
409
|
const value = unit === undefined
|
|
465
|
-
? this.toDate({ value: opts.value,
|
|
466
|
-
: this.startOf({ value: opts.value, unit,
|
|
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,
|
|
469
|
-
: this.startOf({ value: opts.other, unit,
|
|
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
|
|
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,
|
|
486
|
-
const base = opts.base === undefined ? this.now() : this.toDate({ value: opts.base,
|
|
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,
|
|
499
|
-
other: this.startOf({ value: base, unit,
|
|
443
|
+
value: this.startOf({ value, unit, tz }),
|
|
444
|
+
other: this.startOf({ value: base, unit, tz }),
|
|
500
445
|
unit,
|
|
501
|
-
|
|
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,
|
|
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({
|
|
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
|