@nivinjoseph/n-date 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/.editorconfig +14 -0
  2. package/.vscode/launch.json +56 -0
  3. package/.vscode/settings.json +111 -0
  4. package/.vscode/tasks.json +12 -0
  5. package/.yarn/releases/yarn-4.14.1.cjs +940 -0
  6. package/.yarnrc.yml +8 -0
  7. package/LICENSE +21 -0
  8. package/README.md +21 -0
  9. package/dist/date-time-format.d.ts +11 -0
  10. package/dist/date-time-format.d.ts.map +1 -0
  11. package/dist/date-time-format.js +11 -0
  12. package/dist/date-time-format.js.map +1 -0
  13. package/dist/date-time-span.d.ts +70 -0
  14. package/dist/date-time-span.d.ts.map +1 -0
  15. package/dist/date-time-span.js +122 -0
  16. package/dist/date-time-span.js.map +1 -0
  17. package/dist/date-time.d.ts +391 -0
  18. package/dist/date-time.d.ts.map +1 -0
  19. package/dist/date-time.js +753 -0
  20. package/dist/date-time.js.map +1 -0
  21. package/dist/index.d.ts +4 -0
  22. package/dist/index.d.ts.map +1 -0
  23. package/dist/index.js +4 -0
  24. package/dist/index.js.map +1 -0
  25. package/dist/tsconfig.json +13 -0
  26. package/docs/README.md +33 -0
  27. package/docs/date-time-span.md +72 -0
  28. package/docs/date-time.md +169 -0
  29. package/docs/formats.md +56 -0
  30. package/docs/getting-started.md +151 -0
  31. package/eslint.config.js +596 -0
  32. package/package.json +57 -0
  33. package/src/date-time-format.ts +35 -0
  34. package/src/date-time-span.ts +130 -0
  35. package/src/date-time.ts +950 -0
  36. package/src/index.ts +3 -0
  37. package/test/date-time-comparison.test.ts +1579 -0
  38. package/test/date-time-create.test.ts +1147 -0
  39. package/test/date-time-math.test.ts +324 -0
  40. package/test/date-time-properties.test.ts +200 -0
  41. package/test/date-time-utility.test.ts +432 -0
  42. package/test/date-time-validations.test.ts +521 -0
  43. package/tsconfig.json +31 -0
