@aglyn/shared-util-timestamp 1.0.0-beta.143
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +76 -0
- package/package.json +34 -0
- package/src/index.d.ts +17 -0
- package/src/index.js +18 -0
- package/src/index.js.map +1 -0
- package/src/lib/timestamp-json.d.ts +53 -0
- package/src/lib/timestamp-json.js +53 -0
- package/src/lib/timestamp-json.js.map +1 -0
- package/src/lib/timestamp.d.ts +242 -0
- package/src/lib/timestamp.js +241 -0
- package/src/lib/timestamp.js.map +1 -0
- package/src/lib/zoned-time.d.ts +133 -0
- package/src/lib/zoned-time.js +302 -0
- package/src/lib/zoned-time.js.map +1 -0
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2022 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* Scientific notation values for decimal precision of time equivalents for
|
|
19
|
+
* conversions when calculating time. Small to big uses a positive exponent and
|
|
20
|
+
* big to small uses a negative exponent.
|
|
21
|
+
* @example
|
|
22
|
+
* `MILLI_TO_SEC` - 1e3 equals 1,000 i.e., 1,000 milliseconds in a second
|
|
23
|
+
* `SEC_TO_MILLI` - 1e-3 equals 0.001 i.e., 1/1,000 of a second is a millisecond
|
|
24
|
+
*/
|
|
25
|
+
export declare enum TimeExchange {
|
|
26
|
+
NANO_TO_MICRO = 1000,
|
|
27
|
+
NANO_TO_MILLI = 1000000,
|
|
28
|
+
NANO_TO_SEC = 1000000000,
|
|
29
|
+
MICRO_TO_NANO = 0.001,
|
|
30
|
+
MICRO_TO_MILLI = 1000,
|
|
31
|
+
MICRO_TO_SEC = 1000000,
|
|
32
|
+
MILLI_TO_NANO = 0.000001,
|
|
33
|
+
MILLI_TO_MICRO = 0.001,
|
|
34
|
+
MILLI_TO_SEC = 1000,
|
|
35
|
+
SEC_TO_NANO = 1e-9,
|
|
36
|
+
SEC_TO_MICRO = 0.000001,
|
|
37
|
+
SEC_TO_MILLI = 0.001,
|
|
38
|
+
SEC_TO_MIN = 60,
|
|
39
|
+
SEC_TO_HR = 3600,
|
|
40
|
+
SEC_TO_DY = 86400,
|
|
41
|
+
SEC_TO_WK = 604800,
|
|
42
|
+
SEC_TO_MO = 2628000,
|
|
43
|
+
SEC_TO_YR = 31540000,
|
|
44
|
+
MIN_TO_SEC = 0.016667,
|
|
45
|
+
HR_TO_SEC = 0.00027778,
|
|
46
|
+
DY_TO_SEC = 0.000011574,
|
|
47
|
+
WK_TO_SEC = 0.0000016534,
|
|
48
|
+
MO_TO_SEC = 3.8052e-7,
|
|
49
|
+
YR_TO_SEC = 3.171e-8
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* The timestamp shape, declared structurally (AGL-1207).
|
|
53
|
+
*
|
|
54
|
+
* It used to be `extends FirestoreTimestamp`, which dragged the Firestore
|
|
55
|
+
* client in through TYPE space as well as value space. Everything that
|
|
56
|
+
* consumes an `ITimestamp` wants these five members; nothing wanted the SDK
|
|
57
|
+
* class's identity.
|
|
58
|
+
*/
|
|
59
|
+
export interface ITimestamp {
|
|
60
|
+
readonly seconds: number;
|
|
61
|
+
readonly nanoseconds: number;
|
|
62
|
+
toDate(): Date;
|
|
63
|
+
toMillis(): number;
|
|
64
|
+
isEqual(other: ITimestamp): boolean;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* A `Timestamp` represents a point in time independent of any time zone or
|
|
68
|
+
* calendar, represented as seconds and fractions of seconds at nanosecond
|
|
69
|
+
* resolution in UTC Epoch time.
|
|
70
|
+
*
|
|
71
|
+
* It is encoded using the Proleptic Gregorian Calendar which extends the
|
|
72
|
+
* Gregorian calendar backwards to year one. It is encoded assuming all minutes
|
|
73
|
+
* are 60 seconds long, i.e. leap seconds are "smeared" so that no leap second
|
|
74
|
+
* table is needed for interpretation. Range is from 0001-01-01T00:00:00Z to
|
|
75
|
+
* 9999-12-31T23:59:59.999999999Z.
|
|
76
|
+
*
|
|
77
|
+
* Model and logical flow inspired by `@firebase/firestore/lite/timestamp`
|
|
78
|
+
*
|
|
79
|
+
* ## Why it extends `Date` (AGL-1207)
|
|
80
|
+
*
|
|
81
|
+
* It used to extend the Firestore SDK's `Timestamp`. A class `extends` is a
|
|
82
|
+
* hard runtime dependency — not type-only, not tree-shakeable — so every
|
|
83
|
+
* module graph reaching this file loaded the whole Firestore client, and any
|
|
84
|
+
* spec that partially mocked `firebase/firestore` failed at IMPORT time.
|
|
85
|
+
*
|
|
86
|
+
* `Date` is a JS builtin, so extending it costs nothing. Crucially it also
|
|
87
|
+
* keeps every existing write working untouched: Firestore's client validates
|
|
88
|
+
* field values with `instanceof Date` and serialises them from the internal
|
|
89
|
+
* time slot via `getTime()`, so an instance of this class is still written as
|
|
90
|
+
* a real timestamp — not as a map. That was verified against the emulator
|
|
91
|
+
* before this change, including with `valueOf()` overridden below to return a
|
|
92
|
+
* string, which does NOT interfere: the SDK never consults it.
|
|
93
|
+
*
|
|
94
|
+
* A plain custom class would have been rejected outright with
|
|
95
|
+
* `invalid-argument: Unsupported field value`, which is why `Date` and not a
|
|
96
|
+
* bare object is the base.
|
|
97
|
+
*/
|
|
98
|
+
/**
|
|
99
|
+
* `Date` at runtime, with two members hidden from its TYPE.
|
|
100
|
+
*
|
|
101
|
+
* `valueOf()` here returns a zero-padded ordering string, `toJSON()` returns
|
|
102
|
+
* `{seconds, nanoseconds, type}`, and `toString()` returns the
|
|
103
|
+
* `Timestamp(seconds=…, nanoseconds=…)` form — all three deliberate, all three
|
|
104
|
+
* predating this change, and all incompatible with `Date`'s own signatures.
|
|
105
|
+
* TypeScript is right to reject the override; the runtime is perfectly happy.
|
|
106
|
+
*
|
|
107
|
+
* Omitting them from the base type keeps every existing behaviour byte-for-byte
|
|
108
|
+
* rather than quietly changing what `JSON.stringify(timestamp)` or a `<`
|
|
109
|
+
* comparison produces — this change is about removing a dependency, not about
|
|
110
|
+
* altering semantics. `Timestamp` is still `Date` at runtime, so `instanceof
|
|
111
|
+
* Date` holds and Firestore serialises it as a timestamp.
|
|
112
|
+
*/
|
|
113
|
+
declare const TimestampBase: {
|
|
114
|
+
new (milliseconds: number): Omit<Date, "valueOf" | "toJSON" | "toString">;
|
|
115
|
+
};
|
|
116
|
+
export declare class Timestamp extends TimestampBase implements ITimestamp {
|
|
117
|
+
/**
|
|
118
|
+
* The earliest date supported by Google Firestore timestamps
|
|
119
|
+
* (0001-01-01T00:00:00Z).
|
|
120
|
+
*/
|
|
121
|
+
static MIN_SECONDS: number;
|
|
122
|
+
/**
|
|
123
|
+
* The latest date supported by Google Firestore timestamps
|
|
124
|
+
* (9999-12-31T23:59:59Z).
|
|
125
|
+
*/
|
|
126
|
+
static MAX_SECONDS: number;
|
|
127
|
+
/**
|
|
128
|
+
* Creates a new {@link Timestamp}.
|
|
129
|
+
*
|
|
130
|
+
* @param seconds - The number of seconds of UTC time since Unix epoch
|
|
131
|
+
* 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to
|
|
132
|
+
* 9999-12-31T23:59:59Z inclusive.
|
|
133
|
+
* @param nanoseconds - The non-negative fractions of a second at nanosecond
|
|
134
|
+
* resolution. Negative second values with fractions must still have
|
|
135
|
+
* non-negative nanoseconds values that count forward in time. Must be
|
|
136
|
+
* from 0 to 999,999,999 inclusive.
|
|
137
|
+
*/
|
|
138
|
+
/**
|
|
139
|
+
* The number of seconds of UTC time since Unix epoch 1970-01-01T00:00:00Z.
|
|
140
|
+
*/
|
|
141
|
+
readonly seconds: number;
|
|
142
|
+
/**
|
|
143
|
+
* The fractions of a second at nanosecond resolution.
|
|
144
|
+
*
|
|
145
|
+
* Held as its own field rather than derived from `Date`, which is only
|
|
146
|
+
* millisecond-resolution. Reads coming back from Firestore carry real
|
|
147
|
+
* nanoseconds and are the SDK's own class, not this one; nothing in the repo
|
|
148
|
+
* constructs a sub-millisecond value (`new Timestamp(` has no call sites,
|
|
149
|
+
* and `now()`/`fromMillis()`/`fromDate()` are all millisecond-sourced), so
|
|
150
|
+
* the internal slot losing sub-millisecond precision is not reachable today.
|
|
151
|
+
* The field keeps the public shape exact regardless.
|
|
152
|
+
*/
|
|
153
|
+
readonly nanoseconds: number;
|
|
154
|
+
constructor(seconds: number, nanoseconds: number);
|
|
155
|
+
/**
|
|
156
|
+
* Primitive comparator
|
|
157
|
+
* @param left - left operand
|
|
158
|
+
* @param right - right operand
|
|
159
|
+
* @returns -1 if smaller, 0 if equal, 1 if greater
|
|
160
|
+
*/
|
|
161
|
+
static comparator<T>(left: T, right: T): number;
|
|
162
|
+
/**
|
|
163
|
+
* Creates a new {@link Timestamp} with the current date, with millisecond
|
|
164
|
+
* precision.
|
|
165
|
+
*
|
|
166
|
+
* @returns a new {@link Timestamp} representing the current date.
|
|
167
|
+
*/
|
|
168
|
+
static now(): Timestamp;
|
|
169
|
+
/**
|
|
170
|
+
* Creates a new timestamp from the given date.
|
|
171
|
+
*
|
|
172
|
+
* @param date - The date to convert to a {@link Timestamp} instance
|
|
173
|
+
* @returns {@link Timestamp} equivalent as the provided {@link Date}
|
|
174
|
+
*/
|
|
175
|
+
static fromDate(date: Date): ITimestamp;
|
|
176
|
+
/**
|
|
177
|
+
* Creates a new timestamp from the given number of milliseconds, since Unix
|
|
178
|
+
* epoch 1970-01-01T00:00:00Z
|
|
179
|
+
*
|
|
180
|
+
* @param milliseconds - Number of milliseconds
|
|
181
|
+
* @returns New {@link Timestamp} instance from the provided milliseconds
|
|
182
|
+
*/
|
|
183
|
+
static fromMillis(milliseconds: number): Timestamp;
|
|
184
|
+
/**
|
|
185
|
+
* Converts a {@link Timestamp} to a JavaScript {@link Date} object. This
|
|
186
|
+
* conversion causes a loss of precision since `Date` objects only support
|
|
187
|
+
* millisecond precision.
|
|
188
|
+
*
|
|
189
|
+
* @returns JavaScript {@link Date} object representing the same point in time
|
|
190
|
+
* as this {@link Timestamp}, with millisecond precision.
|
|
191
|
+
*/
|
|
192
|
+
toDate(): Date;
|
|
193
|
+
/**
|
|
194
|
+
* Converts a {@link Timestamp} to a numeric timestamp (in milliseconds since
|
|
195
|
+
* epoch). This operation causes a loss of precision.
|
|
196
|
+
*
|
|
197
|
+
* @returns The time corresponding to this {@link Timestamp}, represented as
|
|
198
|
+
* the number of milliseconds since Unix epoch 1970-01-01T00:00:00Z.
|
|
199
|
+
*/
|
|
200
|
+
toMillis(): number;
|
|
201
|
+
/**
|
|
202
|
+
* Returns true if this {@link Timestamp} is equal to the provided one.
|
|
203
|
+
*
|
|
204
|
+
* @param other - The {@link Timestamp} to compare against.
|
|
205
|
+
* @returns true if this {@link Timestamp} is equal to the provided one.
|
|
206
|
+
*/
|
|
207
|
+
isEqual(other: ITimestamp): boolean;
|
|
208
|
+
/**
|
|
209
|
+
* Returns a textual representation of this Timestamp.
|
|
210
|
+
*/
|
|
211
|
+
toString(): string;
|
|
212
|
+
/**
|
|
213
|
+
* Converts this object to a primitive string, which allows Timestamp objects
|
|
214
|
+
* to be compared using the `>`, `<=`, `>=` and `>` operators.
|
|
215
|
+
*
|
|
216
|
+
* This method returns a string of the form <seconds>.<nanoseconds> where
|
|
217
|
+
* <seconds> is translated to have a non-negative value and both <seconds>
|
|
218
|
+
* and <nanoseconds> are left-padded with zeroes to be a consistent length.
|
|
219
|
+
* Strings with this format then have a lexicographical ordering that matches
|
|
220
|
+
* the expected ordering. The <seconds> translation is done to avoid having
|
|
221
|
+
* a leading negative sign (i.e. a leading '-' character) in its string
|
|
222
|
+
* representation, which would affect its lexicographical ordering.
|
|
223
|
+
*/
|
|
224
|
+
valueOf(): string;
|
|
225
|
+
/**
|
|
226
|
+
* Returns a JSON-serializable representation of this Timestamp.
|
|
227
|
+
*/
|
|
228
|
+
toJSON(): {
|
|
229
|
+
seconds: number;
|
|
230
|
+
nanoseconds: number;
|
|
231
|
+
type: string;
|
|
232
|
+
};
|
|
233
|
+
/**
|
|
234
|
+
* Returns the difference of `a` to `b` in seconds unless they are equal, in
|
|
235
|
+
* which case it will compare the difference in nanoseconds
|
|
236
|
+
* @param a - an instance of {@link Timestamp} to compare with {@link b}
|
|
237
|
+
* @param b - an instance of {@link Timestamp} to compare against {@link a}
|
|
238
|
+
*/
|
|
239
|
+
static difference(a: Timestamp, b: Timestamp): number;
|
|
240
|
+
_compareTo(other: ITimestamp): number;
|
|
241
|
+
}
|
|
242
|
+
export default Timestamp;
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2022 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/ /**
|
|
17
|
+
* Scientific notation values for decimal precision of time equivalents for
|
|
18
|
+
* conversions when calculating time. Small to big uses a positive exponent and
|
|
19
|
+
* big to small uses a negative exponent.
|
|
20
|
+
* @example
|
|
21
|
+
* `MILLI_TO_SEC` - 1e3 equals 1,000 i.e., 1,000 milliseconds in a second
|
|
22
|
+
* `SEC_TO_MILLI` - 1e-3 equals 0.001 i.e., 1/1,000 of a second is a millisecond
|
|
23
|
+
*/ // Multiple members intentionally share the same value: base-1000 metric
|
|
24
|
+
// prefix conversions (nano/micro/milli/sec) recur at the same magnitude.
|
|
25
|
+
/* eslint-disable @typescript-eslint/no-duplicate-enum-values */ export var TimeExchange = /*#__PURE__*/ function(TimeExchange) {
|
|
26
|
+
TimeExchange[TimeExchange["NANO_TO_MICRO"] = 1e3] = "NANO_TO_MICRO";
|
|
27
|
+
TimeExchange[TimeExchange["NANO_TO_MILLI"] = 1e6] = "NANO_TO_MILLI";
|
|
28
|
+
TimeExchange[TimeExchange["NANO_TO_SEC"] = 1e9] = "NANO_TO_SEC";
|
|
29
|
+
TimeExchange[TimeExchange["MICRO_TO_NANO"] = 1e-3] = "MICRO_TO_NANO";
|
|
30
|
+
TimeExchange[TimeExchange["MICRO_TO_MILLI"] = 1e3] = "MICRO_TO_MILLI";
|
|
31
|
+
TimeExchange[TimeExchange["MICRO_TO_SEC"] = 1e6] = "MICRO_TO_SEC";
|
|
32
|
+
TimeExchange[TimeExchange["MILLI_TO_NANO"] = 1e-6] = "MILLI_TO_NANO";
|
|
33
|
+
TimeExchange[TimeExchange["MILLI_TO_MICRO"] = 1e-3] = "MILLI_TO_MICRO";
|
|
34
|
+
TimeExchange[TimeExchange["MILLI_TO_SEC"] = 1e3] = "MILLI_TO_SEC";
|
|
35
|
+
TimeExchange[TimeExchange["SEC_TO_NANO"] = 1e-9] = "SEC_TO_NANO";
|
|
36
|
+
TimeExchange[TimeExchange["SEC_TO_MICRO"] = 1e-6] = "SEC_TO_MICRO";
|
|
37
|
+
TimeExchange[TimeExchange["SEC_TO_MILLI"] = 1e-3] = "SEC_TO_MILLI";
|
|
38
|
+
TimeExchange[TimeExchange["SEC_TO_MIN"] = 6e1] = "SEC_TO_MIN";
|
|
39
|
+
TimeExchange[TimeExchange["SEC_TO_HR"] = 3.6e3] = "SEC_TO_HR";
|
|
40
|
+
TimeExchange[TimeExchange["SEC_TO_DY"] = 8.64e4] = "SEC_TO_DY";
|
|
41
|
+
TimeExchange[TimeExchange["SEC_TO_WK"] = 6.048e5] = "SEC_TO_WK";
|
|
42
|
+
TimeExchange[TimeExchange["SEC_TO_MO"] = 2.628e6] = "SEC_TO_MO";
|
|
43
|
+
TimeExchange[TimeExchange["SEC_TO_YR"] = 3.154e7] = "SEC_TO_YR";
|
|
44
|
+
TimeExchange[TimeExchange["MIN_TO_SEC"] = 1.6667e-2] = "MIN_TO_SEC";
|
|
45
|
+
TimeExchange[TimeExchange["HR_TO_SEC"] = 2.7778e-4] = "HR_TO_SEC";
|
|
46
|
+
TimeExchange[TimeExchange["DY_TO_SEC"] = 1.1574e-5] = "DY_TO_SEC";
|
|
47
|
+
TimeExchange[TimeExchange["WK_TO_SEC"] = 1.6534e-6] = "WK_TO_SEC";
|
|
48
|
+
TimeExchange[TimeExchange["MO_TO_SEC"] = 3.8052e-7] = "MO_TO_SEC";
|
|
49
|
+
TimeExchange[TimeExchange["YR_TO_SEC"] = 3.1710e-8] = "YR_TO_SEC";
|
|
50
|
+
return TimeExchange;
|
|
51
|
+
}({});
|
|
52
|
+
/**
|
|
53
|
+
* A `Timestamp` represents a point in time independent of any time zone or
|
|
54
|
+
* calendar, represented as seconds and fractions of seconds at nanosecond
|
|
55
|
+
* resolution in UTC Epoch time.
|
|
56
|
+
*
|
|
57
|
+
* It is encoded using the Proleptic Gregorian Calendar which extends the
|
|
58
|
+
* Gregorian calendar backwards to year one. It is encoded assuming all minutes
|
|
59
|
+
* are 60 seconds long, i.e. leap seconds are "smeared" so that no leap second
|
|
60
|
+
* table is needed for interpretation. Range is from 0001-01-01T00:00:00Z to
|
|
61
|
+
* 9999-12-31T23:59:59.999999999Z.
|
|
62
|
+
*
|
|
63
|
+
* Model and logical flow inspired by `@firebase/firestore/lite/timestamp`
|
|
64
|
+
*
|
|
65
|
+
* ## Why it extends `Date` (AGL-1207)
|
|
66
|
+
*
|
|
67
|
+
* It used to extend the Firestore SDK's `Timestamp`. A class `extends` is a
|
|
68
|
+
* hard runtime dependency — not type-only, not tree-shakeable — so every
|
|
69
|
+
* module graph reaching this file loaded the whole Firestore client, and any
|
|
70
|
+
* spec that partially mocked `firebase/firestore` failed at IMPORT time.
|
|
71
|
+
*
|
|
72
|
+
* `Date` is a JS builtin, so extending it costs nothing. Crucially it also
|
|
73
|
+
* keeps every existing write working untouched: Firestore's client validates
|
|
74
|
+
* field values with `instanceof Date` and serialises them from the internal
|
|
75
|
+
* time slot via `getTime()`, so an instance of this class is still written as
|
|
76
|
+
* a real timestamp — not as a map. That was verified against the emulator
|
|
77
|
+
* before this change, including with `valueOf()` overridden below to return a
|
|
78
|
+
* string, which does NOT interfere: the SDK never consults it.
|
|
79
|
+
*
|
|
80
|
+
* A plain custom class would have been rejected outright with
|
|
81
|
+
* `invalid-argument: Unsupported field value`, which is why `Date` and not a
|
|
82
|
+
* bare object is the base.
|
|
83
|
+
*/ /**
|
|
84
|
+
* `Date` at runtime, with two members hidden from its TYPE.
|
|
85
|
+
*
|
|
86
|
+
* `valueOf()` here returns a zero-padded ordering string, `toJSON()` returns
|
|
87
|
+
* `{seconds, nanoseconds, type}`, and `toString()` returns the
|
|
88
|
+
* `Timestamp(seconds=…, nanoseconds=…)` form — all three deliberate, all three
|
|
89
|
+
* predating this change, and all incompatible with `Date`'s own signatures.
|
|
90
|
+
* TypeScript is right to reject the override; the runtime is perfectly happy.
|
|
91
|
+
*
|
|
92
|
+
* Omitting them from the base type keeps every existing behaviour byte-for-byte
|
|
93
|
+
* rather than quietly changing what `JSON.stringify(timestamp)` or a `<`
|
|
94
|
+
* comparison produces — this change is about removing a dependency, not about
|
|
95
|
+
* altering semantics. `Timestamp` is still `Date` at runtime, so `instanceof
|
|
96
|
+
* Date` holds and Firestore serialises it as a timestamp.
|
|
97
|
+
*/ const TimestampBase = Date;
|
|
98
|
+
export class Timestamp extends TimestampBase {
|
|
99
|
+
/**
|
|
100
|
+
* Primitive comparator
|
|
101
|
+
* @param left - left operand
|
|
102
|
+
* @param right - right operand
|
|
103
|
+
* @returns -1 if smaller, 0 if equal, 1 if greater
|
|
104
|
+
*/ static comparator(left, right) {
|
|
105
|
+
return left < right ? -1 : left > right ? 1 : 0;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Creates a new {@link Timestamp} with the current date, with millisecond
|
|
109
|
+
* precision.
|
|
110
|
+
*
|
|
111
|
+
* @returns a new {@link Timestamp} representing the current date.
|
|
112
|
+
*/ static now() {
|
|
113
|
+
return this.fromMillis(Date.now());
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Creates a new timestamp from the given date.
|
|
117
|
+
*
|
|
118
|
+
* @param date - The date to convert to a {@link Timestamp} instance
|
|
119
|
+
* @returns {@link Timestamp} equivalent as the provided {@link Date}
|
|
120
|
+
*/ static fromDate(date) {
|
|
121
|
+
return this.fromMillis(date.getTime());
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Creates a new timestamp from the given number of milliseconds, since Unix
|
|
125
|
+
* epoch 1970-01-01T00:00:00Z
|
|
126
|
+
*
|
|
127
|
+
* @param milliseconds - Number of milliseconds
|
|
128
|
+
* @returns New {@link Timestamp} instance from the provided milliseconds
|
|
129
|
+
*/ static fromMillis(milliseconds) {
|
|
130
|
+
const seconds = Math.floor(milliseconds / 1e3);
|
|
131
|
+
const nanoseconds = Math.floor((milliseconds - seconds * 1e3) * 1e6);
|
|
132
|
+
return new this(seconds, nanoseconds);
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Converts a {@link Timestamp} to a JavaScript {@link Date} object. This
|
|
136
|
+
* conversion causes a loss of precision since `Date` objects only support
|
|
137
|
+
* millisecond precision.
|
|
138
|
+
*
|
|
139
|
+
* @returns JavaScript {@link Date} object representing the same point in time
|
|
140
|
+
* as this {@link Timestamp}, with millisecond precision.
|
|
141
|
+
*/ toDate() {
|
|
142
|
+
return new Date(this.toMillis());
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Converts a {@link Timestamp} to a numeric timestamp (in milliseconds since
|
|
146
|
+
* epoch). This operation causes a loss of precision.
|
|
147
|
+
*
|
|
148
|
+
* @returns The time corresponding to this {@link Timestamp}, represented as
|
|
149
|
+
* the number of milliseconds since Unix epoch 1970-01-01T00:00:00Z.
|
|
150
|
+
*/ toMillis() {
|
|
151
|
+
return this.seconds * 1e3 + this.nanoseconds / 1e6;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Returns true if this {@link Timestamp} is equal to the provided one.
|
|
155
|
+
*
|
|
156
|
+
* @param other - The {@link Timestamp} to compare against.
|
|
157
|
+
* @returns true if this {@link Timestamp} is equal to the provided one.
|
|
158
|
+
*/ isEqual(other) {
|
|
159
|
+
return other.seconds === this.seconds && other.nanoseconds === this.nanoseconds;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Returns a textual representation of this Timestamp.
|
|
163
|
+
*/ toString() {
|
|
164
|
+
return `Timestamp(seconds=${this.seconds}, nanoseconds=${this.nanoseconds})`;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Converts this object to a primitive string, which allows Timestamp objects
|
|
168
|
+
* to be compared using the `>`, `<=`, `>=` and `>` operators.
|
|
169
|
+
*
|
|
170
|
+
* This method returns a string of the form <seconds>.<nanoseconds> where
|
|
171
|
+
* <seconds> is translated to have a non-negative value and both <seconds>
|
|
172
|
+
* and <nanoseconds> are left-padded with zeroes to be a consistent length.
|
|
173
|
+
* Strings with this format then have a lexicographical ordering that matches
|
|
174
|
+
* the expected ordering. The <seconds> translation is done to avoid having
|
|
175
|
+
* a leading negative sign (i.e. a leading '-' character) in its string
|
|
176
|
+
* representation, which would affect its lexicographical ordering.
|
|
177
|
+
*/ valueOf() {
|
|
178
|
+
const adjustedSeconds = this.seconds - Timestamp.MIN_SECONDS;
|
|
179
|
+
// Note: Up to 12 decimal digits are required to represent all valid
|
|
180
|
+
// 'seconds' values.
|
|
181
|
+
const formattedSeconds = String(adjustedSeconds).padStart(12, '0');
|
|
182
|
+
const formattedNanoseconds = String(this.nanoseconds).padStart(9, '0');
|
|
183
|
+
return formattedSeconds + '.' + formattedNanoseconds;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Returns a JSON-serializable representation of this Timestamp.
|
|
187
|
+
*/ toJSON() {
|
|
188
|
+
return {
|
|
189
|
+
seconds: this.seconds,
|
|
190
|
+
nanoseconds: this.nanoseconds,
|
|
191
|
+
type: 'firestore/timestamp/1.0'
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Returns the difference of `a` to `b` in seconds unless they are equal, in
|
|
196
|
+
* which case it will compare the difference in nanoseconds
|
|
197
|
+
* @param a - an instance of {@link Timestamp} to compare with {@link b}
|
|
198
|
+
* @param b - an instance of {@link Timestamp} to compare against {@link a}
|
|
199
|
+
*/ static difference(a, b) {
|
|
200
|
+
return a._compareTo(b);
|
|
201
|
+
}
|
|
202
|
+
_compareTo(other) {
|
|
203
|
+
if (this.seconds === other.seconds) {
|
|
204
|
+
return Timestamp.comparator(this.nanoseconds, other.nanoseconds);
|
|
205
|
+
}
|
|
206
|
+
return Timestamp.comparator(this.seconds, other.seconds);
|
|
207
|
+
}
|
|
208
|
+
constructor(seconds, nanoseconds){
|
|
209
|
+
// Validation runs BEFORE `super()`, which is legal because it reads only
|
|
210
|
+
// the parameters and never `this`. Order matters: seeding Date with an
|
|
211
|
+
// out-of-range value would otherwise produce an Invalid Date before the
|
|
212
|
+
// error that explains why.
|
|
213
|
+
if (nanoseconds < 0) {
|
|
214
|
+
throw new Error('invalid-argument: timestamp nanoseconds out of range: ' + nanoseconds);
|
|
215
|
+
}
|
|
216
|
+
if (nanoseconds >= 1e9) {
|
|
217
|
+
throw new Error('invalid-argument: timestamp nanoseconds out of range: ' + nanoseconds);
|
|
218
|
+
}
|
|
219
|
+
if (seconds < Timestamp.MIN_SECONDS) {
|
|
220
|
+
throw new Error('invalid-argument: timestamp seconds out of range: ' + seconds);
|
|
221
|
+
}
|
|
222
|
+
// This will break in the year 10,000.
|
|
223
|
+
if (seconds > Timestamp.MAX_SECONDS) {
|
|
224
|
+
throw new Error('invalid-argument: timestamp seconds out of range: ' + seconds);
|
|
225
|
+
}
|
|
226
|
+
super(seconds * 1e3 + nanoseconds / 1e6);
|
|
227
|
+
this.seconds = seconds;
|
|
228
|
+
this.nanoseconds = nanoseconds;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* The earliest date supported by Google Firestore timestamps
|
|
233
|
+
* (0001-01-01T00:00:00Z).
|
|
234
|
+
*/ Timestamp.MIN_SECONDS = -62135596800;
|
|
235
|
+
/**
|
|
236
|
+
* The latest date supported by Google Firestore timestamps
|
|
237
|
+
* (9999-12-31T23:59:59Z).
|
|
238
|
+
*/ Timestamp.MAX_SECONDS = 253402322399;
|
|
239
|
+
export default Timestamp;
|
|
240
|
+
|
|
241
|
+
//# sourceMappingURL=timestamp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/shared/util/timestamp/src/lib/timestamp.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2022 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\n/**\n * Scientific notation values for decimal precision of time equivalents for\n * conversions when calculating time. Small to big uses a positive exponent and\n * big to small uses a negative exponent.\n * @example\n * `MILLI_TO_SEC` - 1e3 equals 1,000 i.e., 1,000 milliseconds in a second\n * `SEC_TO_MILLI` - 1e-3 equals 0.001 i.e., 1/1,000 of a second is a millisecond\n */\n// Multiple members intentionally share the same value: base-1000 metric\n// prefix conversions (nano/micro/milli/sec) recur at the same magnitude.\n/* eslint-disable @typescript-eslint/no-duplicate-enum-values */\nexport enum TimeExchange {\n NANO_TO_MICRO = 1e3,\n NANO_TO_MILLI = 1e6,\n NANO_TO_SEC = 1e9,\n MICRO_TO_NANO = 1e-3,\n MICRO_TO_MILLI = 1e3,\n MICRO_TO_SEC = 1e6,\n MILLI_TO_NANO = 1e-6,\n MILLI_TO_MICRO = 1e-3,\n MILLI_TO_SEC = 1e3,\n SEC_TO_NANO = 1e-9,\n SEC_TO_MICRO = 1e-6,\n SEC_TO_MILLI = 1e-3,\n SEC_TO_MIN = 6e1,\n SEC_TO_HR = 3.6e3,\n SEC_TO_DY = 8.64e4,\n SEC_TO_WK = 6.048e5,\n SEC_TO_MO = 2.628e6,\n SEC_TO_YR = 3.154e7,\n MIN_TO_SEC = 1.6667e-2,\n HR_TO_SEC = 2.7778e-4,\n DY_TO_SEC = 1.1574e-5,\n WK_TO_SEC = 1.6534e-6,\n MO_TO_SEC = 3.8052e-7,\n YR_TO_SEC = 3.1710e-8,\n}\n/* eslint-enable @typescript-eslint/no-duplicate-enum-values */\n\n/**\n * The timestamp shape, declared structurally (AGL-1207).\n *\n * It used to be `extends FirestoreTimestamp`, which dragged the Firestore\n * client in through TYPE space as well as value space. Everything that\n * consumes an `ITimestamp` wants these five members; nothing wanted the SDK\n * class's identity.\n */\nexport interface ITimestamp {\n readonly seconds: number\n readonly nanoseconds: number\n toDate(): Date\n toMillis(): number\n isEqual(other: ITimestamp): boolean\n}\n\n/**\n * A `Timestamp` represents a point in time independent of any time zone or\n * calendar, represented as seconds and fractions of seconds at nanosecond\n * resolution in UTC Epoch time.\n *\n * It is encoded using the Proleptic Gregorian Calendar which extends the\n * Gregorian calendar backwards to year one. It is encoded assuming all minutes\n * are 60 seconds long, i.e. leap seconds are \"smeared\" so that no leap second\n * table is needed for interpretation. Range is from 0001-01-01T00:00:00Z to\n * 9999-12-31T23:59:59.999999999Z.\n *\n * Model and logical flow inspired by `@firebase/firestore/lite/timestamp`\n *\n * ## Why it extends `Date` (AGL-1207)\n *\n * It used to extend the Firestore SDK's `Timestamp`. A class `extends` is a\n * hard runtime dependency — not type-only, not tree-shakeable — so every\n * module graph reaching this file loaded the whole Firestore client, and any\n * spec that partially mocked `firebase/firestore` failed at IMPORT time.\n *\n * `Date` is a JS builtin, so extending it costs nothing. Crucially it also\n * keeps every existing write working untouched: Firestore's client validates\n * field values with `instanceof Date` and serialises them from the internal\n * time slot via `getTime()`, so an instance of this class is still written as\n * a real timestamp — not as a map. That was verified against the emulator\n * before this change, including with `valueOf()` overridden below to return a\n * string, which does NOT interfere: the SDK never consults it.\n *\n * A plain custom class would have been rejected outright with\n * `invalid-argument: Unsupported field value`, which is why `Date` and not a\n * bare object is the base.\n */\n/**\n * `Date` at runtime, with two members hidden from its TYPE.\n *\n * `valueOf()` here returns a zero-padded ordering string, `toJSON()` returns\n * `{seconds, nanoseconds, type}`, and `toString()` returns the\n * `Timestamp(seconds=…, nanoseconds=…)` form — all three deliberate, all three\n * predating this change, and all incompatible with `Date`'s own signatures.\n * TypeScript is right to reject the override; the runtime is perfectly happy.\n *\n * Omitting them from the base type keeps every existing behaviour byte-for-byte\n * rather than quietly changing what `JSON.stringify(timestamp)` or a `<`\n * comparison produces — this change is about removing a dependency, not about\n * altering semantics. `Timestamp` is still `Date` at runtime, so `instanceof\n * Date` holds and Firestore serialises it as a timestamp.\n */\nconst TimestampBase = Date as unknown as {\n new (milliseconds: number): Omit<Date, 'valueOf' | 'toJSON' | 'toString'>\n}\n\nexport class Timestamp extends TimestampBase implements ITimestamp {\n /**\n * The earliest date supported by Google Firestore timestamps\n * (0001-01-01T00:00:00Z).\n */\n public static MIN_SECONDS = -62135596800\n\n /**\n * The latest date supported by Google Firestore timestamps\n * (9999-12-31T23:59:59Z).\n */\n public static MAX_SECONDS = 253402322399\n\n /**\n * Creates a new {@link Timestamp}.\n *\n * @param seconds - The number of seconds of UTC time since Unix epoch\n * 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to\n * 9999-12-31T23:59:59Z inclusive.\n * @param nanoseconds - The non-negative fractions of a second at nanosecond\n * resolution. Negative second values with fractions must still have\n * non-negative nanoseconds values that count forward in time. Must be\n * from 0 to 999,999,999 inclusive.\n */\n /**\n * The number of seconds of UTC time since Unix epoch 1970-01-01T00:00:00Z.\n */\n readonly seconds: number\n /**\n * The fractions of a second at nanosecond resolution.\n *\n * Held as its own field rather than derived from `Date`, which is only\n * millisecond-resolution. Reads coming back from Firestore carry real\n * nanoseconds and are the SDK's own class, not this one; nothing in the repo\n * constructs a sub-millisecond value (`new Timestamp(` has no call sites,\n * and `now()`/`fromMillis()`/`fromDate()` are all millisecond-sourced), so\n * the internal slot losing sub-millisecond precision is not reachable today.\n * The field keeps the public shape exact regardless.\n */\n readonly nanoseconds: number\n\n constructor(seconds: number, nanoseconds: number) {\n // Validation runs BEFORE `super()`, which is legal because it reads only\n // the parameters and never `this`. Order matters: seeding Date with an\n // out-of-range value would otherwise produce an Invalid Date before the\n // error that explains why.\n if (nanoseconds < 0) {\n throw new Error(\n 'invalid-argument: timestamp nanoseconds out of range: ' + nanoseconds,\n )\n }\n if (nanoseconds >= 1e9) {\n throw new Error(\n 'invalid-argument: timestamp nanoseconds out of range: ' + nanoseconds,\n )\n }\n if (seconds < Timestamp.MIN_SECONDS) {\n throw new Error(\n 'invalid-argument: timestamp seconds out of range: ' + seconds,\n )\n }\n // This will break in the year 10,000.\n if (seconds > Timestamp.MAX_SECONDS) {\n throw new Error(\n 'invalid-argument: timestamp seconds out of range: ' + seconds,\n )\n }\n super(seconds * TimeExchange.MILLI_TO_SEC + nanoseconds / TimeExchange.NANO_TO_MILLI)\n this.seconds = seconds\n this.nanoseconds = nanoseconds\n }\n\n /**\n * Primitive comparator\n * @param left - left operand\n * @param right - right operand\n * @returns -1 if smaller, 0 if equal, 1 if greater\n */\n public static comparator<T>(left: T, right: T): number {\n return left < right ? -1 : left > right ? 1 : 0\n }\n\n /**\n * Creates a new {@link Timestamp} with the current date, with millisecond\n * precision.\n *\n * @returns a new {@link Timestamp} representing the current date.\n */\n public static now(): Timestamp {\n return this.fromMillis(Date.now())\n }\n\n /**\n * Creates a new timestamp from the given date.\n *\n * @param date - The date to convert to a {@link Timestamp} instance\n * @returns {@link Timestamp} equivalent as the provided {@link Date}\n */\n public static fromDate(date: Date): ITimestamp {\n return this.fromMillis(date.getTime())\n }\n\n /**\n * Creates a new timestamp from the given number of milliseconds, since Unix\n * epoch 1970-01-01T00:00:00Z\n *\n * @param milliseconds - Number of milliseconds\n * @returns New {@link Timestamp} instance from the provided milliseconds\n */\n public static fromMillis(milliseconds: number): Timestamp {\n const seconds = Math.floor(milliseconds / TimeExchange.MILLI_TO_SEC)\n const nanoseconds = Math.floor(\n (milliseconds - seconds * TimeExchange.MILLI_TO_SEC) *\n TimeExchange.NANO_TO_MILLI,\n )\n return new this(seconds, nanoseconds)\n }\n\n /**\n * Converts a {@link Timestamp} to a JavaScript {@link Date} object. This\n * conversion causes a loss of precision since `Date` objects only support\n * millisecond precision.\n *\n * @returns JavaScript {@link Date} object representing the same point in time\n * as this {@link Timestamp}, with millisecond precision.\n */\n public toDate(): Date {\n return new Date(this.toMillis())\n }\n\n /**\n * Converts a {@link Timestamp} to a numeric timestamp (in milliseconds since\n * epoch). This operation causes a loss of precision.\n *\n * @returns The time corresponding to this {@link Timestamp}, represented as\n * the number of milliseconds since Unix epoch 1970-01-01T00:00:00Z.\n */\n public toMillis(): number {\n return (\n this.seconds * TimeExchange.MILLI_TO_SEC +\n this.nanoseconds / TimeExchange.NANO_TO_MILLI\n )\n }\n\n /**\n * Returns true if this {@link Timestamp} is equal to the provided one.\n *\n * @param other - The {@link Timestamp} to compare against.\n * @returns true if this {@link Timestamp} is equal to the provided one.\n */\n public isEqual(other: ITimestamp): boolean {\n return (\n other.seconds === this.seconds && other.nanoseconds === this.nanoseconds\n )\n }\n\n /**\n * Returns a textual representation of this Timestamp.\n */\n public toString(): string {\n return `Timestamp(seconds=${this.seconds}, nanoseconds=${this.nanoseconds})`\n }\n\n /**\n * Converts this object to a primitive string, which allows Timestamp objects\n * to be compared using the `>`, `<=`, `>=` and `>` operators.\n *\n * This method returns a string of the form <seconds>.<nanoseconds> where\n * <seconds> is translated to have a non-negative value and both <seconds>\n * and <nanoseconds> are left-padded with zeroes to be a consistent length.\n * Strings with this format then have a lexicographical ordering that matches\n * the expected ordering. The <seconds> translation is done to avoid having\n * a leading negative sign (i.e. a leading '-' character) in its string\n * representation, which would affect its lexicographical ordering.\n */\n public valueOf(): string {\n const adjustedSeconds = this.seconds - Timestamp.MIN_SECONDS\n // Note: Up to 12 decimal digits are required to represent all valid\n // 'seconds' values.\n const formattedSeconds = String(adjustedSeconds).padStart(12, '0')\n const formattedNanoseconds = String(this.nanoseconds).padStart(9, '0')\n return formattedSeconds + '.' + formattedNanoseconds\n }\n\n /**\n * Returns a JSON-serializable representation of this Timestamp.\n */\n public toJSON(): { seconds: number; nanoseconds: number; type: string } {\n return {\n seconds: this.seconds,\n nanoseconds: this.nanoseconds,\n type: 'firestore/timestamp/1.0',\n }\n }\n\n /**\n * Returns the difference of `a` to `b` in seconds unless they are equal, in\n * which case it will compare the difference in nanoseconds\n * @param a - an instance of {@link Timestamp} to compare with {@link b}\n * @param b - an instance of {@link Timestamp} to compare against {@link a}\n */\n public static difference(a: Timestamp, b: Timestamp): number {\n return a._compareTo(b)\n }\n\n public _compareTo(other: ITimestamp): number {\n if (this.seconds === other.seconds) {\n return Timestamp.comparator(this.nanoseconds, other.nanoseconds)\n }\n return Timestamp.comparator(this.seconds, other.seconds)\n }\n}\n\nexport default Timestamp\n"],"names":["TimeExchange","TimestampBase","Date","Timestamp","comparator","left","right","now","fromMillis","fromDate","date","getTime","milliseconds","seconds","Math","floor","nanoseconds","toDate","toMillis","isEqual","other","toString","valueOf","adjustedSeconds","MIN_SECONDS","formattedSeconds","String","padStart","formattedNanoseconds","toJSON","type","difference","a","b","_compareTo","Error","MAX_SECONDS"],"mappings":"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"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
/** Minutes in a day: the exclusive end of a window that runs to midnight. */
|
|
18
|
+
export declare const MINUTES_PER_DAY: number;
|
|
19
|
+
/** Monday through Friday, in `Date#getUTCDay` numbering. */
|
|
20
|
+
export declare const MONDAY_TO_FRIDAY: readonly number[];
|
|
21
|
+
/** The calendar fields a wall clock in a zone shows for one instant. */
|
|
22
|
+
export interface ZonedDateTime {
|
|
23
|
+
year: number;
|
|
24
|
+
/** 1 January through 12 December. */
|
|
25
|
+
month: number;
|
|
26
|
+
/** 1 through 31. */
|
|
27
|
+
day: number;
|
|
28
|
+
/** 0 through 23. */
|
|
29
|
+
hour: number;
|
|
30
|
+
minute: number;
|
|
31
|
+
second: number;
|
|
32
|
+
/** 0 Sunday through 6 Saturday. */
|
|
33
|
+
weekday: number;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* A wall time to find the instant of. Fields overflow the way `Date.UTC`
|
|
37
|
+
* lets them — day 32 of a month is the first of the next — so a caller can
|
|
38
|
+
* step a calendar by adding to `day`.
|
|
39
|
+
*/
|
|
40
|
+
export interface ZonedWallTime {
|
|
41
|
+
year: number;
|
|
42
|
+
/** 1 January through 12 December; overflow rolls into the next year. */
|
|
43
|
+
month: number;
|
|
44
|
+
day: number;
|
|
45
|
+
hour?: number;
|
|
46
|
+
minute?: number;
|
|
47
|
+
second?: number;
|
|
48
|
+
}
|
|
49
|
+
/** Whether `Intl` knows the zone, so a stored name can be checked before use. */
|
|
50
|
+
export declare function isValidTimeZone(value: unknown): value is string;
|
|
51
|
+
/**
|
|
52
|
+
* The wall clock in `timeZone` at `atMs`.
|
|
53
|
+
*
|
|
54
|
+
* @throws RangeError for a zone `Intl` does not know, or an instant that is
|
|
55
|
+
* not a finite number.
|
|
56
|
+
*/
|
|
57
|
+
export declare function zonedDateTime(atMs: number, timeZone: string): ZonedDateTime;
|
|
58
|
+
/** `YYYY-MM-DD` of the calendar day `atMs` falls in, in `timeZone`. */
|
|
59
|
+
export declare function zonedDayKey(atMs: number, timeZone: string): string;
|
|
60
|
+
/** The wall clock's minute of the day, `hour * 60 + minute`, 0 through 1439. */
|
|
61
|
+
export declare function zonedMinuteOfDay(atMs: number, timeZone: string): number;
|
|
62
|
+
/** The zone's offset from UTC at `atMs`, in milliseconds, positive east. */
|
|
63
|
+
export declare function zoneOffsetMs(atMs: number, timeZone: string): number;
|
|
64
|
+
/**
|
|
65
|
+
* The instant a wall time happens in `timeZone` — see the module note for
|
|
66
|
+
* the two days a year it is ambiguous. Seconds are whole: a millisecond part
|
|
67
|
+
* of `second` is dropped.
|
|
68
|
+
*/
|
|
69
|
+
export declare function zonedWallTimeToInstant(wall: ZonedWallTime, timeZone: string): number;
|
|
70
|
+
/** Midnight at the start of the calendar day `atMs` falls in, in `timeZone`. */
|
|
71
|
+
export declare function startOfZonedDay(atMs: number, timeZone: string): number;
|
|
72
|
+
/**
|
|
73
|
+
* Midnight at the start of the NEXT calendar day in `timeZone` — built from
|
|
74
|
+
* the calendar rather than by adding 24 hours, because a day a clock change
|
|
75
|
+
* falls in is 23 or 25 hours long.
|
|
76
|
+
*/
|
|
77
|
+
export declare function startOfNextZonedDay(atMs: number, timeZone: string): number;
|
|
78
|
+
/**
|
|
79
|
+
* How many calendar days separate the day `fromMs` falls in from the day
|
|
80
|
+
* `toMs` falls in, in `timeZone`: `0` for the same day, negative when `toMs`
|
|
81
|
+
* is on an earlier one. Counted on the calendar, so a 23-hour day is a day.
|
|
82
|
+
*/
|
|
83
|
+
export declare function zonedCalendarDaysBetween(fromMs: number, toMs: number, timeZone: string): number;
|
|
84
|
+
/**
|
|
85
|
+
* `count` business days after `atMs`, at the same wall-clock time, in
|
|
86
|
+
* `timeZone`.
|
|
87
|
+
*
|
|
88
|
+
* The calendar is walked a day at a time from the day after `atMs`, and each
|
|
89
|
+
* day whose weekday is in `businessDays` counts one. The time of day is the
|
|
90
|
+
* wall time `atMs` showed, so a 10:00 send is followed at 10:00 after a clock
|
|
91
|
+
* change as well; a wall time the destination day skips moves forward with
|
|
92
|
+
* the clock. `0` is `atMs` itself, whatever day that is.
|
|
93
|
+
*
|
|
94
|
+
* No holidays: a calendar that knew some countries' holidays would quietly
|
|
95
|
+
* shorten the wait in every country it did not know.
|
|
96
|
+
*
|
|
97
|
+
* @throws RangeError for a count that is not a whole number of days, or a
|
|
98
|
+
* `businessDays` list with no weekday in it.
|
|
99
|
+
*/
|
|
100
|
+
export declare function addZonedBusinessDays(atMs: number, count: number, timeZone: string, businessDays?: readonly number[]): number;
|
|
101
|
+
/**
|
|
102
|
+
* One open stretch of a day, in minutes after local midnight: `start`
|
|
103
|
+
* inclusive, `end` exclusive, `0 <= start < end <= 1440`.
|
|
104
|
+
*/
|
|
105
|
+
export interface WeeklyInterval {
|
|
106
|
+
start: number;
|
|
107
|
+
end: number;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Open stretches by weekday (`0` Sunday through `6` Saturday), read in one
|
|
111
|
+
* zone. A weekday with no entry is closed.
|
|
112
|
+
*/
|
|
113
|
+
export type WeeklySchedule = Readonly<Partial<Record<number, readonly WeeklyInterval[]>>>;
|
|
114
|
+
/** A stretch of a schedule as instants: `startMs` inclusive, `endMs` exclusive. */
|
|
115
|
+
export interface ZonedInterval {
|
|
116
|
+
startMs: number;
|
|
117
|
+
endMs: number;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* The stretch of `schedule` that contains `atMs`, or else the next one to
|
|
121
|
+
* open after it — `startMs <= atMs` tells the two apart — or `null` when the
|
|
122
|
+
* schedule never opens.
|
|
123
|
+
*
|
|
124
|
+
* Each end of a stretch is placed on the calendar by
|
|
125
|
+
* {@link zonedWallTimeToInstant}, so the day a clock changes is measured as
|
|
126
|
+
* it is lived: 09:00–17:00 is eight hours of wall clock either way, a time
|
|
127
|
+
* the spring gap skips is read the way that function reads it, and a stretch
|
|
128
|
+
* that comes out empty — it starts inside the gap and ends as the gap ends —
|
|
129
|
+
* does not open that day.
|
|
130
|
+
*/
|
|
131
|
+
export declare function nextWeeklyOpening(atMs: number, schedule: WeeklySchedule, timeZone: string): ZonedInterval | null;
|
|
132
|
+
/** Whether `atMs` falls inside an open stretch of `schedule`. */
|
|
133
|
+
export declare function isWithinWeeklySchedule(atMs: number, schedule: WeeklySchedule, timeZone: string): boolean;
|