chronos-ts 1.0.3 → 2.0.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 +251 -433
- package/dist/core/chronos.d.ts +460 -0
- package/dist/core/chronos.js +1259 -0
- package/dist/core/index.d.ts +9 -0
- package/dist/core/index.js +19 -0
- package/dist/core/interval.d.ts +289 -0
- package/dist/core/interval.js +689 -0
- package/dist/core/period-collection.d.ts +205 -0
- package/dist/core/period-collection.js +562 -0
- package/dist/core/period.d.ts +428 -0
- package/dist/core/period.js +1007 -0
- package/dist/core/timezone.d.ts +289 -0
- package/dist/core/timezone.js +671 -0
- package/dist/index.d.ts +50 -3
- package/dist/index.js +148 -7
- package/dist/locales/index.d.ts +66 -0
- package/dist/locales/index.js +847 -0
- package/dist/types/index.d.ts +428 -0
- package/dist/types/index.js +71 -0
- package/dist/utils/index.d.ts +127 -0
- package/dist/utils/index.js +656 -0
- package/package.json +19 -3
- package/dist/interval.d.ts +0 -61
- package/dist/interval.js +0 -82
- package/dist/period.d.ts +0 -185
- package/dist/period.js +0 -326
- package/dist/precision.d.ts +0 -24
- package/dist/precision.js +0 -46
- package/dist/utils.d.ts +0 -188
- package/dist/utils.js +0 -337
|
@@ -0,0 +1,1259 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Chronos - The ultimate TypeScript date/time library
|
|
4
|
+
* @module Chronos
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.Chronos = void 0;
|
|
8
|
+
const types_1 = require("../types");
|
|
9
|
+
const timezone_1 = require("./timezone");
|
|
10
|
+
const utils_1 = require("../utils");
|
|
11
|
+
const locales_1 = require("../locales");
|
|
12
|
+
// ============================================================================
|
|
13
|
+
// Global Configuration
|
|
14
|
+
// ============================================================================
|
|
15
|
+
let globalConfig = {
|
|
16
|
+
timezone: undefined,
|
|
17
|
+
locale: 'en',
|
|
18
|
+
weekStartsOn: types_1.DayOfWeek.Sunday,
|
|
19
|
+
firstWeekContainsDate: 1,
|
|
20
|
+
strict: false,
|
|
21
|
+
};
|
|
22
|
+
let testNow = null;
|
|
23
|
+
// ============================================================================
|
|
24
|
+
// Chronos Class
|
|
25
|
+
// ============================================================================
|
|
26
|
+
/**
|
|
27
|
+
* Chronos - A comprehensive date/time manipulation library
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```typescript
|
|
31
|
+
* // Create instances
|
|
32
|
+
* const now = Chronos.now();
|
|
33
|
+
* const date = Chronos.parse('2024-01-15');
|
|
34
|
+
* const birthday = Chronos.create(1990, 5, 15);
|
|
35
|
+
*
|
|
36
|
+
* // Manipulate
|
|
37
|
+
* const future = now.add(3, 'months').startOf('day');
|
|
38
|
+
* const past = now.subtract(1, 'year').endOf('month');
|
|
39
|
+
*
|
|
40
|
+
* // Compare
|
|
41
|
+
* const isAfter = date.isAfter(birthday);
|
|
42
|
+
* const diff = date.diff(birthday, 'years');
|
|
43
|
+
*
|
|
44
|
+
* // Format
|
|
45
|
+
* const formatted = now.format('YYYY-MM-DD HH:mm:ss');
|
|
46
|
+
* const relative = birthday.fromNow(); // "34 years ago"
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
class Chronos {
|
|
50
|
+
// ============================================================================
|
|
51
|
+
// Constructors
|
|
52
|
+
// ============================================================================
|
|
53
|
+
/**
|
|
54
|
+
* Create a new Chronos instance
|
|
55
|
+
*
|
|
56
|
+
* @param input - Date input (string, number, Date, or Chronos)
|
|
57
|
+
* @param timezone - Optional timezone
|
|
58
|
+
*/
|
|
59
|
+
constructor(input, timezone) {
|
|
60
|
+
var _a;
|
|
61
|
+
this._locale = (0, locales_1.getLocale)((_a = globalConfig.locale) !== null && _a !== void 0 ? _a : 'en');
|
|
62
|
+
this._timezone = timezone !== null && timezone !== void 0 ? timezone : globalConfig.timezone;
|
|
63
|
+
if (testNow && input === undefined) {
|
|
64
|
+
this._date = new Date(testNow._date);
|
|
65
|
+
}
|
|
66
|
+
else if (input === null || input === undefined) {
|
|
67
|
+
this._date = new Date();
|
|
68
|
+
}
|
|
69
|
+
else if (typeof input === 'number') {
|
|
70
|
+
this._date = new Date(input);
|
|
71
|
+
}
|
|
72
|
+
else if (typeof input === 'string') {
|
|
73
|
+
this._date = this.parseString(input);
|
|
74
|
+
}
|
|
75
|
+
else if ((0, utils_1.isDate)(input)) {
|
|
76
|
+
this._date = new Date(input);
|
|
77
|
+
}
|
|
78
|
+
else if ((0, utils_1.isChronosLike)(input)) {
|
|
79
|
+
this._date = input.toDate();
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
this._date = new Date();
|
|
83
|
+
}
|
|
84
|
+
if (!(0, utils_1.isValidDate)(this._date)) {
|
|
85
|
+
throw new Error(`Invalid date: ${input}`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Parse a date string
|
|
90
|
+
*/
|
|
91
|
+
parseString(input) {
|
|
92
|
+
// Try ISO 8601 first
|
|
93
|
+
const isoDate = new Date(input);
|
|
94
|
+
if ((0, utils_1.isValidDate)(isoDate)) {
|
|
95
|
+
return isoDate;
|
|
96
|
+
}
|
|
97
|
+
// Try common formats
|
|
98
|
+
const formats = [
|
|
99
|
+
/^(\d{4})-(\d{2})-(\d{2})$/,
|
|
100
|
+
/^(\d{2})\/(\d{2})\/(\d{4})$/,
|
|
101
|
+
/^(\d{4})\/(\d{2})\/(\d{2})$/,
|
|
102
|
+
];
|
|
103
|
+
for (const format of formats) {
|
|
104
|
+
const match = input.match(format);
|
|
105
|
+
if (match) {
|
|
106
|
+
const parsed = new Date(input);
|
|
107
|
+
if ((0, utils_1.isValidDate)(parsed)) {
|
|
108
|
+
return parsed;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
throw new Error(`Unable to parse date: ${input}`);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Helper to create a date from components in a specific timezone
|
|
116
|
+
*/
|
|
117
|
+
static dateFromComponents(components, timezone) {
|
|
118
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
119
|
+
const utcTime = Date.UTC((_a = components.year) !== null && _a !== void 0 ? _a : 1970, ((_b = components.month) !== null && _b !== void 0 ? _b : 1) - 1, (_c = components.day) !== null && _c !== void 0 ? _c : 1, (_d = components.hour) !== null && _d !== void 0 ? _d : 0, (_e = components.minute) !== null && _e !== void 0 ? _e : 0, (_f = components.second) !== null && _f !== void 0 ? _f : 0, (_g = components.millisecond) !== null && _g !== void 0 ? _g : 0);
|
|
120
|
+
const tz = new timezone_1.ChronosTimezone(timezone);
|
|
121
|
+
let offset = tz.getOffsetMinutes(new Date(utcTime));
|
|
122
|
+
let date = new Date(utcTime - offset * 60000);
|
|
123
|
+
// Refine offset (handle DST transitions)
|
|
124
|
+
for (let i = 0; i < 3; i++) {
|
|
125
|
+
const newOffset = tz.getOffsetMinutes(date);
|
|
126
|
+
if (newOffset === offset)
|
|
127
|
+
break;
|
|
128
|
+
offset = newOffset;
|
|
129
|
+
date = new Date(utcTime - offset * 60000);
|
|
130
|
+
}
|
|
131
|
+
return date;
|
|
132
|
+
}
|
|
133
|
+
// ============================================================================
|
|
134
|
+
// Static Factory Methods
|
|
135
|
+
// ============================================================================
|
|
136
|
+
/**
|
|
137
|
+
* Create a Chronos instance from various inputs
|
|
138
|
+
*
|
|
139
|
+
* @example
|
|
140
|
+
* ```typescript
|
|
141
|
+
* Chronos.parse('2024-01-15')
|
|
142
|
+
* Chronos.parse(1705276800000)
|
|
143
|
+
* Chronos.parse(new Date())
|
|
144
|
+
* ```
|
|
145
|
+
*/
|
|
146
|
+
static parse(input, timezone) {
|
|
147
|
+
return new Chronos(input, timezone);
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Create a Chronos instance for the current moment
|
|
151
|
+
*
|
|
152
|
+
* @example
|
|
153
|
+
* ```typescript
|
|
154
|
+
* const now = Chronos.now();
|
|
155
|
+
* ```
|
|
156
|
+
*/
|
|
157
|
+
static now(timezone) {
|
|
158
|
+
return new Chronos(undefined, timezone);
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Create a Chronos instance for today at midnight
|
|
162
|
+
*/
|
|
163
|
+
static today(timezone) {
|
|
164
|
+
return Chronos.now(timezone).startOf('day');
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Create a Chronos instance for tomorrow at midnight
|
|
168
|
+
*/
|
|
169
|
+
static tomorrow(timezone) {
|
|
170
|
+
return Chronos.today(timezone).add(1, 'day');
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Create a Chronos instance for yesterday at midnight
|
|
174
|
+
*/
|
|
175
|
+
static yesterday(timezone) {
|
|
176
|
+
return Chronos.today(timezone).subtract(1, 'day');
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Create a Chronos instance from individual components
|
|
180
|
+
* Month is 1-12 (like Carbon PHP)
|
|
181
|
+
*
|
|
182
|
+
* @example
|
|
183
|
+
* ```typescript
|
|
184
|
+
* Chronos.create(2024, 1, 15, 10, 30, 0) // Jan 15, 2024 10:30:00
|
|
185
|
+
* ```
|
|
186
|
+
*/
|
|
187
|
+
static create(year, month = 1, day = 1, hour = 0, minute = 0, second = 0, millisecond = 0, timezone) {
|
|
188
|
+
if (timezone) {
|
|
189
|
+
const date = Chronos.dateFromComponents({
|
|
190
|
+
year,
|
|
191
|
+
month,
|
|
192
|
+
day,
|
|
193
|
+
hour,
|
|
194
|
+
minute,
|
|
195
|
+
second,
|
|
196
|
+
millisecond,
|
|
197
|
+
}, timezone);
|
|
198
|
+
return new Chronos(date, timezone);
|
|
199
|
+
}
|
|
200
|
+
const date = new Date(year, month - 1, day, hour, minute, second, millisecond);
|
|
201
|
+
return new Chronos(date, timezone);
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Create a Chronos instance from a Unix timestamp (seconds)
|
|
205
|
+
*/
|
|
206
|
+
static fromUnix(timestamp, timezone) {
|
|
207
|
+
return new Chronos(timestamp * 1000, timezone);
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Create a Chronos instance from a Unix timestamp (milliseconds)
|
|
211
|
+
*/
|
|
212
|
+
static fromMillis(timestamp, timezone) {
|
|
213
|
+
return new Chronos(timestamp, timezone);
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Create a Chronos instance from components object
|
|
217
|
+
* Month in components is 1-12 (like Carbon PHP)
|
|
218
|
+
*/
|
|
219
|
+
static fromObject(components, timezone) {
|
|
220
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
221
|
+
if (timezone) {
|
|
222
|
+
const date = Chronos.dateFromComponents(components, timezone);
|
|
223
|
+
return new Chronos(date, timezone);
|
|
224
|
+
}
|
|
225
|
+
const now = new Date();
|
|
226
|
+
const date = new Date((_a = components.year) !== null && _a !== void 0 ? _a : now.getFullYear(), ((_b = components.month) !== null && _b !== void 0 ? _b : now.getMonth() + 1) - 1, (_c = components.day) !== null && _c !== void 0 ? _c : now.getDate(), (_d = components.hour) !== null && _d !== void 0 ? _d : 0, (_e = components.minute) !== null && _e !== void 0 ? _e : 0, (_f = components.second) !== null && _f !== void 0 ? _f : 0, (_g = components.millisecond) !== null && _g !== void 0 ? _g : 0);
|
|
227
|
+
return new Chronos(date, timezone);
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Create a Chronos instance from a format string
|
|
231
|
+
*
|
|
232
|
+
* @example
|
|
233
|
+
* ```typescript
|
|
234
|
+
* Chronos.fromFormat('15-01-2024', 'DD-MM-YYYY')
|
|
235
|
+
* ```
|
|
236
|
+
*/
|
|
237
|
+
static fromFormat(input, format, timezone) {
|
|
238
|
+
const components = {};
|
|
239
|
+
let inputIndex = 0;
|
|
240
|
+
const tokens = format.match(/(YYYY|YY|MM|M|DD|D|HH|H|mm|m|ss|s|SSS)/g) || [];
|
|
241
|
+
const literals = format.split(/(YYYY|YY|MM|M|DD|D|HH|H|mm|m|ss|s|SSS)/);
|
|
242
|
+
for (let i = 0; i < literals.length; i++) {
|
|
243
|
+
const literal = literals[i];
|
|
244
|
+
if (tokens.includes(literal)) {
|
|
245
|
+
let length = literal.length;
|
|
246
|
+
if (literal === 'M' ||
|
|
247
|
+
literal === 'D' ||
|
|
248
|
+
literal === 'H' ||
|
|
249
|
+
literal === 'm' ||
|
|
250
|
+
literal === 's') {
|
|
251
|
+
// Variable length, find next non-digit
|
|
252
|
+
length = input.slice(inputIndex).search(/\D/);
|
|
253
|
+
if (length === -1)
|
|
254
|
+
length = input.length - inputIndex;
|
|
255
|
+
}
|
|
256
|
+
const value = parseInt(input.slice(inputIndex, inputIndex + length), 10);
|
|
257
|
+
inputIndex += length;
|
|
258
|
+
switch (literal) {
|
|
259
|
+
case 'YYYY':
|
|
260
|
+
components.year = value;
|
|
261
|
+
break;
|
|
262
|
+
case 'YY':
|
|
263
|
+
components.year = value + (value >= 70 ? 1900 : 2000);
|
|
264
|
+
break;
|
|
265
|
+
case 'MM':
|
|
266
|
+
case 'M':
|
|
267
|
+
components.month = value; // Month is 1-12, fromObject expects 1-12
|
|
268
|
+
break;
|
|
269
|
+
case 'DD':
|
|
270
|
+
case 'D':
|
|
271
|
+
components.day = value;
|
|
272
|
+
break;
|
|
273
|
+
case 'HH':
|
|
274
|
+
case 'H':
|
|
275
|
+
components.hour = value;
|
|
276
|
+
break;
|
|
277
|
+
case 'mm':
|
|
278
|
+
case 'm':
|
|
279
|
+
components.minute = value;
|
|
280
|
+
break;
|
|
281
|
+
case 'ss':
|
|
282
|
+
case 's':
|
|
283
|
+
components.second = value;
|
|
284
|
+
break;
|
|
285
|
+
case 'SSS':
|
|
286
|
+
components.millisecond = value;
|
|
287
|
+
break;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
else {
|
|
291
|
+
inputIndex += literal.length;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
return Chronos.fromObject(components, timezone);
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Create the minimum possible date
|
|
298
|
+
*/
|
|
299
|
+
static min() {
|
|
300
|
+
return new Chronos(new Date(-8640000000000000));
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Create the maximum possible date
|
|
304
|
+
*/
|
|
305
|
+
static max() {
|
|
306
|
+
return new Chronos(new Date(8640000000000000));
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Get the earliest of multiple dates
|
|
310
|
+
*/
|
|
311
|
+
static earliest(...dates) {
|
|
312
|
+
const parsed = dates.map((d) => Chronos.parse(d));
|
|
313
|
+
return parsed.reduce((min, d) => (d.isBefore(min) ? d : min));
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Get the latest of multiple dates
|
|
317
|
+
*/
|
|
318
|
+
static latest(...dates) {
|
|
319
|
+
const parsed = dates.map((d) => Chronos.parse(d));
|
|
320
|
+
return parsed.reduce((max, d) => (d.isAfter(max) ? d : max));
|
|
321
|
+
}
|
|
322
|
+
// ============================================================================
|
|
323
|
+
// Getters
|
|
324
|
+
// ============================================================================
|
|
325
|
+
/** Get the year */
|
|
326
|
+
get year() {
|
|
327
|
+
if (this._timezone) {
|
|
328
|
+
return new timezone_1.ChronosTimezone(this._timezone).getComponents(this._date).year;
|
|
329
|
+
}
|
|
330
|
+
return this._date.getFullYear();
|
|
331
|
+
}
|
|
332
|
+
/** Get the month (1-12) */
|
|
333
|
+
get month() {
|
|
334
|
+
if (this._timezone) {
|
|
335
|
+
return new timezone_1.ChronosTimezone(this._timezone).getComponents(this._date)
|
|
336
|
+
.month;
|
|
337
|
+
}
|
|
338
|
+
return this._date.getMonth() + 1;
|
|
339
|
+
}
|
|
340
|
+
/** Get the day of month (1-31) */
|
|
341
|
+
get date() {
|
|
342
|
+
if (this._timezone) {
|
|
343
|
+
return new timezone_1.ChronosTimezone(this._timezone).getComponents(this._date).day;
|
|
344
|
+
}
|
|
345
|
+
return this._date.getDate();
|
|
346
|
+
}
|
|
347
|
+
/** Alias for date */
|
|
348
|
+
get day() {
|
|
349
|
+
return this.date;
|
|
350
|
+
}
|
|
351
|
+
/** Get the day of week (0-6, Sunday = 0) */
|
|
352
|
+
get dayOfWeek() {
|
|
353
|
+
if (this._timezone) {
|
|
354
|
+
return new timezone_1.ChronosTimezone(this._timezone).getComponents(this._date)
|
|
355
|
+
.dayOfWeek;
|
|
356
|
+
}
|
|
357
|
+
return this._date.getDay();
|
|
358
|
+
}
|
|
359
|
+
/** Get the hour (0-23) */
|
|
360
|
+
get hour() {
|
|
361
|
+
if (this._timezone) {
|
|
362
|
+
return new timezone_1.ChronosTimezone(this._timezone).getComponents(this._date).hour;
|
|
363
|
+
}
|
|
364
|
+
return this._date.getHours();
|
|
365
|
+
}
|
|
366
|
+
/** Get the minute (0-59) */
|
|
367
|
+
get minute() {
|
|
368
|
+
if (this._timezone) {
|
|
369
|
+
return new timezone_1.ChronosTimezone(this._timezone).getComponents(this._date)
|
|
370
|
+
.minute;
|
|
371
|
+
}
|
|
372
|
+
return this._date.getMinutes();
|
|
373
|
+
}
|
|
374
|
+
/** Get the second (0-59) */
|
|
375
|
+
get second() {
|
|
376
|
+
if (this._timezone) {
|
|
377
|
+
return new timezone_1.ChronosTimezone(this._timezone).getComponents(this._date)
|
|
378
|
+
.second;
|
|
379
|
+
}
|
|
380
|
+
return this._date.getSeconds();
|
|
381
|
+
}
|
|
382
|
+
/** Get the millisecond (0-999) */
|
|
383
|
+
get millisecond() {
|
|
384
|
+
return this._date.getMilliseconds();
|
|
385
|
+
}
|
|
386
|
+
/** Get Unix timestamp (seconds) */
|
|
387
|
+
get unix() {
|
|
388
|
+
return Math.floor(this._date.getTime() / 1000);
|
|
389
|
+
}
|
|
390
|
+
/** Get Unix timestamp (milliseconds) */
|
|
391
|
+
get timestamp() {
|
|
392
|
+
return this._date.getTime();
|
|
393
|
+
}
|
|
394
|
+
/** Get the quarter (1-4) */
|
|
395
|
+
get quarter() {
|
|
396
|
+
return (0, utils_1.getQuarter)(this._date);
|
|
397
|
+
}
|
|
398
|
+
/** Get the day of year (1-366) */
|
|
399
|
+
get dayOfYear() {
|
|
400
|
+
return (0, utils_1.getDayOfYear)(this._date);
|
|
401
|
+
}
|
|
402
|
+
/** Get the ISO week number (1-53) */
|
|
403
|
+
get week() {
|
|
404
|
+
return (0, utils_1.getISOWeek)(this._date);
|
|
405
|
+
}
|
|
406
|
+
/** Get the ISO week year */
|
|
407
|
+
get weekYear() {
|
|
408
|
+
return (0, utils_1.getISOWeekYear)(this._date);
|
|
409
|
+
}
|
|
410
|
+
/** Get the number of days in the current month */
|
|
411
|
+
get daysInMonth() {
|
|
412
|
+
return (0, utils_1.getDaysInMonth)(this.year, this.month - 1);
|
|
413
|
+
}
|
|
414
|
+
/** Get the number of days in the current year */
|
|
415
|
+
get daysInYear() {
|
|
416
|
+
return (0, utils_1.getDaysInYear)(this.year);
|
|
417
|
+
}
|
|
418
|
+
/** Get the number of weeks in the current year */
|
|
419
|
+
get weeksInYear() {
|
|
420
|
+
return (0, utils_1.getISOWeek)(new Date(this.year, 11, 28));
|
|
421
|
+
}
|
|
422
|
+
/** Check if the year is a leap year */
|
|
423
|
+
get isLeapYear() {
|
|
424
|
+
return (0, utils_1.isLeapYear)(this.year);
|
|
425
|
+
}
|
|
426
|
+
/** Get the timezone offset in minutes */
|
|
427
|
+
get offset() {
|
|
428
|
+
return this._date.getTimezoneOffset();
|
|
429
|
+
}
|
|
430
|
+
/** Get the timezone offset as string (+05:30) */
|
|
431
|
+
get offsetString() {
|
|
432
|
+
const offset = this.offset;
|
|
433
|
+
const sign = offset <= 0 ? '+' : '-';
|
|
434
|
+
const hours = Math.floor(Math.abs(offset) / 60);
|
|
435
|
+
const minutes = Math.abs(offset) % 60;
|
|
436
|
+
return `${sign}${(0, utils_1.padStart)(hours, 2)}:${(0, utils_1.padStart)(minutes, 2)}`;
|
|
437
|
+
}
|
|
438
|
+
// ============================================================================
|
|
439
|
+
// Setters (Immutable)
|
|
440
|
+
// ============================================================================
|
|
441
|
+
/**
|
|
442
|
+
* Set specific date/time components
|
|
443
|
+
* Returns a new Chronos instance
|
|
444
|
+
*/
|
|
445
|
+
/**
|
|
446
|
+
* Set multiple date/time values at once
|
|
447
|
+
* Month is 1-12 (like Carbon PHP)
|
|
448
|
+
*/
|
|
449
|
+
set(values) {
|
|
450
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
451
|
+
if (this._timezone) {
|
|
452
|
+
const tz = new timezone_1.ChronosTimezone(this._timezone);
|
|
453
|
+
const current = tz.getComponents(this._date);
|
|
454
|
+
const components = {
|
|
455
|
+
year: (_a = values.year) !== null && _a !== void 0 ? _a : current.year,
|
|
456
|
+
month: (_b = values.month) !== null && _b !== void 0 ? _b : current.month,
|
|
457
|
+
day: (_d = (_c = values.date) !== null && _c !== void 0 ? _c : values.day) !== null && _d !== void 0 ? _d : current.day,
|
|
458
|
+
hour: (_e = values.hour) !== null && _e !== void 0 ? _e : current.hour,
|
|
459
|
+
minute: (_f = values.minute) !== null && _f !== void 0 ? _f : current.minute,
|
|
460
|
+
second: (_g = values.second) !== null && _g !== void 0 ? _g : current.second,
|
|
461
|
+
millisecond: (_h = values.millisecond) !== null && _h !== void 0 ? _h : this._date.getMilliseconds(),
|
|
462
|
+
};
|
|
463
|
+
const date = Chronos.dateFromComponents(components, this._timezone);
|
|
464
|
+
return new Chronos(date, this._timezone);
|
|
465
|
+
}
|
|
466
|
+
const date = (0, utils_1.cloneDate)(this._date);
|
|
467
|
+
if (values.year !== undefined)
|
|
468
|
+
date.setFullYear(values.year);
|
|
469
|
+
if (values.month !== undefined)
|
|
470
|
+
date.setMonth(values.month - 1);
|
|
471
|
+
if (values.date !== undefined || values.day !== undefined) {
|
|
472
|
+
date.setDate((_j = values.date) !== null && _j !== void 0 ? _j : values.day);
|
|
473
|
+
}
|
|
474
|
+
if (values.hour !== undefined)
|
|
475
|
+
date.setHours(values.hour);
|
|
476
|
+
if (values.minute !== undefined)
|
|
477
|
+
date.setMinutes(values.minute);
|
|
478
|
+
if (values.second !== undefined)
|
|
479
|
+
date.setSeconds(values.second);
|
|
480
|
+
if (values.millisecond !== undefined)
|
|
481
|
+
date.setMilliseconds(values.millisecond);
|
|
482
|
+
return new Chronos(date, this._timezone);
|
|
483
|
+
}
|
|
484
|
+
/** Set the year */
|
|
485
|
+
setYear(year) {
|
|
486
|
+
return this.set({ year });
|
|
487
|
+
}
|
|
488
|
+
/** Set the month (1-12) */
|
|
489
|
+
setMonth(month) {
|
|
490
|
+
return this.set({ month });
|
|
491
|
+
}
|
|
492
|
+
/** Set the day of month (1-31) */
|
|
493
|
+
setDate(date) {
|
|
494
|
+
return this.set({ date });
|
|
495
|
+
}
|
|
496
|
+
/** Set the hour (0-23) */
|
|
497
|
+
setHour(hour) {
|
|
498
|
+
return this.set({ hour });
|
|
499
|
+
}
|
|
500
|
+
/** Set the minute (0-59) */
|
|
501
|
+
setMinute(minute) {
|
|
502
|
+
return this.set({ minute });
|
|
503
|
+
}
|
|
504
|
+
/** Set the second (0-59) */
|
|
505
|
+
setSecond(second) {
|
|
506
|
+
return this.set({ second });
|
|
507
|
+
}
|
|
508
|
+
/** Set the millisecond (0-999) */
|
|
509
|
+
setMillisecond(millisecond) {
|
|
510
|
+
return this.set({ millisecond });
|
|
511
|
+
}
|
|
512
|
+
// ============================================================================
|
|
513
|
+
// Manipulation Methods
|
|
514
|
+
// ============================================================================
|
|
515
|
+
/**
|
|
516
|
+
* Add time to the date
|
|
517
|
+
*
|
|
518
|
+
* @example
|
|
519
|
+
* ```typescript
|
|
520
|
+
* chronos.add(5, 'days')
|
|
521
|
+
* chronos.add(2, 'months')
|
|
522
|
+
* chronos.add({ years: 1, months: 2 })
|
|
523
|
+
* ```
|
|
524
|
+
*/
|
|
525
|
+
add(amount, unit) {
|
|
526
|
+
if ((0, utils_1.isDuration)(amount)) {
|
|
527
|
+
let result = this.clone();
|
|
528
|
+
const duration = amount;
|
|
529
|
+
if (duration.years)
|
|
530
|
+
result = result.add(duration.years, 'years');
|
|
531
|
+
if (duration.months)
|
|
532
|
+
result = result.add(duration.months, 'months');
|
|
533
|
+
if (duration.weeks)
|
|
534
|
+
result = result.add(duration.weeks, 'weeks');
|
|
535
|
+
if (duration.days)
|
|
536
|
+
result = result.add(duration.days, 'days');
|
|
537
|
+
if (duration.hours)
|
|
538
|
+
result = result.add(duration.hours, 'hours');
|
|
539
|
+
if (duration.minutes)
|
|
540
|
+
result = result.add(duration.minutes, 'minutes');
|
|
541
|
+
if (duration.seconds)
|
|
542
|
+
result = result.add(duration.seconds, 'seconds');
|
|
543
|
+
if (duration.milliseconds)
|
|
544
|
+
result = result.add(duration.milliseconds, 'milliseconds');
|
|
545
|
+
return result;
|
|
546
|
+
}
|
|
547
|
+
if (unit === undefined) {
|
|
548
|
+
throw new Error('Unit is required when amount is a number');
|
|
549
|
+
}
|
|
550
|
+
const normalizedUnit = (0, utils_1.normalizeUnit)(unit);
|
|
551
|
+
const newDate = (0, utils_1.addUnits)(this._date, amount, normalizedUnit);
|
|
552
|
+
return new Chronos(newDate, this._timezone);
|
|
553
|
+
}
|
|
554
|
+
/**
|
|
555
|
+
* Subtract time from the date
|
|
556
|
+
*/
|
|
557
|
+
subtract(amount, unit) {
|
|
558
|
+
if ((0, utils_1.isDuration)(amount)) {
|
|
559
|
+
const negated = {};
|
|
560
|
+
for (const [key, value] of Object.entries(amount)) {
|
|
561
|
+
if (typeof value === 'number') {
|
|
562
|
+
negated[key] = -value;
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
return this.add(negated);
|
|
566
|
+
}
|
|
567
|
+
return this.add(-amount, unit);
|
|
568
|
+
}
|
|
569
|
+
/**
|
|
570
|
+
* Get the start of a time unit
|
|
571
|
+
*
|
|
572
|
+
* @example
|
|
573
|
+
* ```typescript
|
|
574
|
+
* chronos.startOf('day') // 00:00:00.000
|
|
575
|
+
* chronos.startOf('month') // First day of month
|
|
576
|
+
* chronos.startOf('year') // January 1st
|
|
577
|
+
* ```
|
|
578
|
+
*/
|
|
579
|
+
startOf(unit) {
|
|
580
|
+
const normalizedUnit = (0, utils_1.normalizeUnit)(unit);
|
|
581
|
+
const newDate = (0, utils_1.startOf)(this._date, normalizedUnit);
|
|
582
|
+
return new Chronos(newDate, this._timezone);
|
|
583
|
+
}
|
|
584
|
+
/**
|
|
585
|
+
* Get the end of a time unit
|
|
586
|
+
*
|
|
587
|
+
* @example
|
|
588
|
+
* ```typescript
|
|
589
|
+
* chronos.endOf('day') // 23:59:59.999
|
|
590
|
+
* chronos.endOf('month') // Last day of month
|
|
591
|
+
* chronos.endOf('year') // December 31st
|
|
592
|
+
* ```
|
|
593
|
+
*/
|
|
594
|
+
endOf(unit) {
|
|
595
|
+
const normalizedUnit = (0, utils_1.normalizeUnit)(unit);
|
|
596
|
+
const newDate = (0, utils_1.endOf)(this._date, normalizedUnit);
|
|
597
|
+
return new Chronos(newDate, this._timezone);
|
|
598
|
+
}
|
|
599
|
+
// ============================================================================
|
|
600
|
+
// Convenience Add/Subtract Methods
|
|
601
|
+
// ============================================================================
|
|
602
|
+
addMilliseconds(amount) {
|
|
603
|
+
return this.add(amount, 'milliseconds');
|
|
604
|
+
}
|
|
605
|
+
addSeconds(amount) {
|
|
606
|
+
return this.add(amount, 'seconds');
|
|
607
|
+
}
|
|
608
|
+
addMinutes(amount) {
|
|
609
|
+
return this.add(amount, 'minutes');
|
|
610
|
+
}
|
|
611
|
+
addHours(amount) {
|
|
612
|
+
return this.add(amount, 'hours');
|
|
613
|
+
}
|
|
614
|
+
addDays(amount) {
|
|
615
|
+
return this.add(amount, 'days');
|
|
616
|
+
}
|
|
617
|
+
addWeeks(amount) {
|
|
618
|
+
return this.add(amount, 'weeks');
|
|
619
|
+
}
|
|
620
|
+
addMonths(amount) {
|
|
621
|
+
return this.add(amount, 'months');
|
|
622
|
+
}
|
|
623
|
+
addQuarters(amount) {
|
|
624
|
+
return this.add(amount * 3, 'months');
|
|
625
|
+
}
|
|
626
|
+
addYears(amount) {
|
|
627
|
+
return this.add(amount, 'years');
|
|
628
|
+
}
|
|
629
|
+
subtractMilliseconds(amount) {
|
|
630
|
+
return this.subtract(amount, 'milliseconds');
|
|
631
|
+
}
|
|
632
|
+
subtractSeconds(amount) {
|
|
633
|
+
return this.subtract(amount, 'seconds');
|
|
634
|
+
}
|
|
635
|
+
subtractMinutes(amount) {
|
|
636
|
+
return this.subtract(amount, 'minutes');
|
|
637
|
+
}
|
|
638
|
+
subtractHours(amount) {
|
|
639
|
+
return this.subtract(amount, 'hours');
|
|
640
|
+
}
|
|
641
|
+
subtractDays(amount) {
|
|
642
|
+
return this.subtract(amount, 'days');
|
|
643
|
+
}
|
|
644
|
+
subtractWeeks(amount) {
|
|
645
|
+
return this.subtract(amount, 'weeks');
|
|
646
|
+
}
|
|
647
|
+
subtractMonths(amount) {
|
|
648
|
+
return this.subtract(amount, 'months');
|
|
649
|
+
}
|
|
650
|
+
subtractQuarters(amount) {
|
|
651
|
+
return this.subtract(amount * 3, 'months');
|
|
652
|
+
}
|
|
653
|
+
subtractYears(amount) {
|
|
654
|
+
return this.subtract(amount, 'years');
|
|
655
|
+
}
|
|
656
|
+
// ============================================================================
|
|
657
|
+
// Comparison Methods
|
|
658
|
+
// ============================================================================
|
|
659
|
+
/**
|
|
660
|
+
* Check if this date is before another
|
|
661
|
+
*/
|
|
662
|
+
isBefore(other, unit) {
|
|
663
|
+
const otherDate = Chronos.parse(other);
|
|
664
|
+
if (unit) {
|
|
665
|
+
const normalizedUnit = (0, utils_1.normalizeUnit)(unit);
|
|
666
|
+
return ((0, utils_1.startOf)(this._date, normalizedUnit) <
|
|
667
|
+
(0, utils_1.startOf)(otherDate._date, normalizedUnit));
|
|
668
|
+
}
|
|
669
|
+
return this._date < otherDate._date;
|
|
670
|
+
}
|
|
671
|
+
/**
|
|
672
|
+
* Check if this date is after another
|
|
673
|
+
*/
|
|
674
|
+
isAfter(other, unit) {
|
|
675
|
+
const otherDate = Chronos.parse(other);
|
|
676
|
+
if (unit) {
|
|
677
|
+
const normalizedUnit = (0, utils_1.normalizeUnit)(unit);
|
|
678
|
+
return ((0, utils_1.startOf)(this._date, normalizedUnit) >
|
|
679
|
+
(0, utils_1.startOf)(otherDate._date, normalizedUnit));
|
|
680
|
+
}
|
|
681
|
+
return this._date > otherDate._date;
|
|
682
|
+
}
|
|
683
|
+
/**
|
|
684
|
+
* Check if this date is the same as another
|
|
685
|
+
*/
|
|
686
|
+
isSame(other, unit) {
|
|
687
|
+
const otherDate = Chronos.parse(other);
|
|
688
|
+
if (unit) {
|
|
689
|
+
const normalizedUnit = (0, utils_1.normalizeUnit)(unit);
|
|
690
|
+
return ((0, utils_1.startOf)(this._date, normalizedUnit).getTime() ===
|
|
691
|
+
(0, utils_1.startOf)(otherDate._date, normalizedUnit).getTime());
|
|
692
|
+
}
|
|
693
|
+
return this._date.getTime() === otherDate._date.getTime();
|
|
694
|
+
}
|
|
695
|
+
/**
|
|
696
|
+
* Check if this date is same or before another
|
|
697
|
+
*/
|
|
698
|
+
isSameOrBefore(other, unit) {
|
|
699
|
+
return this.isSame(other, unit) || this.isBefore(other, unit);
|
|
700
|
+
}
|
|
701
|
+
/**
|
|
702
|
+
* Check if this date is same or after another
|
|
703
|
+
*/
|
|
704
|
+
isSameOrAfter(other, unit) {
|
|
705
|
+
return this.isSame(other, unit) || this.isAfter(other, unit);
|
|
706
|
+
}
|
|
707
|
+
/**
|
|
708
|
+
* Check if this date is between two others
|
|
709
|
+
*/
|
|
710
|
+
isBetween(start, end, unit, inclusivity = '()') {
|
|
711
|
+
const startDate = Chronos.parse(start);
|
|
712
|
+
const endDate = Chronos.parse(end);
|
|
713
|
+
const leftInclusive = inclusivity[0] === '[';
|
|
714
|
+
const rightInclusive = inclusivity[1] === ']';
|
|
715
|
+
const afterStart = leftInclusive
|
|
716
|
+
? this.isSameOrAfter(startDate, unit)
|
|
717
|
+
: this.isAfter(startDate, unit);
|
|
718
|
+
const beforeEnd = rightInclusive
|
|
719
|
+
? this.isSameOrBefore(endDate, unit)
|
|
720
|
+
: this.isBefore(endDate, unit);
|
|
721
|
+
return afterStart && beforeEnd;
|
|
722
|
+
}
|
|
723
|
+
// ============================================================================
|
|
724
|
+
// Day Type Checks
|
|
725
|
+
// ============================================================================
|
|
726
|
+
/** Check if this date is today */
|
|
727
|
+
isToday() {
|
|
728
|
+
return this.isSame(Chronos.today(), 'day');
|
|
729
|
+
}
|
|
730
|
+
/** Check if this date is tomorrow */
|
|
731
|
+
isTomorrow() {
|
|
732
|
+
return this.isSame(Chronos.tomorrow(), 'day');
|
|
733
|
+
}
|
|
734
|
+
/** Check if this date is yesterday */
|
|
735
|
+
isYesterday() {
|
|
736
|
+
return this.isSame(Chronos.yesterday(), 'day');
|
|
737
|
+
}
|
|
738
|
+
/** Check if this date is in the past */
|
|
739
|
+
isPast() {
|
|
740
|
+
return this.isBefore(Chronos.now());
|
|
741
|
+
}
|
|
742
|
+
/** Check if this date is in the future */
|
|
743
|
+
isFuture() {
|
|
744
|
+
return this.isAfter(Chronos.now());
|
|
745
|
+
}
|
|
746
|
+
/** Check if this is a weekend (Saturday or Sunday) */
|
|
747
|
+
isWeekend() {
|
|
748
|
+
return (this.dayOfWeek === types_1.DayOfWeek.Saturday ||
|
|
749
|
+
this.dayOfWeek === types_1.DayOfWeek.Sunday);
|
|
750
|
+
}
|
|
751
|
+
/** Check if this is a weekday (Monday-Friday) */
|
|
752
|
+
isWeekday() {
|
|
753
|
+
return !this.isWeekend();
|
|
754
|
+
}
|
|
755
|
+
// ============================================================================
|
|
756
|
+
// Specific Day Checks
|
|
757
|
+
// ============================================================================
|
|
758
|
+
isSunday() {
|
|
759
|
+
return this.dayOfWeek === types_1.DayOfWeek.Sunday;
|
|
760
|
+
}
|
|
761
|
+
isMonday() {
|
|
762
|
+
return this.dayOfWeek === types_1.DayOfWeek.Monday;
|
|
763
|
+
}
|
|
764
|
+
isTuesday() {
|
|
765
|
+
return this.dayOfWeek === types_1.DayOfWeek.Tuesday;
|
|
766
|
+
}
|
|
767
|
+
isWednesday() {
|
|
768
|
+
return this.dayOfWeek === types_1.DayOfWeek.Wednesday;
|
|
769
|
+
}
|
|
770
|
+
isThursday() {
|
|
771
|
+
return this.dayOfWeek === types_1.DayOfWeek.Thursday;
|
|
772
|
+
}
|
|
773
|
+
isFriday() {
|
|
774
|
+
return this.dayOfWeek === types_1.DayOfWeek.Friday;
|
|
775
|
+
}
|
|
776
|
+
isSaturday() {
|
|
777
|
+
return this.dayOfWeek === types_1.DayOfWeek.Saturday;
|
|
778
|
+
}
|
|
779
|
+
// ============================================================================
|
|
780
|
+
// Difference Methods
|
|
781
|
+
// ============================================================================
|
|
782
|
+
/**
|
|
783
|
+
* Get the difference between two dates in a specific unit
|
|
784
|
+
*/
|
|
785
|
+
diff(other, unit = 'millisecond', precise = false) {
|
|
786
|
+
const otherDate = Chronos.parse(other);
|
|
787
|
+
const normalizedUnit = (0, utils_1.normalizeUnit)(unit);
|
|
788
|
+
if (precise) {
|
|
789
|
+
const diffMs = this._date.getTime() - otherDate._date.getTime();
|
|
790
|
+
switch (normalizedUnit) {
|
|
791
|
+
case 'second':
|
|
792
|
+
return diffMs / utils_1.MILLISECONDS_PER_SECOND;
|
|
793
|
+
case 'minute':
|
|
794
|
+
return diffMs / utils_1.MILLISECONDS_PER_MINUTE;
|
|
795
|
+
case 'hour':
|
|
796
|
+
return diffMs / utils_1.MILLISECONDS_PER_HOUR;
|
|
797
|
+
case 'day':
|
|
798
|
+
return diffMs / utils_1.MILLISECONDS_PER_DAY;
|
|
799
|
+
case 'week':
|
|
800
|
+
return diffMs / (utils_1.MILLISECONDS_PER_DAY * 7);
|
|
801
|
+
default:
|
|
802
|
+
break;
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
return (0, utils_1.diffInUnits)(this._date, otherDate._date, normalizedUnit);
|
|
806
|
+
}
|
|
807
|
+
/**
|
|
808
|
+
* Get a detailed diff breakdown
|
|
809
|
+
*/
|
|
810
|
+
diffDetailed(other) {
|
|
811
|
+
const otherDate = Chronos.parse(other);
|
|
812
|
+
const diffMs = Math.abs(this._date.getTime() - otherDate._date.getTime());
|
|
813
|
+
let remaining = diffMs;
|
|
814
|
+
const years = Math.floor(remaining / (365.25 * utils_1.MILLISECONDS_PER_DAY));
|
|
815
|
+
remaining -= years * 365.25 * utils_1.MILLISECONDS_PER_DAY;
|
|
816
|
+
const months = Math.floor(remaining / (30.44 * utils_1.MILLISECONDS_PER_DAY));
|
|
817
|
+
remaining -= months * 30.44 * utils_1.MILLISECONDS_PER_DAY;
|
|
818
|
+
const weeks = Math.floor(remaining / (7 * utils_1.MILLISECONDS_PER_DAY));
|
|
819
|
+
remaining -= weeks * 7 * utils_1.MILLISECONDS_PER_DAY;
|
|
820
|
+
const days = Math.floor(remaining / utils_1.MILLISECONDS_PER_DAY);
|
|
821
|
+
remaining -= days * utils_1.MILLISECONDS_PER_DAY;
|
|
822
|
+
const hours = Math.floor(remaining / utils_1.MILLISECONDS_PER_HOUR);
|
|
823
|
+
remaining -= hours * utils_1.MILLISECONDS_PER_HOUR;
|
|
824
|
+
const minutes = Math.floor(remaining / utils_1.MILLISECONDS_PER_MINUTE);
|
|
825
|
+
remaining -= minutes * utils_1.MILLISECONDS_PER_MINUTE;
|
|
826
|
+
const seconds = Math.floor(remaining / utils_1.MILLISECONDS_PER_SECOND);
|
|
827
|
+
remaining -= seconds * utils_1.MILLISECONDS_PER_SECOND;
|
|
828
|
+
return {
|
|
829
|
+
years,
|
|
830
|
+
months,
|
|
831
|
+
weeks,
|
|
832
|
+
days,
|
|
833
|
+
hours,
|
|
834
|
+
minutes,
|
|
835
|
+
seconds,
|
|
836
|
+
milliseconds: remaining,
|
|
837
|
+
totalMilliseconds: diffMs,
|
|
838
|
+
};
|
|
839
|
+
}
|
|
840
|
+
// ============================================================================
|
|
841
|
+
// Human Readable Methods
|
|
842
|
+
// ============================================================================
|
|
843
|
+
/**
|
|
844
|
+
* Get a human-readable relative time string
|
|
845
|
+
*
|
|
846
|
+
* @example
|
|
847
|
+
* ```typescript
|
|
848
|
+
* date.fromNow() // "2 days ago"
|
|
849
|
+
* date.from(other) // "in 3 months"
|
|
850
|
+
* date.fromNow({ short: true }) // "2d ago"
|
|
851
|
+
* ```
|
|
852
|
+
*/
|
|
853
|
+
fromNow(options = {}) {
|
|
854
|
+
return this.from(Chronos.now(), options);
|
|
855
|
+
}
|
|
856
|
+
/**
|
|
857
|
+
* Get relative time from another date
|
|
858
|
+
*/
|
|
859
|
+
from(other, options = {}) {
|
|
860
|
+
var _a, _b;
|
|
861
|
+
const otherDate = Chronos.parse(other);
|
|
862
|
+
const diffMs = this._date.getTime() - otherDate._date.getTime();
|
|
863
|
+
const absDiff = Math.abs(diffMs);
|
|
864
|
+
const isFuture = diffMs > 0;
|
|
865
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
866
|
+
const { short: _short = false, absolute = false } = options;
|
|
867
|
+
const relative = this._locale.relativeTime;
|
|
868
|
+
let value;
|
|
869
|
+
let unit;
|
|
870
|
+
if (absDiff < utils_1.MILLISECONDS_PER_MINUTE) {
|
|
871
|
+
value = Math.round(absDiff / utils_1.MILLISECONDS_PER_SECOND);
|
|
872
|
+
unit = value === 1 ? 's' : 'ss';
|
|
873
|
+
}
|
|
874
|
+
else if (absDiff < utils_1.MILLISECONDS_PER_HOUR) {
|
|
875
|
+
value = Math.round(absDiff / utils_1.MILLISECONDS_PER_MINUTE);
|
|
876
|
+
unit = value === 1 ? 'm' : 'mm';
|
|
877
|
+
}
|
|
878
|
+
else if (absDiff < utils_1.MILLISECONDS_PER_DAY) {
|
|
879
|
+
value = Math.round(absDiff / utils_1.MILLISECONDS_PER_HOUR);
|
|
880
|
+
unit = value === 1 ? 'h' : 'hh';
|
|
881
|
+
}
|
|
882
|
+
else if (absDiff < utils_1.MILLISECONDS_PER_DAY * 7) {
|
|
883
|
+
value = Math.round(absDiff / utils_1.MILLISECONDS_PER_DAY);
|
|
884
|
+
unit = value === 1 ? 'd' : 'dd';
|
|
885
|
+
}
|
|
886
|
+
else if (absDiff < utils_1.MILLISECONDS_PER_DAY * 30) {
|
|
887
|
+
value = Math.round(absDiff / (utils_1.MILLISECONDS_PER_DAY * 7));
|
|
888
|
+
unit = value === 1 ? 'w' : 'ww';
|
|
889
|
+
}
|
|
890
|
+
else if (absDiff < utils_1.MILLISECONDS_PER_DAY * 365) {
|
|
891
|
+
value = Math.round(absDiff / (utils_1.MILLISECONDS_PER_DAY * 30));
|
|
892
|
+
unit = value === 1 ? 'M' : 'MM';
|
|
893
|
+
}
|
|
894
|
+
else {
|
|
895
|
+
value = Math.round(absDiff / (utils_1.MILLISECONDS_PER_DAY * 365));
|
|
896
|
+
unit = value === 1 ? 'y' : 'yy';
|
|
897
|
+
}
|
|
898
|
+
const relativeStr = (_b = (_a = relative[unit]) === null || _a === void 0 ? void 0 : _a.replace('%d', String(value))) !== null && _b !== void 0 ? _b : `${value} ${unit}`;
|
|
899
|
+
if (absolute) {
|
|
900
|
+
return relativeStr;
|
|
901
|
+
}
|
|
902
|
+
return isFuture
|
|
903
|
+
? relative.future.replace('%s', relativeStr)
|
|
904
|
+
: relative.past.replace('%s', relativeStr);
|
|
905
|
+
}
|
|
906
|
+
/**
|
|
907
|
+
* Get relative time to another date
|
|
908
|
+
*/
|
|
909
|
+
to(other, options = {}) {
|
|
910
|
+
return Chronos.parse(other).from(this, options);
|
|
911
|
+
}
|
|
912
|
+
/**
|
|
913
|
+
* Get relative time to now
|
|
914
|
+
*/
|
|
915
|
+
toNow(options = {}) {
|
|
916
|
+
return this.to(Chronos.now(), options);
|
|
917
|
+
}
|
|
918
|
+
// ============================================================================
|
|
919
|
+
// Formatting Methods
|
|
920
|
+
// ============================================================================
|
|
921
|
+
/**
|
|
922
|
+
* Format the date using a format string
|
|
923
|
+
*
|
|
924
|
+
* Supported tokens:
|
|
925
|
+
* - YYYY: 4-digit year
|
|
926
|
+
* - YY: 2-digit year
|
|
927
|
+
* - MMMM: Full month name
|
|
928
|
+
* - MMM: Short month name
|
|
929
|
+
* - MM: 2-digit month
|
|
930
|
+
* - M: 1-2 digit month
|
|
931
|
+
* - DD: 2-digit day
|
|
932
|
+
* - D: 1-2 digit day
|
|
933
|
+
* - dddd: Full weekday name
|
|
934
|
+
* - ddd: Short weekday name
|
|
935
|
+
* - dd: Min weekday name
|
|
936
|
+
* - d: Day of week number
|
|
937
|
+
* - HH: 2-digit hour (24h)
|
|
938
|
+
* - H: 1-2 digit hour (24h)
|
|
939
|
+
* - hh: 2-digit hour (12h)
|
|
940
|
+
* - h: 1-2 digit hour (12h)
|
|
941
|
+
* - mm: 2-digit minute
|
|
942
|
+
* - m: 1-2 digit minute
|
|
943
|
+
* - ss: 2-digit second
|
|
944
|
+
* - s: 1-2 digit second
|
|
945
|
+
* - SSS: 3-digit millisecond
|
|
946
|
+
* - A: AM/PM
|
|
947
|
+
* - a: am/pm
|
|
948
|
+
* - Z: Timezone offset (+05:00)
|
|
949
|
+
* - ZZ: Timezone offset (+0500)
|
|
950
|
+
*/
|
|
951
|
+
format(formatStr = 'YYYY-MM-DDTHH:mm:ssZ') {
|
|
952
|
+
const tokens = {
|
|
953
|
+
YYYY: () => String(this.year),
|
|
954
|
+
YY: () => String(this.year).slice(-2),
|
|
955
|
+
MMMM: () => this._locale.months[this.month - 1],
|
|
956
|
+
MMM: () => this._locale.monthsShort[this.month - 1],
|
|
957
|
+
MM: () => (0, utils_1.padStart)(this.month, 2),
|
|
958
|
+
M: () => String(this.month),
|
|
959
|
+
DD: () => (0, utils_1.padStart)(this.date, 2),
|
|
960
|
+
D: () => String(this.date),
|
|
961
|
+
dddd: () => this._locale.weekdays[this.dayOfWeek],
|
|
962
|
+
ddd: () => this._locale.weekdaysShort[this.dayOfWeek],
|
|
963
|
+
dd: () => this._locale.weekdaysMin[this.dayOfWeek],
|
|
964
|
+
d: () => String(this.dayOfWeek),
|
|
965
|
+
HH: () => (0, utils_1.padStart)(this.hour, 2),
|
|
966
|
+
H: () => String(this.hour),
|
|
967
|
+
hh: () => (0, utils_1.padStart)(this.hour % 12 || 12, 2),
|
|
968
|
+
h: () => String(this.hour % 12 || 12),
|
|
969
|
+
mm: () => (0, utils_1.padStart)(this.minute, 2),
|
|
970
|
+
m: () => String(this.minute),
|
|
971
|
+
ss: () => (0, utils_1.padStart)(this.second, 2),
|
|
972
|
+
s: () => String(this.second),
|
|
973
|
+
SSS: () => (0, utils_1.padStart)(this.millisecond, 3),
|
|
974
|
+
A: () => this._locale.meridiem
|
|
975
|
+
? this._locale.meridiem(this.hour, this.minute, false)
|
|
976
|
+
: this.hour < 12
|
|
977
|
+
? 'AM'
|
|
978
|
+
: 'PM',
|
|
979
|
+
a: () => this._locale.meridiem
|
|
980
|
+
? this._locale.meridiem(this.hour, this.minute, true)
|
|
981
|
+
: this.hour < 12
|
|
982
|
+
? 'am'
|
|
983
|
+
: 'pm',
|
|
984
|
+
Z: () => this.offsetString,
|
|
985
|
+
ZZ: () => this.offsetString.replace(':', ''),
|
|
986
|
+
Q: () => String(this.quarter),
|
|
987
|
+
Do: () => (0, utils_1.ordinalSuffix)(this.date),
|
|
988
|
+
W: () => String(this.week),
|
|
989
|
+
WW: () => (0, utils_1.padStart)(this.week, 2),
|
|
990
|
+
X: () => String(this.unix),
|
|
991
|
+
x: () => String(this.timestamp),
|
|
992
|
+
};
|
|
993
|
+
// Sort tokens by length (longest first) to avoid partial matches
|
|
994
|
+
const sortedTokens = Object.keys(tokens).sort((a, b) => b.length - a.length);
|
|
995
|
+
const regex = new RegExp(`\\[([^\\]]+)\\]|(${sortedTokens.join('|')})`, 'g');
|
|
996
|
+
return formatStr.replace(regex, (match, escaped, token) => {
|
|
997
|
+
var _a, _b;
|
|
998
|
+
if (escaped) {
|
|
999
|
+
return escaped;
|
|
1000
|
+
}
|
|
1001
|
+
return (_b = (_a = tokens[token]) === null || _a === void 0 ? void 0 : _a.call(tokens)) !== null && _b !== void 0 ? _b : match;
|
|
1002
|
+
});
|
|
1003
|
+
}
|
|
1004
|
+
// ============================================================================
|
|
1005
|
+
// Standard Format Methods
|
|
1006
|
+
// ============================================================================
|
|
1007
|
+
/** Format as ISO 8601 */
|
|
1008
|
+
toISOString() {
|
|
1009
|
+
return this._date.toISOString();
|
|
1010
|
+
}
|
|
1011
|
+
/** Format as ISO date (YYYY-MM-DD) */
|
|
1012
|
+
toDateString() {
|
|
1013
|
+
return this.format('YYYY-MM-DD');
|
|
1014
|
+
}
|
|
1015
|
+
/** Format as time (HH:mm:ss) */
|
|
1016
|
+
toTimeString() {
|
|
1017
|
+
return this.format('HH:mm:ss');
|
|
1018
|
+
}
|
|
1019
|
+
/** Format as datetime (YYYY-MM-DD HH:mm:ss) */
|
|
1020
|
+
toDateTimeString() {
|
|
1021
|
+
return this.format('YYYY-MM-DD HH:mm:ss');
|
|
1022
|
+
}
|
|
1023
|
+
/** Format as RFC 2822 */
|
|
1024
|
+
toRFC2822() {
|
|
1025
|
+
return this.format('ddd, DD MMM YYYY HH:mm:ss ZZ');
|
|
1026
|
+
}
|
|
1027
|
+
/** Format as RFC 3339 */
|
|
1028
|
+
toRFC3339() {
|
|
1029
|
+
return this.format('YYYY-MM-DDTHH:mm:ssZ');
|
|
1030
|
+
}
|
|
1031
|
+
/** Format as ATOM */
|
|
1032
|
+
toAtomString() {
|
|
1033
|
+
return this.format('YYYY-MM-DDTHH:mm:ssZ');
|
|
1034
|
+
}
|
|
1035
|
+
/** Format as Cookie */
|
|
1036
|
+
toCookieString() {
|
|
1037
|
+
return this.format('dddd, DD-MMM-YYYY HH:mm:ss Z');
|
|
1038
|
+
}
|
|
1039
|
+
/** Format as RSS */
|
|
1040
|
+
toRSSString() {
|
|
1041
|
+
return this.format('ddd, DD MMM YYYY HH:mm:ss ZZ');
|
|
1042
|
+
}
|
|
1043
|
+
/** Format as W3C */
|
|
1044
|
+
toW3CString() {
|
|
1045
|
+
return this.format('YYYY-MM-DDTHH:mm:ssZ');
|
|
1046
|
+
}
|
|
1047
|
+
// ============================================================================
|
|
1048
|
+
// Conversion Methods
|
|
1049
|
+
// ============================================================================
|
|
1050
|
+
/**
|
|
1051
|
+
* Convert to a specific timezone
|
|
1052
|
+
*/
|
|
1053
|
+
toTimezone(timezone) {
|
|
1054
|
+
return new Chronos(this._date, timezone);
|
|
1055
|
+
}
|
|
1056
|
+
/** Convert to native Date object */
|
|
1057
|
+
toDate() {
|
|
1058
|
+
return new Date(this._date);
|
|
1059
|
+
}
|
|
1060
|
+
/** Convert to array [year, month, day, hour, minute, second, millisecond] */
|
|
1061
|
+
toArray() {
|
|
1062
|
+
return [
|
|
1063
|
+
this.year,
|
|
1064
|
+
this.month,
|
|
1065
|
+
this.date,
|
|
1066
|
+
this.hour,
|
|
1067
|
+
this.minute,
|
|
1068
|
+
this.second,
|
|
1069
|
+
this.millisecond,
|
|
1070
|
+
];
|
|
1071
|
+
}
|
|
1072
|
+
/** Convert to object */
|
|
1073
|
+
toObject() {
|
|
1074
|
+
return {
|
|
1075
|
+
year: this.year,
|
|
1076
|
+
month: this.month,
|
|
1077
|
+
day: this.date,
|
|
1078
|
+
hour: this.hour,
|
|
1079
|
+
minute: this.minute,
|
|
1080
|
+
second: this.second,
|
|
1081
|
+
millisecond: this.millisecond,
|
|
1082
|
+
};
|
|
1083
|
+
}
|
|
1084
|
+
/** Convert to JSON-serializable object */
|
|
1085
|
+
toJSON() {
|
|
1086
|
+
var _a;
|
|
1087
|
+
return {
|
|
1088
|
+
iso: this.toISOString(),
|
|
1089
|
+
timestamp: this.timestamp,
|
|
1090
|
+
timezone: (_a = this._timezone) !== null && _a !== void 0 ? _a : 'local',
|
|
1091
|
+
};
|
|
1092
|
+
}
|
|
1093
|
+
/** Get primitive value (timestamp) */
|
|
1094
|
+
valueOf() {
|
|
1095
|
+
return this._date.getTime();
|
|
1096
|
+
}
|
|
1097
|
+
/** Convert to string */
|
|
1098
|
+
toString() {
|
|
1099
|
+
return this.toISOString();
|
|
1100
|
+
}
|
|
1101
|
+
// ============================================================================
|
|
1102
|
+
// Cloning and Locale
|
|
1103
|
+
// ============================================================================
|
|
1104
|
+
/**
|
|
1105
|
+
* Create a clone of this instance
|
|
1106
|
+
*/
|
|
1107
|
+
clone() {
|
|
1108
|
+
const cloned = new Chronos(this._date, this._timezone);
|
|
1109
|
+
cloned._locale = this._locale;
|
|
1110
|
+
return cloned;
|
|
1111
|
+
}
|
|
1112
|
+
/**
|
|
1113
|
+
* Set the locale for this instance
|
|
1114
|
+
*/
|
|
1115
|
+
locale(code) {
|
|
1116
|
+
const cloned = this.clone();
|
|
1117
|
+
cloned._locale = (0, locales_1.getLocale)(code);
|
|
1118
|
+
return cloned;
|
|
1119
|
+
}
|
|
1120
|
+
/**
|
|
1121
|
+
* Get the current locale code
|
|
1122
|
+
*/
|
|
1123
|
+
getLocale() {
|
|
1124
|
+
return this._locale.code;
|
|
1125
|
+
}
|
|
1126
|
+
// ============================================================================
|
|
1127
|
+
// Navigation Methods
|
|
1128
|
+
// ============================================================================
|
|
1129
|
+
/**
|
|
1130
|
+
* Get the next occurrence of a specific day
|
|
1131
|
+
*/
|
|
1132
|
+
next(day) {
|
|
1133
|
+
const current = this.dayOfWeek;
|
|
1134
|
+
const daysToAdd = (day - current + 7) % 7 || 7;
|
|
1135
|
+
return this.addDays(daysToAdd);
|
|
1136
|
+
}
|
|
1137
|
+
/**
|
|
1138
|
+
* Get the previous occurrence of a specific day
|
|
1139
|
+
*/
|
|
1140
|
+
previous(day) {
|
|
1141
|
+
const current = this.dayOfWeek;
|
|
1142
|
+
const daysToSubtract = (current - day + 7) % 7 || 7;
|
|
1143
|
+
return this.subtractDays(daysToSubtract);
|
|
1144
|
+
}
|
|
1145
|
+
/**
|
|
1146
|
+
* Get the closest date (either this or other)
|
|
1147
|
+
*/
|
|
1148
|
+
closest(date1, date2) {
|
|
1149
|
+
const d1 = Chronos.parse(date1);
|
|
1150
|
+
const d2 = Chronos.parse(date2);
|
|
1151
|
+
const diff1 = Math.abs(this.diff(d1));
|
|
1152
|
+
const diff2 = Math.abs(this.diff(d2));
|
|
1153
|
+
return diff1 <= diff2 ? d1 : d2;
|
|
1154
|
+
}
|
|
1155
|
+
/**
|
|
1156
|
+
* Get the farthest date (either this or other)
|
|
1157
|
+
*/
|
|
1158
|
+
farthest(date1, date2) {
|
|
1159
|
+
const d1 = Chronos.parse(date1);
|
|
1160
|
+
const d2 = Chronos.parse(date2);
|
|
1161
|
+
const diff1 = Math.abs(this.diff(d1));
|
|
1162
|
+
const diff2 = Math.abs(this.diff(d2));
|
|
1163
|
+
return diff1 >= diff2 ? d1 : d2;
|
|
1164
|
+
}
|
|
1165
|
+
// ============================================================================
|
|
1166
|
+
// Static Configuration Methods
|
|
1167
|
+
// ============================================================================
|
|
1168
|
+
/**
|
|
1169
|
+
* Set global configuration
|
|
1170
|
+
*/
|
|
1171
|
+
static configure(config) {
|
|
1172
|
+
globalConfig = Object.assign(Object.assign({}, globalConfig), config);
|
|
1173
|
+
}
|
|
1174
|
+
/**
|
|
1175
|
+
* Get current global configuration
|
|
1176
|
+
*/
|
|
1177
|
+
static getConfig() {
|
|
1178
|
+
return Object.assign({}, globalConfig);
|
|
1179
|
+
}
|
|
1180
|
+
/**
|
|
1181
|
+
* Set test time (for testing purposes)
|
|
1182
|
+
*/
|
|
1183
|
+
static setTestNow(date) {
|
|
1184
|
+
testNow = date ? Chronos.parse(date) : null;
|
|
1185
|
+
}
|
|
1186
|
+
/**
|
|
1187
|
+
* Check if test mode is active
|
|
1188
|
+
*/
|
|
1189
|
+
static hasTestNow() {
|
|
1190
|
+
return testNow !== null;
|
|
1191
|
+
}
|
|
1192
|
+
/**
|
|
1193
|
+
* Get the test time
|
|
1194
|
+
*/
|
|
1195
|
+
static getTestNow() {
|
|
1196
|
+
var _a;
|
|
1197
|
+
return (_a = testNow === null || testNow === void 0 ? void 0 : testNow.clone()) !== null && _a !== void 0 ? _a : null;
|
|
1198
|
+
}
|
|
1199
|
+
// ============================================================================
|
|
1200
|
+
// Validation Methods
|
|
1201
|
+
// ============================================================================
|
|
1202
|
+
/**
|
|
1203
|
+
* Check if the date is valid
|
|
1204
|
+
*/
|
|
1205
|
+
isValid() {
|
|
1206
|
+
return (0, utils_1.isValidDate)(this._date);
|
|
1207
|
+
}
|
|
1208
|
+
/**
|
|
1209
|
+
* Check if this date is the same day as another (regardless of time)
|
|
1210
|
+
*/
|
|
1211
|
+
isSameDay(other) {
|
|
1212
|
+
return this.isSame(other, 'day');
|
|
1213
|
+
}
|
|
1214
|
+
/**
|
|
1215
|
+
* Check if this date is in the same month as another
|
|
1216
|
+
*/
|
|
1217
|
+
isSameMonth(other) {
|
|
1218
|
+
return this.isSame(other, 'month');
|
|
1219
|
+
}
|
|
1220
|
+
/**
|
|
1221
|
+
* Check if this date is in the same year as another
|
|
1222
|
+
*/
|
|
1223
|
+
isSameYear(other) {
|
|
1224
|
+
return this.isSame(other, 'year');
|
|
1225
|
+
}
|
|
1226
|
+
// ============================================================================
|
|
1227
|
+
// Calendar Methods
|
|
1228
|
+
// ============================================================================
|
|
1229
|
+
/**
|
|
1230
|
+
* Get calendar output for the current month
|
|
1231
|
+
*/
|
|
1232
|
+
calendar(referenceDate) {
|
|
1233
|
+
const ref = referenceDate ? Chronos.parse(referenceDate) : Chronos.now();
|
|
1234
|
+
const diffDays = this.diff(ref, 'days');
|
|
1235
|
+
if (this.isSame(ref, 'day')) {
|
|
1236
|
+
return `Today at ${this.format('h:mm A')}`;
|
|
1237
|
+
}
|
|
1238
|
+
else if (this.isSame(ref.addDays(1), 'day')) {
|
|
1239
|
+
return `Tomorrow at ${this.format('h:mm A')}`;
|
|
1240
|
+
}
|
|
1241
|
+
else if (this.isSame(ref.subtractDays(1), 'day')) {
|
|
1242
|
+
return `Yesterday at ${this.format('h:mm A')}`;
|
|
1243
|
+
}
|
|
1244
|
+
else if (diffDays > 0 && diffDays < 7) {
|
|
1245
|
+
return `${this.format('dddd')} at ${this.format('h:mm A')}`;
|
|
1246
|
+
}
|
|
1247
|
+
else if (diffDays < 0 && diffDays > -7) {
|
|
1248
|
+
return `Last ${this.format('dddd')} at ${this.format('h:mm A')}`;
|
|
1249
|
+
}
|
|
1250
|
+
else {
|
|
1251
|
+
return this.format('MM/DD/YYYY');
|
|
1252
|
+
}
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
exports.Chronos = Chronos;
|
|
1256
|
+
// ============================================================================
|
|
1257
|
+
// Export Default
|
|
1258
|
+
// ============================================================================
|
|
1259
|
+
exports.default = Chronos;
|