@@ -0,0 +1,432 @@
1
+ import assert from "node:assert";
2
+ import { describe, test } from "node:test";
3
+ import { DateTime } from "../src/index.js";
4
+ import { IANAZone, DateTime as LuxonDateTime } from "luxon";
5
+ import { ArgumentException } from "@nivinjoseph/n-exception";
6
+
7
+
8
+ await describe("DateTime Utility", async () =>
9
+ {
10
+ await describe("Current zone", async () =>
11
+ {
12
+ // FIXME: This test is failing for me because the zone in luxon is undefined.
13
+ // related issue https://github.com/moment/luxon/issues/1516
14
+ await test.skip(`Given current system zone from DateTime
15
+ when it's validated that it's a proper zone
16
+ then it should return true`,
17
+ () =>
18
+ {
19
+ console.log(LuxonDateTime.now());
20
+ console.log("currentZone", DateTime.currentZone, LuxonDateTime.now().zoneName);
21
+ assert.ok(DateTime.validateTimeZone(DateTime.currentZone));
22
+ }
23
+ );
24
+
25
+ await test(`Given current system zone from DateTime
26
+ when it's compared to luxon current system zone
27
+ then it should be same as Luxon local zone`,
28
+ () =>
29
+ {
30
+ assert.strictEqual(LuxonDateTime.now().zoneName, DateTime.currentZone);
31
+ }
32
+ );
33
+ });
34
+
35
+ await describe("Value of", async () =>
36
+ {
37
+ const value = "2024-01-01 10:00";
38
+ const zone = "utc";
39
+ const dateTime = new DateTime({ value: value, zone: zone });
40
+
41
+ await test(`Given a DateTime with value "2024-01-01 10:00" and zone utc
42
+ when it's compared to luxon dateTime representing the same
43
+ then it's valueOf() should be same as Luxon DateTime`,
44
+ () =>
45
+ {
46
+ assert.strictEqual(dateTime.valueOf(), 1704103200000);
47
+ }
48
+ );
49
+
50
+ await test(`Given a DateTime with value "2024-01-01 10:00" and zone utc
51
+ when it's valueOf() is validated with luxon
52
+ then it should return true`,
53
+ () =>
54
+ {
55
+ assert.ok(LuxonDateTime.fromMillis(dateTime.valueOf()).isValid);
56
+ }
57
+ );
58
+
59
+ await test(`Given the value epoch start ("1970-01-01 00:00") in utc
60
+ when DateTime is created from that
61
+ then it should have valueOf() 0`,
62
+ () =>
63
+ {
64
+ assert.strictEqual(new DateTime({ value: "1970-01-01 00:00", zone: "utc" }).valueOf(), 0);
65
+ }
66
+ );
67
+
68
+ await test(`Given a value before epoch start ("1969-12-31 23:59") in utc
69
+ when DateTime is created from that
70
+ then it should have valueOf() negative (-60000)`,
71
+ () =>
72
+ {
73
+ assert.strictEqual(new DateTime({ value: "1969-12-31 23:59", zone: "utc" }).valueOf(), -60000);
74
+ }
75
+ );
76
+
77
+ await test(`Given a value epoch start ("1970-01-01 00:01") in utc
78
+ when DateTime is created from that
79
+ then it should have valueOf() positive (60000)`,
80
+ () =>
81
+ {
82
+ assert.strictEqual(new DateTime({ value: "1970-01-01 00:01", zone: "utc" }).valueOf(), 60000);
83
+ }
84
+ );
85
+ });
86
+
87
+
88
+ await describe("to string", async () =>
89
+ {
90
+ const value = "2024-01-01 10:00:00";
91
+
92
+ await test(`Given a valid value (${value}) and zone (utc)
93
+ when a DateTime is created from that value and zone
94
+ then toString() on that dateTime should return a string with value and zone`,
95
+ () =>
96
+ {
97
+ const zone = "utc";
98
+ const dateTime = new DateTime({ value: value, zone: zone });
99
+ assert.strictEqual(dateTime.toString(), `${value} ${zone}`);
100
+ }
101
+ );
102
+
103
+ await test(`Given a valid value (${value}) and zone (UTC+5:30)
104
+ when a DateTime is created from that value and zone
105
+ then toString() on that dateTime should return a string with value and zone`,
106
+ () =>
107
+ {
108
+ const zone = "UTC+5:30";
109
+ const dateTime = new DateTime({ value: value, zone: zone });
110
+ assert.strictEqual(dateTime.toString(), `${value} ${zone}`);
111
+ }
112
+ );
113
+
114
+ await test(`Given a valid value (${value}) and zone (America/Los_Angeles)
115
+ when a DateTime is created from that value and zone
116
+ then toString() on that dateTime should return a string with value and zone`,
117
+ () =>
118
+ {
119
+ const zone = "America/Los_Angeles";
120
+ const dateTime = new DateTime({ value: value, zone: zone });
121
+ assert.strictEqual(dateTime.toString(), `${value} ${zone}`);
122
+ }
123
+ );
124
+ });
125
+
126
+ await describe("to string date time", async () =>
127
+ {
128
+ const value = "2024-01-01 10:00:00";
129
+
130
+ await test(`Given a valid value (${value}) and zone (utc)
131
+ when a DateTime is created from that value and zone
132
+ then toStringDateTime() on that dateTime should return the passed in value`,
133
+ () =>
134
+ {
135
+ assert.strictEqual(new DateTime({ value, zone: "utc" }).toStringDateTime(), value);
136
+ }
137
+ );
138
+
139
+ const value1 = "2024-02-29 18:30:00";
140
+ await test(`Given a valid value (${value1}) and zone (utc)
141
+ when a DateTime is created from that value and zone
142
+ then toStringDateTime() on that dateTime should return the passed in value`,
143
+ () =>
144
+ {
145
+ assert.strictEqual(new DateTime({ value: value1, zone: "utc" }).toStringDateTime(), value1);
146
+ }
147
+ );
148
+
149
+ const value2 = "1986-08-17 15:57:00";
150
+ await test(`Given a valid value (${value2}) and zone (utc)
151
+ when a DateTime is created from that value and zone
152
+ then toStringDateTime() on that dateTime should return the passed in value`,
153
+ () =>
154
+ {
155
+ assert.strictEqual(new DateTime({ value: value2, zone: "utc" }).toStringDateTime(), value2);
156
+ }
157
+ );
158
+
159
+ await test(`Given a valid value (${value}) in different zone
160
+ when a DateTime is created from that value and zone
161
+ then toStringDateTime() should return the same value for both dateTime`,
162
+ () =>
163
+ {
164
+ const dateTime1 = new DateTime({ value, zone: "UTC+5:30" });
165
+ const dateTime2 = new DateTime({ value, zone: "America/Los_Angeles" });
166
+ assert.strictEqual(dateTime1.toStringDateTime(), dateTime2.toStringDateTime());
167
+ }
168
+ );
169
+ });
170
+
171
+ await describe("to string ISO", async () =>
172
+ {
173
+ const value = "2024-01-01 10:00";
174
+
175
+ await test(`Given a valid value (${value}) and zone (utc)
176
+ when a DateTime is created from that value and zone
177
+ then toStringISO() should return a valid ISO string`,
178
+ () =>
179
+ {
180
+ assert.ok(LuxonDateTime.fromISO(new DateTime({ value, zone: "utc" }).toStringISO()).isValid);
181
+ }
182
+ );
183
+
184
+ await test(`Given a valid value (${value}) and zone (UTC+5:30)
185
+ when a DateTime is created from that value and zone
186
+ then toStringISO() should return a valid ISO string`,
187
+ () =>
188
+ {
189
+ assert.ok(LuxonDateTime.fromISO(new DateTime({ value, zone: "UTC+5:30" }).toStringISO()).isValid);
190
+ }
191
+ );
192
+
193
+ await test(`Given a valid value (${value}) and zone (America/Los_Angeles)
194
+ when a DateTime is created from that value and zone
195
+ then toStringISO() should return a valid ISO string`,
196
+ () =>
197
+ {
198
+ assert.ok(LuxonDateTime.fromISO(new DateTime({ value, zone: "America/Los_Angeles" }).toStringISO()).isValid);
199
+ }
200
+ );
201
+
202
+ await test(`Given a valid value (${value}) and zone (utc)
203
+ when a DateTime is created from that value and zone
204
+ then toStringISO() on that dateTime should return "2024-01-01T10:00:00.000Z"`,
205
+ () =>
206
+ {
207
+ assert.strictEqual(new DateTime({ value, zone: "utc" }).toStringISO(), "2024-01-01T10:00:00.000Z");
208
+ }
209
+ );
210
+
211
+ const value1 = "2024-02-29 18:30";
212
+ await test(`Given a valid value (${value1}) and zone (utc)
213
+ when a DateTime is created from that value and zone
214
+ then toStringDateTime() on that dateTime should return the passed in value`,
215
+ () =>
216
+ {
217
+ assert.strictEqual(new DateTime({ value: value1, zone: "utc" }).toStringISO(), "2024-02-29T18:30:00.000Z");
218
+ }
219
+ );
220
+
221
+ const value2 = "1986-08-17 15:57";
222
+ await test(`Given a valid value (${value2}) and zone (utc)
223
+ when a DateTime is created from that value and zone
224
+ then toStringDateTime() on that dateTime should return the passed in value`,
225
+ () =>
226
+ {
227
+ assert.strictEqual(new DateTime({ value: value2, zone: "utc" }).toStringISO(), "1986-08-17T15:57:00.000Z");
228
+ }
229
+ );
230
+
231
+ await test(`Given a valid value (${value}) and zone (UTC+5:30)
232
+ when a DateTime is created from that value and zone
233
+ then toStringISO() on that dateTime should return "2024-01-01T10:00:00.000+05:30"`,
234
+ () =>
235
+ {
236
+ assert.strictEqual(new DateTime({ value, zone: "UTC+5:30" }).toStringISO(), "2024-01-01T10:00:00.000+05:30");
237
+ }
238
+ );
239
+
240
+ // FIXME: this test will behave differently depending on daylight savings time active state
241
+ const dstUtcOffset = IANAZone.create("America/Los_Angeles").formatOffset(Date.now(), "short"); // for correct offset in DST
242
+ await test(`Given a valid value (${value}) and zone (America/Los_Angeles)
243
+ when a DateTime is created from that value and zone
244
+ then toStringISO() on that dateTime should return "2024-01-01T10:00:00.000${dstUtcOffset}"`,
245
+ () =>
246
+ {
247
+ assert.strictEqual(new DateTime({ value, zone: "America/Los_Angeles" }).toStringISO(), `2024-01-01T10:00:00.000${dstUtcOffset}`);
248
+ }
249
+ );
250
+ });
251
+
252
+ await describe("Get Days of Month", async () =>
253
+ {
254
+ await describe("For 2024 jan",
255
+ async () =>
256
+ {
257
+ const daysOfMonth = new DateTime({ value: "2024-01-01 10:00", zone: "utc" }).getDaysOfMonth();
258
+
259
+ await test(`Given a DateTime object with value in January "2024-01-01 10:00"
260
+ when daysOfMonth is calculated for that DateTime
261
+ then it should return an array of 31 days`,
262
+ () =>
263
+ {
264
+ assert.strictEqual(daysOfMonth.length, 31);
265
+ }
266
+ );
267
+
268
+ await test(`Given a DateTime object with value in January "2024-01-01 10:00"
269
+ when daysOfMonth is calculated for that DateTime
270
+ then first element of the array should represent first day of month`,
271
+ () =>
272
+ {
273
+ assert.strictEqual(daysOfMonth.takeFirst().value, "2024-01-01 00:00:00");
274
+ assert.strictEqual(daysOfMonth.takeFirst().dateValue, "2024-01-01");
275
+ }
276
+ );
277
+
278
+ await test(`Given a DateTime object with value in January "2024-01-01 10:00"
279
+ when daysOfMonth is calculated for that DateTime
280
+ then last element of the array should represent last day of month`,
281
+ () =>
282
+ {
283
+ assert.strictEqual(daysOfMonth.takeLast().value, "2024-01-31 23:59:59");
284
+ assert.strictEqual(daysOfMonth.takeLast().dateValue, "2024-01-31");
285
+ }
286
+ );
287
+ });
288
+
289
+ await describe("For 2024 feb (leap year)", async () =>
290
+ {
291
+ const daysOfMonth = new DateTime({ value: "2024-02-01 10:00", zone: "utc" }).getDaysOfMonth();
292
+
293
+ await test(`Given a DateTime object with value in leap year February "2024-02-01 10:00"
294
+ when daysOfMonth is calculated for that DateTime
295
+ then it should return an array of 29 days`,
296
+ () =>
297
+ {
298
+ assert.strictEqual(daysOfMonth.length, 29);
299
+ }
300
+ );
301
+
302
+ await test(`Given a DateTime object with value in leap year February "2024-02-01 10:00"
303
+ when daysOfMonth is calculated for that DateTime
304
+ then first element of the array should represent first day of month`,
305
+ () =>
306
+ {
307
+ assert.strictEqual(daysOfMonth.takeFirst().value, "2024-02-01 00:00:00");
308
+ assert.strictEqual(daysOfMonth.takeFirst().dateValue, "2024-02-01");
309
+ }
310
+ );
311
+
312
+ await test(`Given a DateTime object with value in leap year February "2024-02-01 10:00"
313
+ when daysOfMonth is calculated for that DateTime
314
+ then last element of the array should represent last day of month`,
315
+ () =>
316
+ {
317
+ assert.strictEqual(daysOfMonth.takeLast().value, "2024-02-29 23:59:59");
318
+ assert.strictEqual(daysOfMonth.takeLast().dateValue, "2024-02-29");
319
+ }
320
+ );
321
+ });
322
+
323
+ await describe("for 2023 feb (non leap year)", async () =>
324
+ {
325
+ const daysOfMonth = new DateTime({ value: "2023-02-01 10:00", zone: "utc" }).getDaysOfMonth();
326
+
327
+ await test(`Given a DateTime object with value in non leap year February "2023-02-01 10:00"
328
+ when daysOfMonth is calculated for that DateTime
329
+ then it should return an array of 28 days`,
330
+ () =>
331
+ {
332
+ assert.strictEqual(daysOfMonth.length, 28);
333
+ }
334
+ );
335
+
336
+ await test(`Given a DateTime object with value in non leap year February "2024-02-01 10:00"
337
+ when daysOfMonth is calculated for that DateTime
338
+ then first element of the array should represent first day of month`,
339
+ () =>
340
+ {
341
+ assert.strictEqual(daysOfMonth.takeFirst().value, "2023-02-01 00:00:00");
342
+ assert.strictEqual(daysOfMonth.takeFirst().dateValue, "2023-02-01");
343
+ }
344
+ );
345
+
346
+ await test(`Given a DateTime object with value in non leap year February "2024-02-01 10:00"
347
+ when daysOfMonth is calculated for that DateTime
348
+ then last element of the array should represent last day of month`,
349
+ () =>
350
+ {
351
+ assert.strictEqual(daysOfMonth.takeLast().value, "2023-02-28 23:59:59");
352
+ assert.strictEqual(daysOfMonth.takeLast().dateValue, "2023-02-28");
353
+ }
354
+ );
355
+ });
356
+ });
357
+
358
+ await describe("Convert to zone", async () =>
359
+ {
360
+ const value = "2024-01-01 10:00:00";
361
+
362
+ const dateTime = new DateTime({ value, zone: "utc" });
363
+
364
+ await test(`Given a DateTime object with value (${value}) and zone (utc)
365
+ when a DateTime is converted to another zone
366
+ then DateTime returned should have zone set to the new zone`,
367
+ () =>
368
+ {
369
+ assert.strictEqual(dateTime.convertToZone("utc").zone, "utc");
370
+ assert.strictEqual(dateTime.convertToZone("UTC+5:30").zone, "UTC+5:30");
371
+ assert.strictEqual(dateTime.convertToZone("America/Los_Angeles").zone, "America/Los_Angeles");
372
+ }
373
+ );
374
+
375
+ await test(`Given a DateTime object with value (${value}) and zone (utc)
376
+ when a DateTime is converted to another zone
377
+ then DateTime returned should have value changed with a difference of offset between the zones`,
378
+ () =>
379
+ {
380
+ assert.strictEqual(dateTime.convertToZone("utc").value, value);
381
+ assert.strictEqual(dateTime.convertToZone("UTC+5:30").value, "2024-01-01 15:30:00");
382
+ }
383
+ );
384
+
385
+ await test(`Given a DateTime object with value ("2024-01-01 10:00") outside DST and zone (utc)
386
+ when a DateTime is converted to America/Los_Angeles (PST - Pacific Standard Time)
387
+ then DateTime returned should have value changed with -8 hours`,
388
+ () =>
389
+ {
390
+ const dateTime = new DateTime({ value: "2024-01-01 10:00", zone: "utc" });
391
+ assert.strictEqual(dateTime.convertToZone("America/Los_Angeles").value, "2024-01-01 02:00:00");
392
+ }
393
+ );
394
+
395
+ await test(`Given a DateTime object with value ("2024-06-01 10:00") within DST and zone (utc)
396
+ when a DateTime is converted to America/Los_Angeles (PDT — Pacific Daylight Time)
397
+ then DateTime returned should have value changed with -7 hours`,
398
+ () =>
399
+ {
400
+ const dateTime = new DateTime({ value: "2024-06-01 10:00", zone: "utc" });
401
+ assert.strictEqual(dateTime.convertToZone("America/Los_Angeles").value, "2024-06-01 03:00:00");
402
+ }
403
+ );
404
+
405
+ await describe("Check Invalid param for zone", async () =>
406
+ {
407
+ const dateTime = new DateTime({ value: "2024-01-01 10:00", zone: "utc" });
408
+
409
+ async function checkIsInvalidParam(zone: string, reason: string): Promise<void>
410
+ {
411
+ await test(`Given a DateTime (${dateTime.toString()}), and a zone to convert it to (${zone})
412
+ when ${reason}
413
+ then it should throw a validation error`,
414
+ () =>
415
+ {
416
+ assert.throws(() => dateTime.convertToZone(zone), ArgumentException);
417
+ }
418
+ );
419
+ }
420
+
421
+ await checkIsInvalidParam("", "zone is an empty string");
422
+ await checkIsInvalidParam("aksfljn", "zone is a random string");
423
+ await checkIsInvalidParam("local", "zone is local");
424
+ await checkIsInvalidParam("America/LosAngeles", "zone is misspelled"); // correct is America/Los_Angeles
425
+ await checkIsInvalidParam("UTC+14:01", "zone is invalid");
426
+ await checkIsInvalidParam("UTC-12:01", "zone is invalid");
427
+ await checkIsInvalidParam("UTC+15", "zone is invalid");
428
+ await checkIsInvalidParam("UTC-13", "zone is invalid");
429
+ });
430
+ });
431
+ });
432
+