@subrotosaha/datekit 1.1.0 → 1.2.0
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/README.md +484 -249
- package/dist/index.d.mts +106 -8
- package/dist/index.d.ts +106 -8
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -21,15 +21,15 @@
|
|
|
21
21
|
|
|
22
22
|
DateKit is a modern, lightweight date/time library that combines the best ideas from Moment.js, date-fns, and Day.js with a fresh, developer-friendly API.
|
|
23
23
|
|
|
24
|
-
| Feature
|
|
25
|
-
|
|
26
|
-
| **Immutable**
|
|
27
|
-
| **TypeScript-first**
|
|
28
|
-
| **Chainable API**
|
|
29
|
-
| **UTC-first**
|
|
30
|
-
| **IANA Timezone Support** | ✅ Built-in | Plugin
|
|
31
|
-
| **Business Days**
|
|
32
|
-
| **Zero Dependencies**
|
|
24
|
+
| Feature | DateKit | Moment.js | date-fns | Day.js |
|
|
25
|
+
| ------------------------- | ----------- | --------- | ------------ | -------- |
|
|
26
|
+
| **Immutable** | ✅ | ❌ | ✅ | ✅ |
|
|
27
|
+
| **TypeScript-first** | ✅ | Partial | ✅ | Partial |
|
|
28
|
+
| **Chainable API** | ✅ | ✅ | ❌ | ✅ |
|
|
29
|
+
| **UTC-first** | ✅ | ❌ | ❌ | Optional |
|
|
30
|
+
| **IANA Timezone Support** | ✅ Built-in | Plugin | Separate pkg | Plugin |
|
|
31
|
+
| **Business Days** | ✅ Built-in | ❌ | ❌ | ❌ |
|
|
32
|
+
| **Zero Dependencies** | ✅ | ❌ | ✅ | ✅ |
|
|
33
33
|
|
|
34
34
|
### 🎯 Key Features
|
|
35
35
|
|
|
@@ -39,7 +39,9 @@ DateKit is a modern, lightweight date/time library that combines the best ideas
|
|
|
39
39
|
- 🎨 **Chainable API** — Fluent, readable code
|
|
40
40
|
- 🌐 **IANA Timezone Support** — Full timezone conversion built-in
|
|
41
41
|
- 📊 **Business Day Calculations** — Skip weekends and holidays
|
|
42
|
-
- 🌍 **i18n Ready** —
|
|
42
|
+
- 🌍 **i18n Ready** — 13 built-in locales with RTL support (Arabic, Urdu)
|
|
43
|
+
- 🗓️ **DateRange** — Inclusive date ranges with set operations (intersection, union, overlap)
|
|
44
|
+
- 🔍 **Format-String Parsing** — `DateKit.parse(str, format)` for any date format
|
|
43
45
|
- 📝 **TypeScript Native** — Full type safety and IntelliSense
|
|
44
46
|
|
|
45
47
|
---
|
|
@@ -71,10 +73,7 @@ const date = new DateKit("2024-03-15T14:30:00Z");
|
|
|
71
73
|
console.log(date.format("MMMM D, YYYY")); // "March 15, 2024"
|
|
72
74
|
|
|
73
75
|
// Chain operations (all immutable!)
|
|
74
|
-
const futureDate = date
|
|
75
|
-
.add(2, "week")
|
|
76
|
-
.startOf("month")
|
|
77
|
-
.setHour(9);
|
|
76
|
+
const futureDate = date.add(2, "week").startOf("month").setHour(9);
|
|
78
77
|
|
|
79
78
|
console.log(futureDate.format("dddd, MMMM D, YYYY [at] h:mm A"));
|
|
80
79
|
// "Monday, April 1, 2024 at 9:00 AM"
|
|
@@ -110,6 +109,17 @@ console.log(meeting.humanize()); // "an hour"
|
|
|
110
109
|
- [Localization](#localization)
|
|
111
110
|
- [Intervals](#intervals)
|
|
112
111
|
- [Static Methods](#static-methods)
|
|
112
|
+
- [Parse with Format](#parse-with-format)
|
|
113
|
+
|
|
114
|
+
</details>
|
|
115
|
+
|
|
116
|
+
<details>
|
|
117
|
+
<summary><strong>📅 DateRange Class</strong></summary>
|
|
118
|
+
|
|
119
|
+
- [Creating Date Ranges](#creating-date-ranges)
|
|
120
|
+
- [Predicates](#range-predicates)
|
|
121
|
+
- [Set Operations](#set-operations)
|
|
122
|
+
- [Metrics](#range-metrics)
|
|
113
123
|
|
|
114
124
|
</details>
|
|
115
125
|
|
|
@@ -159,9 +169,9 @@ const fromUnix = DateKit.unix(1710513000);
|
|
|
159
169
|
|
|
160
170
|
// With configuration
|
|
161
171
|
const configured = new DateKit("2024-03-15", {
|
|
162
|
-
locale: "es",
|
|
163
|
-
weekStartsOn: 1,
|
|
164
|
-
strictParsing: true
|
|
172
|
+
locale: "es", // Spanish locale
|
|
173
|
+
weekStartsOn: 1, // Monday = 1
|
|
174
|
+
strictParsing: true, // Strict date parsing
|
|
165
175
|
});
|
|
166
176
|
```
|
|
167
177
|
|
|
@@ -175,18 +185,18 @@ Transform dates into human-readable strings:
|
|
|
175
185
|
const date = new DateKit("2024-03-15T14:30:45.123Z");
|
|
176
186
|
|
|
177
187
|
// Common formats
|
|
178
|
-
date.format("YYYY-MM-DD");
|
|
179
|
-
date.format("DD/MM/YYYY");
|
|
180
|
-
date.format("MMMM D, YYYY");
|
|
181
|
-
date.format("dddd, MMMM Do YYYY");
|
|
188
|
+
date.format("YYYY-MM-DD"); // "2024-03-15"
|
|
189
|
+
date.format("DD/MM/YYYY"); // "15/03/2024"
|
|
190
|
+
date.format("MMMM D, YYYY"); // "March 15, 2024"
|
|
191
|
+
date.format("dddd, MMMM Do YYYY"); // "Friday, March 15th 2024"
|
|
182
192
|
|
|
183
193
|
// With time
|
|
184
|
-
date.format("YYYY-MM-DD HH:mm:ss");
|
|
185
|
-
date.format("h:mm A");
|
|
186
|
-
date.format("HH:mm:ss.SSS");
|
|
194
|
+
date.format("YYYY-MM-DD HH:mm:ss"); // "2024-03-15 14:30:45"
|
|
195
|
+
date.format("h:mm A"); // "2:30 PM"
|
|
196
|
+
date.format("HH:mm:ss.SSS"); // "14:30:45.123"
|
|
187
197
|
|
|
188
198
|
// Complex formats
|
|
189
|
-
date.format("[Today is] dddd");
|
|
199
|
+
date.format("[Today is] dddd"); // "Today is Friday"
|
|
190
200
|
date.format("Qo [quarter of] YYYY"); // "1st quarter of 2024"
|
|
191
201
|
|
|
192
202
|
// With locale
|
|
@@ -224,8 +234,8 @@ DateKit.formatInTimezone(utcDate, "Asia/Dhaka", "YYYY-MM-DD HH:mm");
|
|
|
224
234
|
// Meeting at 2:30 PM in Dhaka - what time in New York?
|
|
225
235
|
DateKit.convertTimezone(
|
|
226
236
|
"2024-12-25T14:30:00",
|
|
227
|
-
"Asia/Dhaka",
|
|
228
|
-
"America/New_York",
|
|
237
|
+
"Asia/Dhaka", // Source timezone
|
|
238
|
+
"America/New_York", // Target timezone
|
|
229
239
|
"YYYY-MM-DD HH:mm"
|
|
230
240
|
);
|
|
231
241
|
// → "2024-12-25 03:30" (10.5 hour difference)
|
|
@@ -250,7 +260,11 @@ tokyoMorning.toISOString();
|
|
|
250
260
|
// → "2024-12-25T00:00:00.000Z" (stored as UTC internally)
|
|
251
261
|
|
|
252
262
|
// Display it in another timezone
|
|
253
|
-
DateKit.formatInTimezone(
|
|
263
|
+
DateKit.formatInTimezone(
|
|
264
|
+
tokyoMorning.toDate(),
|
|
265
|
+
"America/Los_Angeles",
|
|
266
|
+
"h:mm A"
|
|
267
|
+
);
|
|
254
268
|
// → "4:00 PM" (previous day!)
|
|
255
269
|
```
|
|
256
270
|
|
|
@@ -260,7 +274,8 @@ Parse browser-generated date strings and format them **preserving the original t
|
|
|
260
274
|
|
|
261
275
|
```typescript
|
|
262
276
|
// Browser's Date.toString() output with timezone info
|
|
263
|
-
const browserDate =
|
|
277
|
+
const browserDate =
|
|
278
|
+
"Sun Dec 25 2024 00:00:00 GMT+0600 (Bangladesh Standard Time)";
|
|
264
279
|
|
|
265
280
|
// ✅ Preserves the local date (midnight in Bangladesh)
|
|
266
281
|
DateKit.formatFromTimezoneString(browserDate, "YYYY-MM-DD HH:mm");
|
|
@@ -291,9 +306,9 @@ frenchKit.formatZonedDate(dateString, "dddd D MMMM YYYY");
|
|
|
291
306
|
|
|
292
307
|
```typescript
|
|
293
308
|
// Current offset for a timezone
|
|
294
|
-
DateKit.getTimezoneOffset("Asia/Kolkata");
|
|
295
|
-
DateKit.getTimezoneOffset("America/New_York");
|
|
296
|
-
DateKit.getTimezoneOffset("UTC");
|
|
309
|
+
DateKit.getTimezoneOffset("Asia/Kolkata"); // 330 (UTC+5:30)
|
|
310
|
+
DateKit.getTimezoneOffset("America/New_York"); // -300 or -240 (depends on DST)
|
|
311
|
+
DateKit.getTimezoneOffset("UTC"); // 0
|
|
297
312
|
|
|
298
313
|
// Check offset at a specific date (for DST-aware calculations)
|
|
299
314
|
const summer = new Date("2024-07-15");
|
|
@@ -309,23 +324,23 @@ DateKit.getTimezoneOffset("America/New_York", winter); // -300 (EST)
|
|
|
309
324
|
|
|
310
325
|
Access individual date/time components (all UTC-based):
|
|
311
326
|
|
|
312
|
-
| Method
|
|
313
|
-
|
|
314
|
-
| `year()`
|
|
315
|
-
| `month()`
|
|
316
|
-
| `getDate()`
|
|
317
|
-
| `day()`
|
|
318
|
-
| `hour()`
|
|
319
|
-
| `minute()`
|
|
320
|
-
| `second()`
|
|
321
|
-
| `millisecond()` | Millisecond (0-999)
|
|
322
|
-
| `quarter()`
|
|
323
|
-
| `week()`
|
|
324
|
-
| `isoWeek()`
|
|
325
|
-
| `weekday()`
|
|
326
|
-
| `isoWeekday()`
|
|
327
|
-
| `dayOfYear()`
|
|
328
|
-
| `weekYear()`
|
|
327
|
+
| Method | Returns | Example |
|
|
328
|
+
| --------------- | -------------------- | ------------ |
|
|
329
|
+
| `year()` | Full year | `2024` |
|
|
330
|
+
| `month()` | Month (0-indexed) | `2` (March) |
|
|
331
|
+
| `getDate()` | Day of month | `15` |
|
|
332
|
+
| `day()` | Day of week (0=Sun) | `5` (Friday) |
|
|
333
|
+
| `hour()` | Hour (0-23) | `14` |
|
|
334
|
+
| `minute()` | Minute (0-59) | `30` |
|
|
335
|
+
| `second()` | Second (0-59) | `45` |
|
|
336
|
+
| `millisecond()` | Millisecond (0-999) | `123` |
|
|
337
|
+
| `quarter()` | Quarter (1-4) | `1` |
|
|
338
|
+
| `week()` | ISO week number | `11` |
|
|
339
|
+
| `isoWeek()` | ISO week number | `11` |
|
|
340
|
+
| `weekday()` | Locale-aware weekday | `5` |
|
|
341
|
+
| `isoWeekday()` | ISO weekday (Mon=1) | `5` |
|
|
342
|
+
| `dayOfYear()` | Day of year (1-366) | `75` |
|
|
343
|
+
| `weekYear()` | ISO week year | `2024` |
|
|
329
344
|
|
|
330
345
|
```typescript
|
|
331
346
|
const date = new DateKit("2024-03-15T14:30:45.123Z");
|
|
@@ -352,24 +367,26 @@ All setters return a **new DateKit instance** (immutable):
|
|
|
352
367
|
const date = new DateKit("2024-03-15T14:30:00Z");
|
|
353
368
|
|
|
354
369
|
// Individual setters
|
|
355
|
-
date.setYear(2025).toISOString();
|
|
356
|
-
date.setMonth(11).toISOString();
|
|
357
|
-
date.setDate(1).toISOString();
|
|
358
|
-
date.setHour(9).toISOString();
|
|
359
|
-
date.setMinute(0).toISOString();
|
|
360
|
-
date.setSecond(0).toISOString();
|
|
361
|
-
date.setMillisecond(500).toISOString();
|
|
362
|
-
date.setQuarter(3).toISOString();
|
|
370
|
+
date.setYear(2025).toISOString(); // "2025-03-15T14:30:00.000Z"
|
|
371
|
+
date.setMonth(11).toISOString(); // "2024-12-15T14:30:00.000Z"
|
|
372
|
+
date.setDate(1).toISOString(); // "2024-03-01T14:30:00.000Z"
|
|
373
|
+
date.setHour(9).toISOString(); // "2024-03-15T09:30:00.000Z"
|
|
374
|
+
date.setMinute(0).toISOString(); // "2024-03-15T14:00:00.000Z"
|
|
375
|
+
date.setSecond(0).toISOString(); // "2024-03-15T14:30:00.000Z"
|
|
376
|
+
date.setMillisecond(500).toISOString(); // "2024-03-15T14:30:00.500Z"
|
|
377
|
+
date.setQuarter(3).toISOString(); // "2024-09-15T14:30:00.000Z"
|
|
363
378
|
|
|
364
379
|
// Set multiple values at once
|
|
365
|
-
date
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
380
|
+
date
|
|
381
|
+
.set({
|
|
382
|
+
year: 2025,
|
|
383
|
+
month: 0, // January
|
|
384
|
+
date: 1,
|
|
385
|
+
hour: 0,
|
|
386
|
+
minute: 0,
|
|
387
|
+
second: 0,
|
|
388
|
+
})
|
|
389
|
+
.format("YYYY-MM-DD HH:mm:ss");
|
|
373
390
|
// → "2025-01-01 00:00:00"
|
|
374
391
|
```
|
|
375
392
|
|
|
@@ -383,15 +400,15 @@ Add or subtract time with chainable operations:
|
|
|
383
400
|
const date = new DateKit("2024-01-15T10:00:00Z");
|
|
384
401
|
|
|
385
402
|
// Adding time
|
|
386
|
-
date.add(5, "day").format("YYYY-MM-DD");
|
|
387
|
-
date.add(2, "week").format("YYYY-MM-DD");
|
|
388
|
-
date.add(3, "month").format("YYYY-MM-DD");
|
|
389
|
-
date.add(1, "year").format("YYYY-MM-DD");
|
|
390
|
-
date.add(90, "minute").format("HH:mm");
|
|
403
|
+
date.add(5, "day").format("YYYY-MM-DD"); // "2024-01-20"
|
|
404
|
+
date.add(2, "week").format("YYYY-MM-DD"); // "2024-01-29"
|
|
405
|
+
date.add(3, "month").format("YYYY-MM-DD"); // "2024-04-15"
|
|
406
|
+
date.add(1, "year").format("YYYY-MM-DD"); // "2025-01-15"
|
|
407
|
+
date.add(90, "minute").format("HH:mm"); // "11:30"
|
|
391
408
|
|
|
392
409
|
// Subtracting time
|
|
393
410
|
date.subtract(1, "month").format("YYYY-MM-DD"); // "2023-12-15"
|
|
394
|
-
date.subtract(2, "hour").format("HH:mm");
|
|
411
|
+
date.subtract(2, "hour").format("HH:mm"); // "08:00"
|
|
395
412
|
|
|
396
413
|
// Chaining (all operations are immutable!)
|
|
397
414
|
const result = date
|
|
@@ -414,18 +431,18 @@ Snap to the boundaries of time units:
|
|
|
414
431
|
const date = new DateKit("2024-03-15T14:30:45.123Z");
|
|
415
432
|
|
|
416
433
|
// Start of...
|
|
417
|
-
date.startOf("year").format("YYYY-MM-DD HH:mm:ss");
|
|
418
|
-
date.startOf("quarter").format("YYYY-MM-DD");
|
|
419
|
-
date.startOf("month").format("YYYY-MM-DD");
|
|
420
|
-
date.startOf("week").format("YYYY-MM-DD");
|
|
421
|
-
date.startOf("day").format("YYYY-MM-DD HH:mm:ss");
|
|
422
|
-
date.startOf("hour").format("HH:mm:ss");
|
|
434
|
+
date.startOf("year").format("YYYY-MM-DD HH:mm:ss"); // "2024-01-01 00:00:00"
|
|
435
|
+
date.startOf("quarter").format("YYYY-MM-DD"); // "2024-01-01"
|
|
436
|
+
date.startOf("month").format("YYYY-MM-DD"); // "2024-03-01"
|
|
437
|
+
date.startOf("week").format("YYYY-MM-DD"); // "2024-03-10" (Sunday)
|
|
438
|
+
date.startOf("day").format("YYYY-MM-DD HH:mm:ss"); // "2024-03-15 00:00:00"
|
|
439
|
+
date.startOf("hour").format("HH:mm:ss"); // "14:00:00"
|
|
423
440
|
|
|
424
441
|
// End of...
|
|
425
|
-
date.endOf("year").format("YYYY-MM-DD HH:mm:ss");
|
|
426
|
-
date.endOf("month").format("YYYY-MM-DD");
|
|
427
|
-
date.endOf("day").format("HH:mm:ss.SSS");
|
|
428
|
-
date.endOf("hour").format("HH:mm:ss.SSS");
|
|
442
|
+
date.endOf("year").format("YYYY-MM-DD HH:mm:ss"); // "2024-12-31 23:59:59"
|
|
443
|
+
date.endOf("month").format("YYYY-MM-DD"); // "2024-03-31"
|
|
444
|
+
date.endOf("day").format("HH:mm:ss.SSS"); // "23:59:59.999"
|
|
445
|
+
date.endOf("hour").format("HH:mm:ss.SSS"); // "14:59:59.999"
|
|
429
446
|
```
|
|
430
447
|
|
|
431
448
|
---
|
|
@@ -440,24 +457,24 @@ const jan20 = new DateKit("2024-01-20");
|
|
|
440
457
|
const feb15 = new DateKit("2024-02-15");
|
|
441
458
|
|
|
442
459
|
// Basic comparisons
|
|
443
|
-
jan15.isBefore(jan20);
|
|
444
|
-
jan20.isAfter(jan15);
|
|
445
|
-
jan15.isSame("2024-01-15");
|
|
460
|
+
jan15.isBefore(jan20); // true
|
|
461
|
+
jan20.isAfter(jan15); // true
|
|
462
|
+
jan15.isSame("2024-01-15"); // true
|
|
446
463
|
|
|
447
464
|
// Compare by unit
|
|
448
465
|
jan15.isSame(jan20, "month"); // true (both January)
|
|
449
|
-
jan15.isSame(feb15, "year");
|
|
466
|
+
jan15.isSame(feb15, "year"); // true (both 2024)
|
|
450
467
|
|
|
451
468
|
// Inclusive comparisons
|
|
452
|
-
jan15.isSameOrBefore(jan20);
|
|
453
|
-
jan20.isSameOrAfter(jan15);
|
|
469
|
+
jan15.isSameOrBefore(jan20); // true
|
|
470
|
+
jan20.isSameOrAfter(jan15); // true
|
|
454
471
|
|
|
455
472
|
// Range check with inclusivity options
|
|
456
473
|
const jan17 = new DateKit("2024-01-17");
|
|
457
|
-
jan17.isBetween("2024-01-15", "2024-01-20");
|
|
458
|
-
jan17.isBetween("2024-01-15", "2024-01-20", undefined, "[]");
|
|
459
|
-
jan15.isBetween("2024-01-15", "2024-01-20", undefined, "[)");
|
|
460
|
-
jan20.isBetween("2024-01-15", "2024-01-20", undefined, "(]");
|
|
474
|
+
jan17.isBetween("2024-01-15", "2024-01-20"); // true (exclusive)
|
|
475
|
+
jan17.isBetween("2024-01-15", "2024-01-20", undefined, "[]"); // true (inclusive)
|
|
476
|
+
jan15.isBetween("2024-01-15", "2024-01-20", undefined, "[)"); // true (start-inclusive)
|
|
477
|
+
jan20.isBetween("2024-01-15", "2024-01-20", undefined, "(]"); // true (end-inclusive)
|
|
461
478
|
```
|
|
462
479
|
|
|
463
480
|
---
|
|
@@ -472,25 +489,25 @@ const saturday = new DateKit("2024-03-16"); // A Saturday
|
|
|
472
489
|
const leapYear = new DateKit("2024-02-29");
|
|
473
490
|
|
|
474
491
|
// Relative checks
|
|
475
|
-
today.isToday();
|
|
476
|
-
today.add(1, "day").isTomorrow();
|
|
492
|
+
today.isToday(); // true
|
|
493
|
+
today.add(1, "day").isTomorrow(); // true
|
|
477
494
|
today.subtract(1, "day").isYesterday(); // true
|
|
478
495
|
|
|
479
496
|
// Period checks
|
|
480
|
-
today.isThisWeek();
|
|
481
|
-
today.isThisMonth();
|
|
482
|
-
today.isThisQuarter();
|
|
483
|
-
today.isThisYear();
|
|
497
|
+
today.isThisWeek(); // true
|
|
498
|
+
today.isThisMonth(); // true
|
|
499
|
+
today.isThisQuarter(); // true
|
|
500
|
+
today.isThisYear(); // true
|
|
484
501
|
|
|
485
502
|
// Day type checks
|
|
486
|
-
saturday.isWeekend();
|
|
487
|
-
saturday.isWeekday();
|
|
503
|
+
saturday.isWeekend(); // true
|
|
504
|
+
saturday.isWeekday(); // false
|
|
488
505
|
|
|
489
506
|
// Year checks
|
|
490
|
-
leapYear.isLeapYear();
|
|
507
|
+
leapYear.isLeapYear(); // true (2024 is a leap year)
|
|
491
508
|
|
|
492
509
|
// DST check (environment-dependent)
|
|
493
|
-
today.isDST();
|
|
510
|
+
today.isDST(); // true/false based on current DST status
|
|
494
511
|
```
|
|
495
512
|
|
|
496
513
|
---
|
|
@@ -504,22 +521,22 @@ const start = new DateKit("2024-01-01T00:00:00Z");
|
|
|
504
521
|
const end = new DateKit("2024-03-15T14:30:00Z");
|
|
505
522
|
|
|
506
523
|
// Basic differences (returns integers by default)
|
|
507
|
-
end.diff(start, "day");
|
|
508
|
-
end.diff(start, "week");
|
|
509
|
-
end.diff(start, "month");
|
|
510
|
-
end.diff(start, "hour");
|
|
524
|
+
end.diff(start, "day"); // 74
|
|
525
|
+
end.diff(start, "week"); // 10
|
|
526
|
+
end.diff(start, "month"); // 2
|
|
527
|
+
end.diff(start, "hour"); // 1782
|
|
511
528
|
|
|
512
529
|
// Precise differences (floating point)
|
|
513
|
-
end.diff(start, "day", true);
|
|
530
|
+
end.diff(start, "day", true); // 74.604...
|
|
514
531
|
end.diff(start, "month", true); // 2.467...
|
|
515
532
|
|
|
516
533
|
// Negative differences (when comparing backwards)
|
|
517
|
-
start.diff(end, "day");
|
|
534
|
+
start.diff(end, "day"); // -74
|
|
518
535
|
|
|
519
536
|
// Common use case: age calculation
|
|
520
537
|
const birthdate = new DateKit("1990-05-15");
|
|
521
538
|
const today = new DateKit("2024-03-15");
|
|
522
|
-
today.diff(birthdate, "year");
|
|
539
|
+
today.diff(birthdate, "year"); // 33
|
|
523
540
|
```
|
|
524
541
|
|
|
525
542
|
---
|
|
@@ -532,23 +549,23 @@ Human-friendly "time ago" / "time from now" strings:
|
|
|
532
549
|
const now = DateKit.now();
|
|
533
550
|
|
|
534
551
|
// From now (past)
|
|
535
|
-
now.subtract(5, "second").fromNow();
|
|
536
|
-
now.subtract(3, "minute").fromNow();
|
|
537
|
-
now.subtract(2, "hour").fromNow();
|
|
538
|
-
now.subtract(1, "day").fromNow();
|
|
539
|
-
now.subtract(5, "day").fromNow();
|
|
540
|
-
now.subtract(1, "month").fromNow();
|
|
541
|
-
now.subtract(2, "year").fromNow();
|
|
552
|
+
now.subtract(5, "second").fromNow(); // "a few seconds ago"
|
|
553
|
+
now.subtract(3, "minute").fromNow(); // "3 minutes ago"
|
|
554
|
+
now.subtract(2, "hour").fromNow(); // "2 hours ago"
|
|
555
|
+
now.subtract(1, "day").fromNow(); // "a day ago"
|
|
556
|
+
now.subtract(5, "day").fromNow(); // "5 days ago"
|
|
557
|
+
now.subtract(1, "month").fromNow(); // "a month ago"
|
|
558
|
+
now.subtract(2, "year").fromNow(); // "2 years ago"
|
|
542
559
|
|
|
543
560
|
// To now (future)
|
|
544
|
-
now.add(10, "minute").toNow();
|
|
545
|
-
now.add(3, "day").toNow();
|
|
561
|
+
now.add(10, "minute").toNow(); // "in 10 minutes"
|
|
562
|
+
now.add(3, "day").toNow(); // "in 3 days"
|
|
546
563
|
|
|
547
564
|
// Between specific dates
|
|
548
565
|
const past = new DateKit("2024-01-01");
|
|
549
566
|
const future = new DateKit("2024-12-31");
|
|
550
|
-
past.from(future);
|
|
551
|
-
future.to(past);
|
|
567
|
+
past.from(future); // "in 12 months"
|
|
568
|
+
future.to(past); // "12 months ago"
|
|
552
569
|
|
|
553
570
|
// Without suffix
|
|
554
571
|
now.subtract(5, "minute").fromNow(true); // "5 minutes"
|
|
@@ -563,16 +580,16 @@ Context-aware date descriptions:
|
|
|
563
580
|
```typescript
|
|
564
581
|
const now = DateKit.now();
|
|
565
582
|
|
|
566
|
-
now.calendar();
|
|
567
|
-
now.add(1, "day").calendar();
|
|
568
|
-
now.subtract(1, "day").calendar();
|
|
569
|
-
now.add(3, "day").calendar();
|
|
570
|
-
now.subtract(7, "day").calendar();
|
|
583
|
+
now.calendar(); // "Today at 2:30 PM"
|
|
584
|
+
now.add(1, "day").calendar(); // "Tomorrow at 2:30 PM"
|
|
585
|
+
now.subtract(1, "day").calendar(); // "Yesterday at 2:30 PM"
|
|
586
|
+
now.add(3, "day").calendar(); // "Thursday at 2:30 PM"
|
|
587
|
+
now.subtract(7, "day").calendar(); // "03/08/2024"
|
|
571
588
|
|
|
572
589
|
// With custom reference date
|
|
573
590
|
const eventDate = new DateKit("2024-06-15T10:00:00Z");
|
|
574
591
|
const currentDate = new DateKit("2024-06-14");
|
|
575
|
-
eventDate.calendar(currentDate);
|
|
592
|
+
eventDate.calendar(currentDate); // "Tomorrow at 10:00 AM"
|
|
576
593
|
```
|
|
577
594
|
|
|
578
595
|
---
|
|
@@ -585,18 +602,18 @@ Helpful methods for common operations:
|
|
|
585
602
|
const date = new DateKit("2024-02-15");
|
|
586
603
|
|
|
587
604
|
// Days in the current month
|
|
588
|
-
date.daysInMonth();
|
|
605
|
+
date.daysInMonth(); // 29 (February 2024, leap year)
|
|
589
606
|
new DateKit("2023-02-15").daysInMonth(); // 28 (non-leap year)
|
|
590
607
|
new DateKit("2024-01-15").daysInMonth(); // 31
|
|
591
608
|
|
|
592
609
|
// Weeks in year (ISO)
|
|
593
|
-
date.weeksInYear();
|
|
610
|
+
date.weeksInYear(); // 52 (or 53 for some years)
|
|
594
611
|
|
|
595
612
|
// Age calculation
|
|
596
613
|
const birthdate = new DateKit("1990-05-15");
|
|
597
|
-
birthdate.age();
|
|
598
|
-
birthdate.age("2024-05-14");
|
|
599
|
-
birthdate.age("2024-05-15");
|
|
614
|
+
birthdate.age(); // Current age in years
|
|
615
|
+
birthdate.age("2024-05-14"); // 33 (day before birthday)
|
|
616
|
+
birthdate.age("2024-05-15"); // 34 (on birthday)
|
|
600
617
|
|
|
601
618
|
// Clone (independent copy)
|
|
602
619
|
const original = new DateKit("2024-03-15");
|
|
@@ -606,8 +623,8 @@ copy.add(1, "day"); // Doesn't affect original
|
|
|
606
623
|
// Duration to another date
|
|
607
624
|
const start = new DateKit("2024-01-01T08:00:00Z");
|
|
608
625
|
const end = new DateKit("2024-01-01T17:30:00Z");
|
|
609
|
-
start.duration(end).asHours();
|
|
610
|
-
start.duration(end).humanize();
|
|
626
|
+
start.duration(end).asHours(); // 9.5
|
|
627
|
+
start.duration(end).humanize(); // "9 hours"
|
|
611
628
|
```
|
|
612
629
|
|
|
613
630
|
---
|
|
@@ -621,7 +638,7 @@ const friday = new DateKit("2024-03-15"); // Friday
|
|
|
621
638
|
const monday = new DateKit("2024-03-18"); // Monday
|
|
622
639
|
|
|
623
640
|
// Check if business day
|
|
624
|
-
friday.isBusinessDay();
|
|
641
|
+
friday.isBusinessDay(); // true
|
|
625
642
|
friday.add(1, "day").isBusinessDay(); // false (Saturday)
|
|
626
643
|
|
|
627
644
|
// Add business days (skips weekends)
|
|
@@ -647,8 +664,8 @@ const holidays = [
|
|
|
647
664
|
friday.addBusinessDays(1, holidays).format("YYYY-MM-DD dddd");
|
|
648
665
|
// → "2024-03-19 Tuesday" (skipped the holiday)
|
|
649
666
|
|
|
650
|
-
friday.isBusinessDay(holidays);
|
|
651
|
-
monday.isBusinessDay(holidays);
|
|
667
|
+
friday.isBusinessDay(holidays); // true
|
|
668
|
+
monday.isBusinessDay(holidays); // false (it's a holiday)
|
|
652
669
|
```
|
|
653
670
|
|
|
654
671
|
---
|
|
@@ -668,7 +685,7 @@ const spanish = date.locale("es") as DateKit;
|
|
|
668
685
|
spanish.format("dddd, D [de] MMMM [de] YYYY"); // "Viernes, 15 de Marzo de 2024"
|
|
669
686
|
|
|
670
687
|
// Get current locale
|
|
671
|
-
date.locale();
|
|
688
|
+
date.locale(); // "en"
|
|
672
689
|
spanish.locale(); // "es"
|
|
673
690
|
|
|
674
691
|
// Create with locale
|
|
@@ -676,9 +693,45 @@ const esDate = new DateKit("2024-03-15", { locale: "es" });
|
|
|
676
693
|
esDate.format("MMMM"); // "Marzo"
|
|
677
694
|
```
|
|
678
695
|
|
|
679
|
-
**Built-in locales:**
|
|
696
|
+
**Built-in locales:**
|
|
697
|
+
|
|
698
|
+
| Code | Language | Direction |
|
|
699
|
+
| ---- | -------------------- | --------- |
|
|
700
|
+
| `en` | English | LTR |
|
|
701
|
+
| `es` | Spanish | LTR |
|
|
702
|
+
| `fr` | French | LTR |
|
|
703
|
+
| `de` | German | LTR |
|
|
704
|
+
| `pt` | Portuguese | LTR |
|
|
705
|
+
| `zh` | Chinese (Simplified) | LTR |
|
|
706
|
+
| `ja` | Japanese | LTR |
|
|
707
|
+
| `ko` | Korean | LTR |
|
|
708
|
+
| `ru` | Russian | LTR |
|
|
709
|
+
| `hi` | Hindi | LTR |
|
|
710
|
+
| `bn` | Bengali | LTR |
|
|
711
|
+
| `ar` | Arabic | **RTL** |
|
|
712
|
+
| `ur` | Urdu | **RTL** |
|
|
680
713
|
|
|
681
|
-
|
|
714
|
+
```typescript
|
|
715
|
+
import { DateKit, registerLocale } from "@subrotosaha/datekit";
|
|
716
|
+
import { ru } from "@subrotosaha/datekit/locales/ru";
|
|
717
|
+
|
|
718
|
+
// All 13 locales are registered automatically
|
|
719
|
+
new DateKit().locale("ja").fromNow(); // "数秒前"
|
|
720
|
+
|
|
721
|
+
// Text direction is exposed via LocaleConfig.dir
|
|
722
|
+
import { getLocale } from "@subrotosaha/datekit";
|
|
723
|
+
getLocale("ar").dir; // "rtl"
|
|
724
|
+
getLocale("en").dir; // "ltr"
|
|
725
|
+
|
|
726
|
+
// Register a custom locale
|
|
727
|
+
registerLocale({
|
|
728
|
+
name: "my-locale",
|
|
729
|
+
dir: "ltr",
|
|
730
|
+
// ... other fields
|
|
731
|
+
});
|
|
732
|
+
```
|
|
733
|
+
|
|
734
|
+
> 💡 **Tip**: Use `registerLocale()` to add your own custom locale at runtime.
|
|
682
735
|
|
|
683
736
|
---
|
|
684
737
|
|
|
@@ -690,25 +743,25 @@ Generate arrays of dates for iteration:
|
|
|
690
743
|
// Each day in a range
|
|
691
744
|
const days = DateKit.eachDayOfInterval({
|
|
692
745
|
start: "2024-03-01",
|
|
693
|
-
end: "2024-03-07"
|
|
746
|
+
end: "2024-03-07",
|
|
694
747
|
});
|
|
695
|
-
days.map(d => d.format("YYYY-MM-DD"));
|
|
748
|
+
days.map((d) => d.format("YYYY-MM-DD"));
|
|
696
749
|
// → ["2024-03-01", "2024-03-02", ..., "2024-03-07"]
|
|
697
750
|
|
|
698
751
|
// Each week start
|
|
699
752
|
const weeks = DateKit.eachWeekOfInterval({
|
|
700
753
|
start: "2024-03-01",
|
|
701
|
-
end: "2024-03-31"
|
|
754
|
+
end: "2024-03-31",
|
|
702
755
|
});
|
|
703
|
-
weeks.map(d => d.format("YYYY-MM-DD"));
|
|
756
|
+
weeks.map((d) => d.format("YYYY-MM-DD"));
|
|
704
757
|
// → ["2024-02-25", "2024-03-03", "2024-03-10", ...]
|
|
705
758
|
|
|
706
759
|
// Each month start
|
|
707
760
|
const months = DateKit.eachMonthOfInterval({
|
|
708
761
|
start: "2024-01-01",
|
|
709
|
-
end: "2024-06-30"
|
|
762
|
+
end: "2024-06-30",
|
|
710
763
|
});
|
|
711
|
-
months.map(d => d.format("MMMM YYYY"));
|
|
764
|
+
months.map((d) => d.format("MMMM YYYY"));
|
|
712
765
|
// → ["January 2024", "February 2024", ..., "June 2024"]
|
|
713
766
|
```
|
|
714
767
|
|
|
@@ -720,16 +773,16 @@ Utility methods without instance creation:
|
|
|
720
773
|
|
|
721
774
|
```typescript
|
|
722
775
|
// Current moment
|
|
723
|
-
DateKit.now();
|
|
776
|
+
DateKit.now(); // DateKit for current time
|
|
724
777
|
|
|
725
778
|
// Create from specific inputs
|
|
726
|
-
DateKit.utc("2024-03-15");
|
|
727
|
-
DateKit.unix(1710513000);
|
|
779
|
+
DateKit.utc("2024-03-15"); // Parse as UTC
|
|
780
|
+
DateKit.unix(1710513000); // From Unix seconds
|
|
728
781
|
|
|
729
782
|
// Validation
|
|
730
|
-
DateKit.isValid("2024-03-15");
|
|
731
|
-
DateKit.isValid("invalid-date");
|
|
732
|
-
DateKit.isValid(new Date("invalid"));
|
|
783
|
+
DateKit.isValid("2024-03-15"); // true
|
|
784
|
+
DateKit.isValid("invalid-date"); // false
|
|
785
|
+
DateKit.isValid(new Date("invalid")); // false
|
|
733
786
|
|
|
734
787
|
// Find extremes
|
|
735
788
|
DateKit.max("2024-01-01", "2024-06-15", "2024-03-20").format("YYYY-MM-DD");
|
|
@@ -739,12 +792,158 @@ DateKit.min("2024-01-01", "2024-06-15", "2024-03-20").format("YYYY-MM-DD");
|
|
|
739
792
|
// → "2024-01-01"
|
|
740
793
|
|
|
741
794
|
// Duration factory
|
|
742
|
-
DateKit.duration(2, "hours").asMinutes();
|
|
795
|
+
DateKit.duration(2, "hours").asMinutes(); // 120
|
|
743
796
|
DateKit.duration({ days: 1, hours: 12 }).asHours(); // 36
|
|
744
797
|
|
|
745
798
|
// Type guard
|
|
746
799
|
DateKit.isDuration(new Duration(5, "days")); // true
|
|
747
|
-
DateKit.isDuration({});
|
|
800
|
+
DateKit.isDuration({}); // false
|
|
801
|
+
```
|
|
802
|
+
|
|
803
|
+
---
|
|
804
|
+
|
|
805
|
+
### Parse with Format
|
|
806
|
+
|
|
807
|
+
Parse a string using a custom format pattern:
|
|
808
|
+
|
|
809
|
+
```typescript
|
|
810
|
+
// DateKit.parse(dateStr, formatStr, config?)
|
|
811
|
+
DateKit.parse("25/03/2025", "DD/MM/YYYY").format("YYYY-MM-DD");
|
|
812
|
+
// → "2025-03-25"
|
|
813
|
+
|
|
814
|
+
DateKit.parse("March 25, 2025", "MMMM DD, YYYY").toISOString();
|
|
815
|
+
// → "2025-03-25T00:00:00.000Z"
|
|
816
|
+
|
|
817
|
+
DateKit.parse("2025-03-25 14:30", "YYYY-MM-DD HH:mm").format("h:mm A");
|
|
818
|
+
// → "2:30 PM"
|
|
819
|
+
|
|
820
|
+
// Supports AM/PM, 12-hour clock
|
|
821
|
+
DateKit.parse("03/25/2025 02:30 PM", "MM/DD/YYYY hh:mm A");
|
|
822
|
+
|
|
823
|
+
// Two-digit year (pivots at 2000 + current offset)
|
|
824
|
+
DateKit.parse("25/12/99", "DD/MM/YY").year(); // 1999
|
|
825
|
+
|
|
826
|
+
// Escape literal text with square brackets (same as format())
|
|
827
|
+
DateKit.parse("Today is 2025-03-25", "[Today is] YYYY-MM-DD");
|
|
828
|
+
```
|
|
829
|
+
|
|
830
|
+
**Supported parse tokens:**
|
|
831
|
+
|
|
832
|
+
| Token | Description |
|
|
833
|
+
| -------- | ----------------------- |
|
|
834
|
+
| `YYYY` | 4-digit year |
|
|
835
|
+
| `YY` | 2-digit year |
|
|
836
|
+
| `MM` | 2-digit month (01-12) |
|
|
837
|
+
| `M` | Month without padding |
|
|
838
|
+
| `DD` | 2-digit day of month |
|
|
839
|
+
| `D` | Day without padding |
|
|
840
|
+
| `HH` | 24-hour hours (00-23) |
|
|
841
|
+
| `H` | 24-hour without padding |
|
|
842
|
+
| `hh` | 12-hour hours (01-12) |
|
|
843
|
+
| `h` | 12-hour without padding |
|
|
844
|
+
| `mm` | Minutes (00-59) |
|
|
845
|
+
| `m` | Minutes without padding |
|
|
846
|
+
| `ss` | Seconds (00-59) |
|
|
847
|
+
| `s` | Seconds without padding |
|
|
848
|
+
| `SSS` | Milliseconds |
|
|
849
|
+
| `A` | AM/PM (uppercase) |
|
|
850
|
+
| `a` | am/pm (lowercase) |
|
|
851
|
+
| `[text]` | Escaped literal text |
|
|
852
|
+
|
|
853
|
+
---
|
|
854
|
+
|
|
855
|
+
## 📅 DateRange Class
|
|
856
|
+
|
|
857
|
+
Represent an inclusive date range `[start, end]` with set operations.
|
|
858
|
+
|
|
859
|
+
### Creating Date Ranges
|
|
860
|
+
|
|
861
|
+
```typescript
|
|
862
|
+
import { DateRange } from "@subrotosaha/datekit";
|
|
863
|
+
|
|
864
|
+
// From any DateInput (ISO string, Date, timestamp, DateKit)
|
|
865
|
+
const q1 = new DateRange("2025-01-01", "2025-03-31");
|
|
866
|
+
const q2 = new DateRange("2025-04-01", "2025-06-30");
|
|
867
|
+
|
|
868
|
+
// Start must not be after end — throws RangeError otherwise
|
|
869
|
+
const range = new DateRange(
|
|
870
|
+
DateKit.now().startOf("year"),
|
|
871
|
+
DateKit.now().endOf("year")
|
|
872
|
+
);
|
|
873
|
+
|
|
874
|
+
console.log(range.start.format("YYYY-MM-DD")); // "2025-01-01"
|
|
875
|
+
console.log(range.end.format("YYYY-MM-DD")); // "2025-12-31"
|
|
876
|
+
```
|
|
877
|
+
|
|
878
|
+
---
|
|
879
|
+
|
|
880
|
+
### Range Predicates
|
|
881
|
+
|
|
882
|
+
```typescript
|
|
883
|
+
const range = new DateRange("2025-01-01", "2025-12-31");
|
|
884
|
+
|
|
885
|
+
// Contains — inclusive on both ends
|
|
886
|
+
range.contains("2025-06-15"); // true
|
|
887
|
+
range.contains("2024-12-31"); // false
|
|
888
|
+
range.contains("2026-01-01"); // false
|
|
889
|
+
|
|
890
|
+
// Overlaps — true unless one ends strictly before the other starts
|
|
891
|
+
const a = new DateRange("2025-01-01", "2025-06-30");
|
|
892
|
+
const b = new DateRange("2025-04-01", "2025-12-31");
|
|
893
|
+
const c = new DateRange("2026-01-01", "2026-12-31");
|
|
894
|
+
|
|
895
|
+
a.overlaps(b); // true (April–June overlap)
|
|
896
|
+
a.overlaps(c); // false (no overlap)
|
|
897
|
+
```
|
|
898
|
+
|
|
899
|
+
---
|
|
900
|
+
|
|
901
|
+
### Set Operations
|
|
902
|
+
|
|
903
|
+
```typescript
|
|
904
|
+
const a = new DateRange("2025-01-01", "2025-06-30");
|
|
905
|
+
const b = new DateRange("2025-04-01", "2025-12-31");
|
|
906
|
+
|
|
907
|
+
// Intersection — overlapping portion, or null
|
|
908
|
+
const overlap = a.intersection(b);
|
|
909
|
+
overlap?.start.format("YYYY-MM-DD"); // "2025-04-01"
|
|
910
|
+
overlap?.end.format("YYYY-MM-DD"); // "2025-06-30"
|
|
911
|
+
|
|
912
|
+
// Non-overlapping ranges
|
|
913
|
+
const p = new DateRange("2025-01-01", "2025-03-31");
|
|
914
|
+
const q = new DateRange("2025-07-01", "2025-12-31");
|
|
915
|
+
p.intersection(q); // null
|
|
916
|
+
|
|
917
|
+
// Union — smallest range covering both
|
|
918
|
+
const all = a.union(b);
|
|
919
|
+
all.start.format("YYYY-MM-DD"); // "2025-01-01"
|
|
920
|
+
all.end.format("YYYY-MM-DD"); // "2025-12-31"
|
|
921
|
+
```
|
|
922
|
+
|
|
923
|
+
---
|
|
924
|
+
|
|
925
|
+
### Range Metrics
|
|
926
|
+
|
|
927
|
+
```typescript
|
|
928
|
+
const q1 = new DateRange("2025-01-01", "2025-03-31");
|
|
929
|
+
|
|
930
|
+
// Number of whole days
|
|
931
|
+
q1.days(); // 89
|
|
932
|
+
|
|
933
|
+
// Duration object (full precision)
|
|
934
|
+
q1.duration().asHours(); // 2136
|
|
935
|
+
q1.duration().humanize(); // "3 months"
|
|
936
|
+
|
|
937
|
+
// Iterate — returns DateKit[] at a given step
|
|
938
|
+
q1.toArray("week").map((d) => d.format("MMM D"));
|
|
939
|
+
// → ["Jan 1", "Jan 8", "Jan 15", ...]
|
|
940
|
+
|
|
941
|
+
q1.toArray("month").map((d) => d.format("MMMM"));
|
|
942
|
+
// → ["January", "February", "March"]
|
|
943
|
+
|
|
944
|
+
// Serialisation
|
|
945
|
+
q1.toString(); // "[2025-01-01T00:00:00.000Z / 2025-03-31T00:00:00.000Z]"
|
|
946
|
+
q1.toJSON(); // { start: "2025-01-01T00:00:00.000Z", end: "2025-03-31T00:00:00.000Z" }
|
|
748
947
|
```
|
|
749
948
|
|
|
750
949
|
---
|
|
@@ -768,7 +967,7 @@ const complex = new Duration({
|
|
|
768
967
|
days: 2,
|
|
769
968
|
hours: 5,
|
|
770
969
|
minutes: 30,
|
|
771
|
-
seconds: 15
|
|
970
|
+
seconds: 15,
|
|
772
971
|
});
|
|
773
972
|
|
|
774
973
|
// From DateKit factory
|
|
@@ -793,15 +992,15 @@ Convert durations to different units:
|
|
|
793
992
|
const duration = new Duration(90, "minutes");
|
|
794
993
|
|
|
795
994
|
duration.asMilliseconds(); // 5400000
|
|
796
|
-
duration.asSeconds();
|
|
797
|
-
duration.asMinutes();
|
|
798
|
-
duration.asHours();
|
|
799
|
-
duration.asDays();
|
|
800
|
-
duration.asWeeks();
|
|
995
|
+
duration.asSeconds(); // 5400
|
|
996
|
+
duration.asMinutes(); // 90
|
|
997
|
+
duration.asHours(); // 1.5
|
|
998
|
+
duration.asDays(); // 0.0625
|
|
999
|
+
duration.asWeeks(); // 0.00893...
|
|
801
1000
|
|
|
802
1001
|
// Approximate conversions
|
|
803
|
-
duration.asMonths();
|
|
804
|
-
duration.asYears();
|
|
1002
|
+
duration.asMonths(); // ~0.00205 (using 30.44 days/month)
|
|
1003
|
+
duration.asYears(); // ~0.00017 (using 365.25 days/year)
|
|
805
1004
|
|
|
806
1005
|
// Get structured object
|
|
807
1006
|
const complex = new Duration({ days: 2, hours: 5, minutes: 30 });
|
|
@@ -816,14 +1015,14 @@ complex.toObject();
|
|
|
816
1015
|
Human-readable duration strings:
|
|
817
1016
|
|
|
818
1017
|
```typescript
|
|
819
|
-
new Duration(30, "seconds").humanize();
|
|
820
|
-
new Duration(1, "minutes").humanize();
|
|
821
|
-
new Duration(45, "minutes").humanize();
|
|
822
|
-
new Duration(5, "hours").humanize();
|
|
823
|
-
new Duration(24, "hours").humanize();
|
|
824
|
-
new Duration(35, "days").humanize();
|
|
825
|
-
new Duration(400, "days").humanize();
|
|
826
|
-
new Duration(3, "years").humanize();
|
|
1018
|
+
new Duration(30, "seconds").humanize(); // "a few seconds"
|
|
1019
|
+
new Duration(1, "minutes").humanize(); // "a minute"
|
|
1020
|
+
new Duration(45, "minutes").humanize(); // "an hour"
|
|
1021
|
+
new Duration(5, "hours").humanize(); // "5 hours"
|
|
1022
|
+
new Duration(24, "hours").humanize(); // "a day"
|
|
1023
|
+
new Duration(35, "days").humanize(); // "a month"
|
|
1024
|
+
new Duration(400, "days").humanize(); // "a year"
|
|
1025
|
+
new Duration(3, "years").humanize(); // "3 years"
|
|
827
1026
|
```
|
|
828
1027
|
|
|
829
1028
|
---
|
|
@@ -837,7 +1036,7 @@ const hour = new Duration(1, "hours");
|
|
|
837
1036
|
const halfHour = new Duration(30, "minutes");
|
|
838
1037
|
|
|
839
1038
|
// Addition
|
|
840
|
-
hour.add(halfHour).asMinutes();
|
|
1039
|
+
hour.add(halfHour).asMinutes(); // 90
|
|
841
1040
|
|
|
842
1041
|
// Subtraction
|
|
843
1042
|
hour.subtract(halfHour).asMinutes(); // 30
|
|
@@ -855,69 +1054,71 @@ new Duration(2, "hours")
|
|
|
855
1054
|
|
|
856
1055
|
Transform DateKit instances:
|
|
857
1056
|
|
|
858
|
-
| Method
|
|
859
|
-
|
|
860
|
-
| `toDate()`
|
|
861
|
-
| `toISOString()` | `string`
|
|
862
|
-
| `toUnix()`
|
|
863
|
-
| `valueOf()`
|
|
864
|
-
| `toArray()`
|
|
865
|
-
| `toObject()`
|
|
866
|
-
| `toJSON()`
|
|
867
|
-
| `toString()`
|
|
1057
|
+
| Method | Returns | Description |
|
|
1058
|
+
| --------------- | ---------- | ----------------------------------------- |
|
|
1059
|
+
| `toDate()` | `Date` | Native Date object (copy) |
|
|
1060
|
+
| `toISOString()` | `string` | ISO 8601 format |
|
|
1061
|
+
| `toUnix()` | `number` | Unix timestamp (seconds) |
|
|
1062
|
+
| `valueOf()` | `number` | Unix timestamp (milliseconds) |
|
|
1063
|
+
| `toArray()` | `number[]` | `[year, month, date, hour, min, sec, ms]` |
|
|
1064
|
+
| `toObject()` | `object` | Structured date components |
|
|
1065
|
+
| `toJSON()` | `string` | ISO string (for serialization) |
|
|
1066
|
+
| `toString()` | `string` | Native Date string |
|
|
868
1067
|
|
|
869
1068
|
```typescript
|
|
870
1069
|
const date = new DateKit("2024-03-15T14:30:45.123Z");
|
|
871
1070
|
|
|
872
|
-
date.toDate();
|
|
873
|
-
date.toISOString();
|
|
874
|
-
date.toUnix();
|
|
875
|
-
date.valueOf();
|
|
876
|
-
date.toArray();
|
|
877
|
-
date.toObject();
|
|
1071
|
+
date.toDate(); // Date object
|
|
1072
|
+
date.toISOString(); // "2024-03-15T14:30:45.123Z"
|
|
1073
|
+
date.toUnix(); // 1710513045
|
|
1074
|
+
date.valueOf(); // 1710513045123
|
|
1075
|
+
date.toArray(); // [2024, 2, 15, 14, 30, 45, 123]
|
|
1076
|
+
date.toObject(); // { year: 2024, month: 2, date: 15, ... }
|
|
878
1077
|
```
|
|
879
1078
|
|
|
880
1079
|
---
|
|
881
1080
|
|
|
882
1081
|
## 📋 Format Tokens Reference
|
|
883
1082
|
|
|
884
|
-
| Category
|
|
885
|
-
|
|
886
|
-
| **Year**
|
|
887
|
-
|
|
|
888
|
-
| **Quarter**
|
|
889
|
-
|
|
|
890
|
-
| **Month**
|
|
891
|
-
|
|
|
892
|
-
|
|
|
893
|
-
|
|
|
894
|
-
|
|
|
895
|
-
| **Week**
|
|
896
|
-
|
|
|
897
|
-
| **
|
|
898
|
-
|
|
|
899
|
-
| | `
|
|
900
|
-
|
|
|
901
|
-
|
|
|
902
|
-
| | `
|
|
903
|
-
|
|
|
904
|
-
|
|
|
905
|
-
| | `
|
|
906
|
-
|
|
|
907
|
-
|
|
|
908
|
-
|
|
|
909
|
-
|
|
|
910
|
-
| **
|
|
911
|
-
|
|
|
912
|
-
| **
|
|
913
|
-
| | `
|
|
914
|
-
| | `
|
|
915
|
-
|
|
|
916
|
-
|
|
|
917
|
-
| **
|
|
918
|
-
|
|
|
919
|
-
| **
|
|
920
|
-
|
|
|
1083
|
+
| Category | Token | Output | Example |
|
|
1084
|
+
| ----------------- | ---------- | ------------------- | --------------- |
|
|
1085
|
+
| **Year** | `YYYY` | 4-digit year | `2024` |
|
|
1086
|
+
| | `YY` | 2-digit year | `24` |
|
|
1087
|
+
| **Quarter** | `Q` | Quarter number | `1` - `4` |
|
|
1088
|
+
| | `Qo` | Quarter ordinal | `1st`, `2nd` |
|
|
1089
|
+
| **Month** | `MMMM` | Full name | `March` |
|
|
1090
|
+
| | `MMM` | Short name | `Mar` |
|
|
1091
|
+
| | `MM` | 2-digit | `03` |
|
|
1092
|
+
| | `M` | Number | `3` |
|
|
1093
|
+
| | `Mo` | Ordinal | `3rd` |
|
|
1094
|
+
| **Week (ISO)** | `W` / `WW` | ISO week number | `11` / `11` |
|
|
1095
|
+
| | `Wo` | ISO week ordinal | `11th` |
|
|
1096
|
+
| **Week (locale)** | `w` / `ww` | Locale week number | `11` / `11` |
|
|
1097
|
+
| | `wo` | Locale week ordinal | `11th` |
|
|
1098
|
+
| **Day of Year** | `DDD` | Day number | `75` |
|
|
1099
|
+
| | `DDDD` | Padded | `075` |
|
|
1100
|
+
| | `DDDo` | Ordinal | `75th` |
|
|
1101
|
+
| **Day of Month** | `DD` | 2-digit | `15` |
|
|
1102
|
+
| | `D` | Number | `15` |
|
|
1103
|
+
| | `Do` | Ordinal | `15th` |
|
|
1104
|
+
| **Day of Week** | `dddd` | Full name | `Friday` |
|
|
1105
|
+
| | `ddd` | Short name | `Fri` |
|
|
1106
|
+
| | `dd` | Min name | `Fr` |
|
|
1107
|
+
| | `d` | Number (Sun=0) | `5` |
|
|
1108
|
+
| | `do` | Ordinal | `5th` |
|
|
1109
|
+
| **Hour** | `HH` / `H` | 24-hour | `14` / `14` |
|
|
1110
|
+
| | `hh` / `h` | 12-hour | `02` / `2` |
|
|
1111
|
+
| **Minute** | `mm` / `m` | Minutes | `30` / `30` |
|
|
1112
|
+
| **Second** | `ss` / `s` | Seconds | `45` / `45` |
|
|
1113
|
+
| **Millisecond** | `SSS` | 3-digit | `123` |
|
|
1114
|
+
| | `SS` | 2-digit | `12` |
|
|
1115
|
+
| | `S` | 1-digit | `1` |
|
|
1116
|
+
| **AM/PM** | `A` | Uppercase | `PM` |
|
|
1117
|
+
| | `a` | Lowercase | `pm` |
|
|
1118
|
+
| **Timezone** | `Z` | With colon | `+00:00` |
|
|
1119
|
+
| | `ZZ` | Compact | `+0000` |
|
|
1120
|
+
| **Unix** | `X` | Seconds | `1710513045` |
|
|
1121
|
+
| | `x` | Milliseconds | `1710513045123` |
|
|
921
1122
|
|
|
922
1123
|
---
|
|
923
1124
|
|
|
@@ -937,6 +1138,8 @@ import type {
|
|
|
937
1138
|
QuarterNumber,
|
|
938
1139
|
DayOfWeek,
|
|
939
1140
|
} from "@subrotosaha/datekit";
|
|
1141
|
+
|
|
1142
|
+
import { DateRange } from "@subrotosaha/datekit";
|
|
940
1143
|
```
|
|
941
1144
|
|
|
942
1145
|
<details>
|
|
@@ -948,8 +1151,15 @@ type DateInput = Date | string | number;
|
|
|
948
1151
|
|
|
949
1152
|
// Time manipulation units
|
|
950
1153
|
type TimeUnit =
|
|
951
|
-
| "millisecond"
|
|
952
|
-
| "
|
|
1154
|
+
| "millisecond"
|
|
1155
|
+
| "second"
|
|
1156
|
+
| "minute"
|
|
1157
|
+
| "hour"
|
|
1158
|
+
| "day"
|
|
1159
|
+
| "week"
|
|
1160
|
+
| "month"
|
|
1161
|
+
| "quarter"
|
|
1162
|
+
| "year";
|
|
953
1163
|
|
|
954
1164
|
// Days of the week (0 = Sunday)
|
|
955
1165
|
type DayOfWeek = 0 | 1 | 2 | 3 | 4 | 5 | 6;
|
|
@@ -959,16 +1169,16 @@ type QuarterNumber = 1 | 2 | 3 | 4;
|
|
|
959
1169
|
|
|
960
1170
|
// Configuration options
|
|
961
1171
|
interface DateKitConfig {
|
|
962
|
-
locale?: string;
|
|
963
|
-
weekStartsOn?: DayOfWeek;
|
|
964
|
-
timezone?: string;
|
|
965
|
-
strictParsing?: boolean;
|
|
1172
|
+
locale?: string; // Locale code (e.g., "en", "es")
|
|
1173
|
+
weekStartsOn?: DayOfWeek; // First day of week
|
|
1174
|
+
timezone?: string; // IANA timezone
|
|
1175
|
+
strictParsing?: boolean; // Strict date parsing
|
|
966
1176
|
}
|
|
967
1177
|
|
|
968
1178
|
// For set() method
|
|
969
1179
|
interface SetDateValues {
|
|
970
1180
|
year?: number;
|
|
971
|
-
month?: number;
|
|
1181
|
+
month?: number; // 0-indexed
|
|
972
1182
|
date?: number;
|
|
973
1183
|
hour?: number;
|
|
974
1184
|
minute?: number;
|
|
@@ -997,14 +1207,36 @@ interface DurationObject {
|
|
|
997
1207
|
// Locale configuration
|
|
998
1208
|
interface LocaleConfig {
|
|
999
1209
|
name: string;
|
|
1210
|
+
dir?: "ltr" | "rtl"; // Text direction (RTL for ar, ur)
|
|
1000
1211
|
weekdays: string[];
|
|
1001
1212
|
weekdaysShort: string[];
|
|
1002
1213
|
weekdaysMin: string[];
|
|
1003
1214
|
months: string[];
|
|
1004
1215
|
monthsShort: string[];
|
|
1005
1216
|
ordinal: (n: number) => string;
|
|
1006
|
-
relativeTime: {
|
|
1007
|
-
|
|
1217
|
+
relativeTime: {
|
|
1218
|
+
future: string; // e.g. "in %s"
|
|
1219
|
+
past: string; // e.g. "%s ago"
|
|
1220
|
+
s: string; // seconds
|
|
1221
|
+
m: string; // a minute
|
|
1222
|
+
mm: string | ((n: number) => string); // N minutes (supports plural functions)
|
|
1223
|
+
h: string; // an hour
|
|
1224
|
+
hh: string | ((n: number) => string); // N hours
|
|
1225
|
+
d: string; // a day
|
|
1226
|
+
dd: string | ((n: number) => string); // N days
|
|
1227
|
+
M: string; // a month
|
|
1228
|
+
MM: string | ((n: number) => string); // N months
|
|
1229
|
+
y: string; // a year
|
|
1230
|
+
yy: string | ((n: number) => string); // N years
|
|
1231
|
+
};
|
|
1232
|
+
calendar: {
|
|
1233
|
+
sameDay: string; // "[Today at] LT"
|
|
1234
|
+
nextDay: string; // "[Tomorrow at] LT"
|
|
1235
|
+
nextWeek: string; // "dddd [at] LT"
|
|
1236
|
+
lastDay: string; // "[Yesterday at] LT"
|
|
1237
|
+
lastWeek: string; // "[Last] dddd [at] LT"
|
|
1238
|
+
sameElse: string; // "L" (fallback format)
|
|
1239
|
+
};
|
|
1008
1240
|
}
|
|
1009
1241
|
```
|
|
1010
1242
|
|
|
@@ -1029,12 +1261,7 @@ const timezones = [
|
|
|
1029
1261
|
|
|
1030
1262
|
console.log("Meeting scheduled for 2 PM Dhaka time:");
|
|
1031
1263
|
timezones.forEach(({ city, tz }) => {
|
|
1032
|
-
const time = DateKit.convertTimezone(
|
|
1033
|
-
meetingTime,
|
|
1034
|
-
"Asia/Dhaka",
|
|
1035
|
-
tz,
|
|
1036
|
-
"h:mm A"
|
|
1037
|
-
);
|
|
1264
|
+
const time = DateKit.convertTimezone(meetingTime, "Asia/Dhaka", tz, "h:mm A");
|
|
1038
1265
|
console.log(` ${city}: ${time}`);
|
|
1039
1266
|
});
|
|
1040
1267
|
```
|
|
@@ -1046,13 +1273,14 @@ function getWeekDates(date: DateKit) {
|
|
|
1046
1273
|
const start = date.startOf("week");
|
|
1047
1274
|
return DateKit.eachDayOfInterval({
|
|
1048
1275
|
start: start.toISOString(),
|
|
1049
|
-
end: start.add(6, "day").toISOString()
|
|
1276
|
+
end: start.add(6, "day").toISOString(),
|
|
1050
1277
|
});
|
|
1051
1278
|
}
|
|
1052
1279
|
|
|
1053
1280
|
const thisWeek = getWeekDates(DateKit.now());
|
|
1054
|
-
thisWeek.forEach(day => {
|
|
1055
|
-
console.log(
|
|
1281
|
+
thisWeek.forEach((day) => {
|
|
1282
|
+
console.log(
|
|
1283
|
+
day.format("ddd, MMM D"),
|
|
1056
1284
|
day.isToday() ? "(today)" : "",
|
|
1057
1285
|
day.isWeekend() ? "🌴" : ""
|
|
1058
1286
|
);
|
|
@@ -1070,7 +1298,10 @@ function getNextBusinessDay(date: DateKit): DateKit {
|
|
|
1070
1298
|
return next;
|
|
1071
1299
|
}
|
|
1072
1300
|
|
|
1073
|
-
function calculateDeliveryDate(
|
|
1301
|
+
function calculateDeliveryDate(
|
|
1302
|
+
orderDate: DateKit,
|
|
1303
|
+
businessDays: number
|
|
1304
|
+
): DateKit {
|
|
1074
1305
|
return orderDate.addBusinessDays(businessDays);
|
|
1075
1306
|
}
|
|
1076
1307
|
|
|
@@ -1079,7 +1310,9 @@ const delivery = calculateDeliveryDate(order, 5);
|
|
|
1079
1310
|
|
|
1080
1311
|
console.log(`Ordered: ${order.format("dddd, MMMM D")}`);
|
|
1081
1312
|
console.log(`Estimated Delivery: ${delivery.format("dddd, MMMM D")}`);
|
|
1082
|
-
console.log(
|
|
1313
|
+
console.log(
|
|
1314
|
+
`(${order.businessDaysUntil(delivery.toISOString())} business days)`
|
|
1315
|
+
);
|
|
1083
1316
|
```
|
|
1084
1317
|
|
|
1085
1318
|
### Age Calculator
|
|
@@ -1089,18 +1322,20 @@ function formatAge(birthdate: DateKit): string {
|
|
|
1089
1322
|
const years = birthdate.age();
|
|
1090
1323
|
const months = DateKit.now().diff(birthdate.add(years, "year"), "month");
|
|
1091
1324
|
const days = DateKit.now().diff(
|
|
1092
|
-
birthdate.add(years, "year").add(months, "month"),
|
|
1325
|
+
birthdate.add(years, "year").add(months, "month"),
|
|
1093
1326
|
"day"
|
|
1094
1327
|
);
|
|
1095
|
-
|
|
1328
|
+
|
|
1096
1329
|
return `${years} years, ${months} months, ${days} days`;
|
|
1097
1330
|
}
|
|
1098
1331
|
|
|
1099
1332
|
const birthday = new DateKit("1990-05-15");
|
|
1100
1333
|
console.log(`Age: ${formatAge(birthday)}`);
|
|
1101
|
-
console.log(
|
|
1102
|
-
|
|
1103
|
-
|
|
1334
|
+
console.log(
|
|
1335
|
+
`Days until next birthday: ${birthday
|
|
1336
|
+
.setYear(DateKit.now().year() + 1)
|
|
1337
|
+
.diff(DateKit.now(), "day")}`
|
|
1338
|
+
);
|
|
1104
1339
|
```
|
|
1105
1340
|
|
|
1106
1341
|
---
|
|
@@ -1130,8 +1365,8 @@ All "mutating" methods return new instances:
|
|
|
1130
1365
|
const original = new DateKit("2024-03-15");
|
|
1131
1366
|
const modified = original.add(1, "day");
|
|
1132
1367
|
|
|
1133
|
-
original.format("YYYY-MM-DD");
|
|
1134
|
-
modified.format("YYYY-MM-DD");
|
|
1368
|
+
original.format("YYYY-MM-DD"); // "2024-03-15" (unchanged!)
|
|
1369
|
+
modified.format("YYYY-MM-DD"); // "2024-03-16"
|
|
1135
1370
|
```
|
|
1136
1371
|
|
|
1137
1372
|
### Month Overflow
|