@thi.ng/date 2.5.5 → 2.5.7

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/datetime.js CHANGED
@@ -1,330 +1,327 @@
1
1
  import { isNumber } from "@thi.ng/checks/is-number";
2
2
  import { isString } from "@thi.ng/checks/is-string";
3
3
  import { Z2, Z3, Z4 } from "@thi.ng/strings/pad-left";
4
- import { DAY, HOUR, MINUTE, SECOND, } from "./api.js";
4
+ import {
5
+ DAY,
6
+ HOUR,
7
+ MINUTE,
8
+ SECOND
9
+ } from "./api.js";
5
10
  import { ensureDate, ensureEpoch, isLeapYear } from "./checks.js";
6
11
  import { defFormat } from "./format.js";
7
12
  import { LOCALE } from "./i18n.js";
8
13
  import { __precisionToID } from "./internal/precision.js";
9
14
  import { dayInYear, daysInMonth, weekInYear } from "./units.js";
10
- export const dateTime = (epoch, prec) => new DateTime(epoch, prec);
11
- /**
12
- * Epoch abstraction with adjustable coarseness/precision. All date fields in
13
- * UTC only.
14
- */
15
- export class DateTime {
16
- t;
17
- s;
18
- m;
19
- h;
20
- d;
21
- M;
22
- y;
23
- constructor(epoch = Date.now(), prec = "t") {
24
- const x = ensureDate(epoch);
25
- const id = __precisionToID(prec);
26
- this.y = x.getUTCFullYear();
27
- this.M = id >= 1 ? x.getUTCMonth() : 0;
28
- this.d = id >= 2 ? x.getUTCDate() : 1;
29
- this.h = id >= 3 ? x.getUTCHours() : 0;
30
- this.m = id >= 4 ? x.getUTCMinutes() : 0;
31
- this.s = id >= 5 ? x.getUTCSeconds() : 0;
32
- this.t = id >= 6 ? x.getUTCMilliseconds() : 0;
33
- }
34
- /**
35
- * Readonly property, returning 1-based quarter
36
- *
37
- * @remarks
38
- * - 1 = Jan - Mar
39
- * - 2 = Apr - Jun
40
- * - 3 = Jul - Sep
41
- * - 4 = Oct - Dec
42
- */
43
- get q() {
44
- return ((this.M / 3) | 0) + 1;
45
- }
46
- /**
47
- * Alias readonly property, same as {@link DateTime.weekInYear}.
48
- */
49
- get w() {
50
- return this.weekInYear();
51
- }
52
- set(d) {
53
- const $d = ensureDateTime(d);
54
- this.y = $d.y;
55
- this.M = $d.M;
56
- this.d = $d.d;
57
- this.h = $d.h;
58
- this.m = $d.m;
59
- this.s = $d.s;
60
- this.t = $d.t;
61
- return this;
62
- }
63
- copy() {
64
- return new DateTime(this.toISOString());
65
- }
66
- getTime() {
67
- return Date.UTC(this.y, this.M, this.d, this.h, this.m, this.s, this.t);
68
- }
69
- withPrecision(prec) {
70
- return new DateTime(this, prec);
71
- }
72
- setPrecision(prec) {
73
- const precID = __precisionToID(prec);
74
- precID < 6 && (this.t = 0);
75
- precID < 5 && (this.s = 0);
76
- precID < 4 && (this.m = 0);
77
- precID < 3 && (this.h = 0);
78
- precID < 2 && (this.d = 1);
79
- precID < 1 && (this.M = 0);
80
- return this;
81
- }
82
- compare(d) {
83
- return this.getTime() - ensureEpoch(d);
84
- }
85
- /**
86
- * Returns true if this instance is before the given date, i.e. if
87
- * `this.compare(d) < 0`.
88
- *
89
- * @param d -
90
- */
91
- isBefore(d) {
92
- return this.compare(d) < 0;
93
- }
94
- /**
95
- * Returns true if this instance is before the given date, i.e. if
96
- * `this.compare(d) > 0`.
97
- *
98
- * @param d -
99
- */
100
- isAfter(d) {
101
- return this.compare(d) > 0;
102
- }
103
- equiv(o) {
104
- return maybeIsDate(o) ? this.compare(o) === 0 : false;
105
- }
106
- eqDelta(d, eps = 0) {
107
- return Math.abs(this.getTime() - ensureDate(d).getTime()) <= eps;
108
- }
109
- daysInMonth() {
110
- return daysInMonth(this.y, this.M);
111
- }
112
- dayInYear() {
113
- return dayInYear(this.y, this.M, this.d);
114
- }
115
- /**
116
- * Returns week number according to ISO8601.
117
- *
118
- * @remarks
119
- * Reference:
120
- * https://en.wikipedia.org/wiki/Week#The_ISO_week_date_system
121
- *
122
- */
123
- weekInYear() {
124
- return weekInYear(this.y, this.M, this.d);
125
- }
126
- /**
127
- * Leap years are multiple of 4, excludingcentennial years that aren’t
128
- * multiples of 400.
129
- */
130
- isLeapYear() {
131
- return isLeapYear(this.y);
132
- }
133
- incMillisecond() {
134
- if (++this.t > 999) {
135
- this.t = 0;
136
- this.incSecond();
137
- }
138
- return this.t;
139
- }
140
- decMillisecond() {
141
- if (--this.t < 0) {
142
- this.t = 999;
143
- this.decSecond();
144
- }
145
- return this.t;
146
- }
147
- incSecond() {
148
- if (++this.s > 59) {
149
- this.s = 0;
150
- this.incMinute();
151
- }
152
- return this.s;
153
- }
154
- decSecond() {
155
- if (--this.s < 0) {
156
- this.s = 59;
157
- this.decMinute();
158
- }
159
- return this.s;
160
- }
161
- incMinute() {
162
- if (++this.m > 59) {
163
- this.m = 0;
164
- this.incHour();
165
- }
166
- return this.m;
167
- }
168
- decMinute() {
169
- if (--this.m < 0) {
170
- this.m = 59;
171
- this.decHour();
172
- }
173
- return this.m;
174
- }
175
- incHour() {
176
- if (++this.h > 23) {
177
- this.h = 0;
178
- this.incDay();
179
- }
180
- return this.h;
181
- }
182
- decHour() {
183
- if (--this.h < 0) {
184
- this.h = 23;
185
- this.decDay();
186
- }
187
- return this.h;
188
- }
189
- incDay() {
190
- if (++this.d > this.daysInMonth()) {
191
- this.d = 1;
192
- this.incMonth();
193
- }
194
- return this.d;
195
- }
196
- decDay() {
197
- if (--this.d < 1) {
198
- this.decMonth();
199
- this.d = this.daysInMonth();
200
- }
201
- return this.d;
202
- }
203
- incWeek() {
204
- this.d += 7;
205
- const max = this.daysInMonth();
206
- if (this.d > max) {
207
- this.d -= max;
208
- this.incMonth();
209
- }
210
- return this.weekInYear();
211
- }
212
- decWeek() {
213
- this.d -= 7;
214
- if (this.d < 1) {
215
- this.decMonth();
216
- this.d += this.daysInMonth();
217
- }
218
- return this.weekInYear();
219
- }
220
- incMonth() {
221
- if (++this.M > 11) {
222
- this.M = 0;
223
- ++this.y;
224
- }
225
- return this.M;
226
- }
227
- decMonth() {
228
- if (--this.M < 0) {
229
- this.M = 11;
230
- --this.y;
231
- }
232
- return this.M;
233
- }
234
- incQuarter() {
235
- this.M += 3;
236
- if (this.M > 11) {
237
- this.M %= 12;
238
- this.y++;
239
- }
240
- return this.q;
241
- }
242
- decQuarter() {
243
- this.M -= 3;
244
- if (this.M < 0) {
245
- this.M += 12;
246
- this.y--;
247
- }
248
- return this.q;
249
- }
250
- incYear() {
251
- // TODO epoch overflow handling, throw error?
252
- return ++this.y;
253
- }
254
- decYear() {
255
- // TODO epoch underflow handling, throw error?
256
- return --this.y;
257
- }
258
- /**
259
- * Returns a new `DateTime` instance relative to this date, but with given
260
- * period added/subtracted.
261
- *
262
- * @param x -
263
- * @param prec -
264
- */
265
- add(x, prec) {
266
- if (prec === "w")
267
- return this.add(x * 7, "d");
268
- if (prec === "q")
269
- return this.add(x * 3, "M");
270
- const res = this.copy();
271
- const precID = __precisionToID(prec);
272
- if (precID >= 2) {
273
- res.set(res.getTime() + x * [DAY, HOUR, MINUTE, SECOND, 1][precID - 2]);
274
- }
275
- else if (prec === "M") {
276
- const y = (x / 12) | 0;
277
- res.y += y;
278
- x -= y * 12;
279
- const m = res.M + x;
280
- m > 11 && res.y++;
281
- m < 0 && res.y--;
282
- res.M = m % 12;
283
- if (res.M < 0)
284
- res.M += 12;
285
- res.d = Math.min(res.d, res.daysInMonth());
286
- }
287
- else if (prec === "y") {
288
- res.y += x;
289
- }
290
- return res;
291
- }
292
- toDate() {
293
- return new Date(this.toISOString());
294
- }
295
- toJSON() {
296
- return this.toISOString();
297
- }
298
- toString() {
299
- return this.toDate().toUTCString();
300
- }
301
- /**
302
- * Returns formatted version using current {@link LOCALE.dateTime}
303
- * formatter.
304
- *
305
- * @remarks
306
- * The host environment's locale is NOT used. Only the currently active
307
- * `LOCALE` is relevant.
308
- */
309
- toLocaleString() {
310
- return defFormat(LOCALE.dateTime)(this, true);
311
- }
312
- toISOString() {
313
- return `${Z4(this.y)}-${Z2(this.M + 1)}-${Z2(this.d)}T${Z2(this.h)}:${Z2(this.m)}:${Z2(this.s)}.${Z3(this.t)}Z`;
314
- }
315
- valueOf() {
316
- return this.getTime();
317
- }
15
+ const dateTime = (epoch, prec) => new DateTime(epoch, prec);
16
+ class DateTime {
17
+ t;
18
+ s;
19
+ m;
20
+ h;
21
+ d;
22
+ M;
23
+ y;
24
+ constructor(epoch = Date.now(), prec = "t") {
25
+ const x = ensureDate(epoch);
26
+ const id = __precisionToID(prec);
27
+ this.y = x.getUTCFullYear();
28
+ this.M = id >= 1 ? x.getUTCMonth() : 0;
29
+ this.d = id >= 2 ? x.getUTCDate() : 1;
30
+ this.h = id >= 3 ? x.getUTCHours() : 0;
31
+ this.m = id >= 4 ? x.getUTCMinutes() : 0;
32
+ this.s = id >= 5 ? x.getUTCSeconds() : 0;
33
+ this.t = id >= 6 ? x.getUTCMilliseconds() : 0;
34
+ }
35
+ /**
36
+ * Readonly property, returning 1-based quarter
37
+ *
38
+ * @remarks
39
+ * - 1 = Jan - Mar
40
+ * - 2 = Apr - Jun
41
+ * - 3 = Jul - Sep
42
+ * - 4 = Oct - Dec
43
+ */
44
+ get q() {
45
+ return (this.M / 3 | 0) + 1;
46
+ }
47
+ /**
48
+ * Alias readonly property, same as {@link DateTime.weekInYear}.
49
+ */
50
+ get w() {
51
+ return this.weekInYear();
52
+ }
53
+ set(d) {
54
+ const $d = ensureDateTime(d);
55
+ this.y = $d.y;
56
+ this.M = $d.M;
57
+ this.d = $d.d;
58
+ this.h = $d.h;
59
+ this.m = $d.m;
60
+ this.s = $d.s;
61
+ this.t = $d.t;
62
+ return this;
63
+ }
64
+ copy() {
65
+ return new DateTime(this.toISOString());
66
+ }
67
+ getTime() {
68
+ return Date.UTC(this.y, this.M, this.d, this.h, this.m, this.s, this.t);
69
+ }
70
+ withPrecision(prec) {
71
+ return new DateTime(this, prec);
72
+ }
73
+ setPrecision(prec) {
74
+ const precID = __precisionToID(prec);
75
+ precID < 6 && (this.t = 0);
76
+ precID < 5 && (this.s = 0);
77
+ precID < 4 && (this.m = 0);
78
+ precID < 3 && (this.h = 0);
79
+ precID < 2 && (this.d = 1);
80
+ precID < 1 && (this.M = 0);
81
+ return this;
82
+ }
83
+ compare(d) {
84
+ return this.getTime() - ensureEpoch(d);
85
+ }
86
+ /**
87
+ * Returns true if this instance is before the given date, i.e. if
88
+ * `this.compare(d) < 0`.
89
+ *
90
+ * @param d -
91
+ */
92
+ isBefore(d) {
93
+ return this.compare(d) < 0;
94
+ }
95
+ /**
96
+ * Returns true if this instance is before the given date, i.e. if
97
+ * `this.compare(d) > 0`.
98
+ *
99
+ * @param d -
100
+ */
101
+ isAfter(d) {
102
+ return this.compare(d) > 0;
103
+ }
104
+ equiv(o) {
105
+ return maybeIsDate(o) ? this.compare(o) === 0 : false;
106
+ }
107
+ eqDelta(d, eps = 0) {
108
+ return Math.abs(this.getTime() - ensureDate(d).getTime()) <= eps;
109
+ }
110
+ daysInMonth() {
111
+ return daysInMonth(this.y, this.M);
112
+ }
113
+ dayInYear() {
114
+ return dayInYear(this.y, this.M, this.d);
115
+ }
116
+ /**
117
+ * Returns week number according to ISO8601.
118
+ *
119
+ * @remarks
120
+ * Reference:
121
+ * https://en.wikipedia.org/wiki/Week#The_ISO_week_date_system
122
+ *
123
+ */
124
+ weekInYear() {
125
+ return weekInYear(this.y, this.M, this.d);
126
+ }
127
+ /**
128
+ * Leap years are multiple of 4, excludingcentennial years that aren’t
129
+ * multiples of 400.
130
+ */
131
+ isLeapYear() {
132
+ return isLeapYear(this.y);
133
+ }
134
+ incMillisecond() {
135
+ if (++this.t > 999) {
136
+ this.t = 0;
137
+ this.incSecond();
138
+ }
139
+ return this.t;
140
+ }
141
+ decMillisecond() {
142
+ if (--this.t < 0) {
143
+ this.t = 999;
144
+ this.decSecond();
145
+ }
146
+ return this.t;
147
+ }
148
+ incSecond() {
149
+ if (++this.s > 59) {
150
+ this.s = 0;
151
+ this.incMinute();
152
+ }
153
+ return this.s;
154
+ }
155
+ decSecond() {
156
+ if (--this.s < 0) {
157
+ this.s = 59;
158
+ this.decMinute();
159
+ }
160
+ return this.s;
161
+ }
162
+ incMinute() {
163
+ if (++this.m > 59) {
164
+ this.m = 0;
165
+ this.incHour();
166
+ }
167
+ return this.m;
168
+ }
169
+ decMinute() {
170
+ if (--this.m < 0) {
171
+ this.m = 59;
172
+ this.decHour();
173
+ }
174
+ return this.m;
175
+ }
176
+ incHour() {
177
+ if (++this.h > 23) {
178
+ this.h = 0;
179
+ this.incDay();
180
+ }
181
+ return this.h;
182
+ }
183
+ decHour() {
184
+ if (--this.h < 0) {
185
+ this.h = 23;
186
+ this.decDay();
187
+ }
188
+ return this.h;
189
+ }
190
+ incDay() {
191
+ if (++this.d > this.daysInMonth()) {
192
+ this.d = 1;
193
+ this.incMonth();
194
+ }
195
+ return this.d;
196
+ }
197
+ decDay() {
198
+ if (--this.d < 1) {
199
+ this.decMonth();
200
+ this.d = this.daysInMonth();
201
+ }
202
+ return this.d;
203
+ }
204
+ incWeek() {
205
+ this.d += 7;
206
+ const max = this.daysInMonth();
207
+ if (this.d > max) {
208
+ this.d -= max;
209
+ this.incMonth();
210
+ }
211
+ return this.weekInYear();
212
+ }
213
+ decWeek() {
214
+ this.d -= 7;
215
+ if (this.d < 1) {
216
+ this.decMonth();
217
+ this.d += this.daysInMonth();
218
+ }
219
+ return this.weekInYear();
220
+ }
221
+ incMonth() {
222
+ if (++this.M > 11) {
223
+ this.M = 0;
224
+ ++this.y;
225
+ }
226
+ return this.M;
227
+ }
228
+ decMonth() {
229
+ if (--this.M < 0) {
230
+ this.M = 11;
231
+ --this.y;
232
+ }
233
+ return this.M;
234
+ }
235
+ incQuarter() {
236
+ this.M += 3;
237
+ if (this.M > 11) {
238
+ this.M %= 12;
239
+ this.y++;
240
+ }
241
+ return this.q;
242
+ }
243
+ decQuarter() {
244
+ this.M -= 3;
245
+ if (this.M < 0) {
246
+ this.M += 12;
247
+ this.y--;
248
+ }
249
+ return this.q;
250
+ }
251
+ incYear() {
252
+ return ++this.y;
253
+ }
254
+ decYear() {
255
+ return --this.y;
256
+ }
257
+ /**
258
+ * Returns a new `DateTime` instance relative to this date, but with given
259
+ * period added/subtracted.
260
+ *
261
+ * @param x -
262
+ * @param prec -
263
+ */
264
+ add(x, prec) {
265
+ if (prec === "w")
266
+ return this.add(x * 7, "d");
267
+ if (prec === "q")
268
+ return this.add(x * 3, "M");
269
+ const res = this.copy();
270
+ const precID = __precisionToID(prec);
271
+ if (precID >= 2) {
272
+ res.set(
273
+ res.getTime() + x * [DAY, HOUR, MINUTE, SECOND, 1][precID - 2]
274
+ );
275
+ } else if (prec === "M") {
276
+ const y = x / 12 | 0;
277
+ res.y += y;
278
+ x -= y * 12;
279
+ const m = res.M + x;
280
+ m > 11 && res.y++;
281
+ m < 0 && res.y--;
282
+ res.M = m % 12;
283
+ if (res.M < 0)
284
+ res.M += 12;
285
+ res.d = Math.min(res.d, res.daysInMonth());
286
+ } else if (prec === "y") {
287
+ res.y += x;
288
+ }
289
+ return res;
290
+ }
291
+ toDate() {
292
+ return new Date(this.toISOString());
293
+ }
294
+ toJSON() {
295
+ return this.toISOString();
296
+ }
297
+ toString() {
298
+ return this.toDate().toUTCString();
299
+ }
300
+ /**
301
+ * Returns formatted version using current {@link LOCALE.dateTime}
302
+ * formatter.
303
+ *
304
+ * @remarks
305
+ * The host environment's locale is NOT used. Only the currently active
306
+ * `LOCALE` is relevant.
307
+ */
308
+ toLocaleString() {
309
+ return defFormat(LOCALE.dateTime)(this, true);
310
+ }
311
+ toISOString() {
312
+ return `${Z4(this.y)}-${Z2(this.M + 1)}-${Z2(this.d)}T${Z2(
313
+ this.h
314
+ )}:${Z2(this.m)}:${Z2(this.s)}.${Z3(this.t)}Z`;
315
+ }
316
+ valueOf() {
317
+ return this.getTime();
318
+ }
318
319
  }
319
- /**
320
- * Coerces `x` to a {@link DateTime} instance.
321
- *
322
- * @param x -
323
- */
324
- export const ensureDateTime = (x, prec = "t") => x instanceof DateTime ? x : new DateTime(x, prec);
325
- /**
326
- * Returns true if `x` is a {@link MaybeDate}.
327
- *
328
- * @param x -
329
- */
330
- export const maybeIsDate = (x) => x instanceof DateTime || x instanceof Date || isNumber(x) || isString(x);
320
+ const ensureDateTime = (x, prec = "t") => x instanceof DateTime ? x : new DateTime(x, prec);
321
+ const maybeIsDate = (x) => x instanceof DateTime || x instanceof Date || isNumber(x) || isString(x);
322
+ export {
323
+ DateTime,
324
+ dateTime,
325
+ ensureDateTime,
326
+ maybeIsDate
327
+ };