one-second 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +369 -0
- package/dist/index.d.ts +257 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +695 -0
- package/dist/index.js.map +1 -0
- package/package.json +64 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,695 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* date-lite - Ultra-lightweight date library using native Intl API
|
|
3
|
+
* Zero dependencies, ~2KB, immutable, tree-shakeable
|
|
4
|
+
*/
|
|
5
|
+
// ============================================
|
|
6
|
+
// Core: Parse to Date
|
|
7
|
+
// ============================================
|
|
8
|
+
/**
|
|
9
|
+
* Convert any input to a Date object
|
|
10
|
+
*/
|
|
11
|
+
export function toDate(input) {
|
|
12
|
+
if (input instanceof Date)
|
|
13
|
+
return new Date(input.getTime());
|
|
14
|
+
if (typeof input === 'number')
|
|
15
|
+
return new Date(input);
|
|
16
|
+
return new Date(input);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Check if input is a valid date
|
|
20
|
+
*/
|
|
21
|
+
export function isValid(input) {
|
|
22
|
+
const d = toDate(input);
|
|
23
|
+
return !isNaN(d.getTime());
|
|
24
|
+
}
|
|
25
|
+
// ============================================
|
|
26
|
+
// Formatting (using native Intl)
|
|
27
|
+
// ============================================
|
|
28
|
+
// Cache formatters for performance
|
|
29
|
+
const formatterCache = new Map();
|
|
30
|
+
function getFormatter(options) {
|
|
31
|
+
const key = JSON.stringify(options);
|
|
32
|
+
let formatter = formatterCache.get(key);
|
|
33
|
+
if (!formatter) {
|
|
34
|
+
const { locale, ...opts } = options;
|
|
35
|
+
formatter = new Intl.DateTimeFormat(locale, opts);
|
|
36
|
+
formatterCache.set(key, formatter);
|
|
37
|
+
}
|
|
38
|
+
return formatter;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Format date using Intl.DateTimeFormat
|
|
42
|
+
*/
|
|
43
|
+
export function format(input, options = {}) {
|
|
44
|
+
return getFormatter(options).format(toDate(input));
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Format date to ISO string (YYYY-MM-DD)
|
|
48
|
+
*/
|
|
49
|
+
export function toISO(input) {
|
|
50
|
+
const d = toDate(input);
|
|
51
|
+
const year = d.getFullYear();
|
|
52
|
+
const month = String(d.getMonth() + 1).padStart(2, '0');
|
|
53
|
+
const day = String(d.getDate()).padStart(2, '0');
|
|
54
|
+
return `${year}-${month}-${day}`;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Format time to HH:MM:SS
|
|
58
|
+
*/
|
|
59
|
+
export function toTime(input) {
|
|
60
|
+
const d = toDate(input);
|
|
61
|
+
const hours = String(d.getHours()).padStart(2, '0');
|
|
62
|
+
const minutes = String(d.getMinutes()).padStart(2, '0');
|
|
63
|
+
const seconds = String(d.getSeconds()).padStart(2, '0');
|
|
64
|
+
return `${hours}:${minutes}:${seconds}`;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Format to full ISO datetime string
|
|
68
|
+
*/
|
|
69
|
+
export function toISOString(input) {
|
|
70
|
+
return toDate(input).toISOString();
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Format date using format string (like dayjs/moment)
|
|
74
|
+
* Tokens: YYYY, YY, MM, M, DD, D, HH, H, mm, m, ss, s, SSS, ddd, dddd, MMM, MMMM, A, a
|
|
75
|
+
*/
|
|
76
|
+
export function formatStr(input, template, locale = 'en-US') {
|
|
77
|
+
const d = toDate(input);
|
|
78
|
+
const year = d.getFullYear();
|
|
79
|
+
const month = d.getMonth();
|
|
80
|
+
const date = d.getDate();
|
|
81
|
+
const day = d.getDay();
|
|
82
|
+
const hours = d.getHours();
|
|
83
|
+
const minutes = d.getMinutes();
|
|
84
|
+
const seconds = d.getSeconds();
|
|
85
|
+
const ms = d.getMilliseconds();
|
|
86
|
+
// Get localized names using Intl
|
|
87
|
+
const monthLong = new Intl.DateTimeFormat(locale, { month: 'long' }).format(d);
|
|
88
|
+
const monthShort = new Intl.DateTimeFormat(locale, { month: 'short' }).format(d);
|
|
89
|
+
const dayLong = new Intl.DateTimeFormat(locale, { weekday: 'long' }).format(d);
|
|
90
|
+
const dayShort = new Intl.DateTimeFormat(locale, { weekday: 'short' }).format(d);
|
|
91
|
+
const pad = (n, len = 2) => String(n).padStart(len, '0');
|
|
92
|
+
const tokens = {
|
|
93
|
+
'YYYY': String(year),
|
|
94
|
+
'YY': String(year).slice(-2),
|
|
95
|
+
'MMMM': monthLong,
|
|
96
|
+
'MMM': monthShort,
|
|
97
|
+
'MM': pad(month + 1),
|
|
98
|
+
'M': String(month + 1),
|
|
99
|
+
'DD': pad(date),
|
|
100
|
+
'D': String(date),
|
|
101
|
+
'dddd': dayLong,
|
|
102
|
+
'ddd': dayShort,
|
|
103
|
+
'HH': pad(hours),
|
|
104
|
+
'H': String(hours),
|
|
105
|
+
'hh': pad(hours % 12 || 12),
|
|
106
|
+
'h': String(hours % 12 || 12),
|
|
107
|
+
'mm': pad(minutes),
|
|
108
|
+
'm': String(minutes),
|
|
109
|
+
'ss': pad(seconds),
|
|
110
|
+
's': String(seconds),
|
|
111
|
+
'SSS': pad(ms, 3),
|
|
112
|
+
'A': hours < 12 ? 'AM' : 'PM',
|
|
113
|
+
'a': hours < 12 ? 'am' : 'pm',
|
|
114
|
+
};
|
|
115
|
+
// Sort by length (longest first) to match MMMM before MMM before MM before M
|
|
116
|
+
const pattern = Object.keys(tokens)
|
|
117
|
+
.sort((a, b) => b.length - a.length)
|
|
118
|
+
.join('|');
|
|
119
|
+
return template.replace(new RegExp(pattern, 'g'), match => tokens[match] || match);
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Parse date from string with format
|
|
123
|
+
* Tokens: YYYY, MM, DD, HH, mm, ss
|
|
124
|
+
*/
|
|
125
|
+
export function parse(dateStr, template) {
|
|
126
|
+
const tokenDefs = [
|
|
127
|
+
{ token: 'YYYY', regex: '(\\d{4})', field: 'year' },
|
|
128
|
+
{ token: 'YY', regex: '(\\d{2})', field: 'year', transform: (v) => 2000 + v },
|
|
129
|
+
{ token: 'MM', regex: '(\\d{2})', field: 'month', transform: (v) => v - 1 },
|
|
130
|
+
{ token: 'M', regex: '(\\d{1,2})', field: 'month', transform: (v) => v - 1 },
|
|
131
|
+
{ token: 'DD', regex: '(\\d{2})', field: 'day' },
|
|
132
|
+
{ token: 'D', regex: '(\\d{1,2})', field: 'day' },
|
|
133
|
+
{ token: 'HH', regex: '(\\d{2})', field: 'hour' },
|
|
134
|
+
{ token: 'H', regex: '(\\d{1,2})', field: 'hour' },
|
|
135
|
+
{ token: 'mm', regex: '(\\d{2})', field: 'minute' },
|
|
136
|
+
{ token: 'm', regex: '(\\d{1,2})', field: 'minute' },
|
|
137
|
+
{ token: 'ss', regex: '(\\d{2})', field: 'second' },
|
|
138
|
+
{ token: 's', regex: '(\\d{1,2})', field: 'second' },
|
|
139
|
+
{ token: 'SSS', regex: '(\\d{3})', field: 'ms' },
|
|
140
|
+
];
|
|
141
|
+
// Sort by token length (longest first) to avoid partial matches
|
|
142
|
+
const sortedDefs = [...tokenDefs].sort((a, b) => b.token.length - a.token.length);
|
|
143
|
+
// Find which tokens are in the template and their positions
|
|
144
|
+
const foundTokens = [];
|
|
145
|
+
let searchTemplate = template;
|
|
146
|
+
for (const def of sortedDefs) {
|
|
147
|
+
let pos = searchTemplate.indexOf(def.token);
|
|
148
|
+
while (pos !== -1) {
|
|
149
|
+
foundTokens.push({ pos, def });
|
|
150
|
+
// Replace with placeholder to avoid double-matching
|
|
151
|
+
searchTemplate = searchTemplate.substring(0, pos) + '\x00'.repeat(def.token.length) + searchTemplate.substring(pos + def.token.length);
|
|
152
|
+
pos = searchTemplate.indexOf(def.token);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
// Sort by position
|
|
156
|
+
foundTokens.sort((a, b) => a.pos - b.pos);
|
|
157
|
+
// Build regex pattern
|
|
158
|
+
let pattern = template;
|
|
159
|
+
// Escape special regex chars first
|
|
160
|
+
pattern = pattern.replace(/[.*+?^${}|[\]\\]/g, '\\$&');
|
|
161
|
+
// Replace tokens with their regex patterns (in reverse order to maintain positions)
|
|
162
|
+
for (const { def } of [...foundTokens].reverse().sort((a, b) => b.pos - a.pos)) {
|
|
163
|
+
const escaped = def.token.replace(/[.*+?^${}|[\]\\]/g, '\\$&');
|
|
164
|
+
pattern = pattern.replace(escaped, def.regex);
|
|
165
|
+
}
|
|
166
|
+
const regex = new RegExp('^' + pattern + '$');
|
|
167
|
+
const match = dateStr.match(regex);
|
|
168
|
+
if (!match) {
|
|
169
|
+
return new Date(NaN);
|
|
170
|
+
}
|
|
171
|
+
const parts = {
|
|
172
|
+
year: new Date().getFullYear(),
|
|
173
|
+
month: 0,
|
|
174
|
+
day: 1,
|
|
175
|
+
hour: 0,
|
|
176
|
+
minute: 0,
|
|
177
|
+
second: 0,
|
|
178
|
+
ms: 0,
|
|
179
|
+
};
|
|
180
|
+
// Apply matches in order
|
|
181
|
+
for (let i = 0; i < foundTokens.length; i++) {
|
|
182
|
+
const { def } = foundTokens[i];
|
|
183
|
+
let value = parseInt(match[i + 1], 10);
|
|
184
|
+
if (def.transform) {
|
|
185
|
+
value = def.transform(value);
|
|
186
|
+
}
|
|
187
|
+
parts[def.field] = value;
|
|
188
|
+
}
|
|
189
|
+
return new Date(parts.year, parts.month, parts.day, parts.hour, parts.minute, parts.second, parts.ms);
|
|
190
|
+
}
|
|
191
|
+
// Preset formats
|
|
192
|
+
export function formatDate(input, locale = 'en-US') {
|
|
193
|
+
return format(input, { locale, year: 'numeric', month: 'short', day: 'numeric' });
|
|
194
|
+
}
|
|
195
|
+
export function formatDateTime(input, locale = 'en-US') {
|
|
196
|
+
return format(input, {
|
|
197
|
+
locale,
|
|
198
|
+
year: 'numeric',
|
|
199
|
+
month: 'short',
|
|
200
|
+
day: 'numeric',
|
|
201
|
+
hour: '2-digit',
|
|
202
|
+
minute: '2-digit',
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
export function formatTime(input, locale = 'en-US') {
|
|
206
|
+
return format(input, { locale, hour: '2-digit', minute: '2-digit' });
|
|
207
|
+
}
|
|
208
|
+
// ============================================
|
|
209
|
+
// Relative Time (using native Intl.RelativeTimeFormat)
|
|
210
|
+
// ============================================
|
|
211
|
+
const rtfCache = new Map();
|
|
212
|
+
function getRelativeFormatter(options) {
|
|
213
|
+
const key = JSON.stringify(options);
|
|
214
|
+
let formatter = rtfCache.get(key);
|
|
215
|
+
if (!formatter) {
|
|
216
|
+
const { locale = 'en', ...opts } = options;
|
|
217
|
+
formatter = new Intl.RelativeTimeFormat(locale, opts);
|
|
218
|
+
rtfCache.set(key, formatter);
|
|
219
|
+
}
|
|
220
|
+
return formatter;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Get relative time string (e.g., "2 hours ago", "in 3 days")
|
|
224
|
+
*/
|
|
225
|
+
export function relative(input, options = {}) {
|
|
226
|
+
const d = toDate(input);
|
|
227
|
+
const now = Date.now();
|
|
228
|
+
const diffMs = d.getTime() - now;
|
|
229
|
+
const diffSec = Math.round(diffMs / 1000);
|
|
230
|
+
const diffMin = Math.round(diffSec / 60);
|
|
231
|
+
const diffHour = Math.round(diffMin / 60);
|
|
232
|
+
const diffDay = Math.round(diffHour / 24);
|
|
233
|
+
const diffWeek = Math.round(diffDay / 7);
|
|
234
|
+
const diffMonth = Math.round(diffDay / 30);
|
|
235
|
+
const diffYear = Math.round(diffDay / 365);
|
|
236
|
+
const rtf = getRelativeFormatter({ numeric: 'auto', ...options });
|
|
237
|
+
if (Math.abs(diffSec) < 60)
|
|
238
|
+
return rtf.format(diffSec, 'second');
|
|
239
|
+
if (Math.abs(diffMin) < 60)
|
|
240
|
+
return rtf.format(diffMin, 'minute');
|
|
241
|
+
if (Math.abs(diffHour) < 24)
|
|
242
|
+
return rtf.format(diffHour, 'hour');
|
|
243
|
+
if (Math.abs(diffDay) < 7)
|
|
244
|
+
return rtf.format(diffDay, 'day');
|
|
245
|
+
if (Math.abs(diffWeek) < 4)
|
|
246
|
+
return rtf.format(diffWeek, 'week');
|
|
247
|
+
if (Math.abs(diffMonth) < 12)
|
|
248
|
+
return rtf.format(diffMonth, 'month');
|
|
249
|
+
return rtf.format(diffYear, 'year');
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Get human-readable time ago string
|
|
253
|
+
*/
|
|
254
|
+
export function timeAgo(input, locale = 'en') {
|
|
255
|
+
return relative(input, { locale, numeric: 'auto' });
|
|
256
|
+
}
|
|
257
|
+
// ============================================
|
|
258
|
+
// Date Arithmetic (immutable - returns new Date)
|
|
259
|
+
// ============================================
|
|
260
|
+
/**
|
|
261
|
+
* Add time to a date (returns new Date)
|
|
262
|
+
*/
|
|
263
|
+
export function add(input, amount, unit) {
|
|
264
|
+
const d = toDate(input);
|
|
265
|
+
switch (unit) {
|
|
266
|
+
case 'year':
|
|
267
|
+
return new Date(d.getFullYear() + amount, d.getMonth(), d.getDate(), d.getHours(), d.getMinutes(), d.getSeconds(), d.getMilliseconds());
|
|
268
|
+
case 'month':
|
|
269
|
+
return new Date(d.getFullYear(), d.getMonth() + amount, d.getDate(), d.getHours(), d.getMinutes(), d.getSeconds(), d.getMilliseconds());
|
|
270
|
+
case 'week':
|
|
271
|
+
return new Date(d.getTime() + amount * 7 * 24 * 60 * 60 * 1000);
|
|
272
|
+
case 'day':
|
|
273
|
+
return new Date(d.getTime() + amount * 24 * 60 * 60 * 1000);
|
|
274
|
+
case 'hour':
|
|
275
|
+
return new Date(d.getTime() + amount * 60 * 60 * 1000);
|
|
276
|
+
case 'minute':
|
|
277
|
+
return new Date(d.getTime() + amount * 60 * 1000);
|
|
278
|
+
case 'second':
|
|
279
|
+
return new Date(d.getTime() + amount * 1000);
|
|
280
|
+
case 'millisecond':
|
|
281
|
+
return new Date(d.getTime() + amount);
|
|
282
|
+
default:
|
|
283
|
+
return d;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Subtract time from a date (returns new Date)
|
|
288
|
+
*/
|
|
289
|
+
export function subtract(input, amount, unit) {
|
|
290
|
+
return add(input, -amount, unit);
|
|
291
|
+
}
|
|
292
|
+
// Convenience methods
|
|
293
|
+
export const addYears = (input, n) => add(input, n, 'year');
|
|
294
|
+
export const addMonths = (input, n) => add(input, n, 'month');
|
|
295
|
+
export const addWeeks = (input, n) => add(input, n, 'week');
|
|
296
|
+
export const addDays = (input, n) => add(input, n, 'day');
|
|
297
|
+
export const addHours = (input, n) => add(input, n, 'hour');
|
|
298
|
+
export const addMinutes = (input, n) => add(input, n, 'minute');
|
|
299
|
+
export const addSeconds = (input, n) => add(input, n, 'second');
|
|
300
|
+
export const subYears = (input, n) => subtract(input, n, 'year');
|
|
301
|
+
export const subMonths = (input, n) => subtract(input, n, 'month');
|
|
302
|
+
export const subWeeks = (input, n) => subtract(input, n, 'week');
|
|
303
|
+
export const subDays = (input, n) => subtract(input, n, 'day');
|
|
304
|
+
export const subHours = (input, n) => subtract(input, n, 'hour');
|
|
305
|
+
export const subMinutes = (input, n) => subtract(input, n, 'minute');
|
|
306
|
+
export const subSeconds = (input, n) => subtract(input, n, 'second');
|
|
307
|
+
// ============================================
|
|
308
|
+
// Comparisons
|
|
309
|
+
// ============================================
|
|
310
|
+
/**
|
|
311
|
+
* Check if two dates are the same day
|
|
312
|
+
*/
|
|
313
|
+
export function isSameDay(a, b) {
|
|
314
|
+
const d1 = toDate(a);
|
|
315
|
+
const d2 = toDate(b);
|
|
316
|
+
return d1.getFullYear() === d2.getFullYear() &&
|
|
317
|
+
d1.getMonth() === d2.getMonth() &&
|
|
318
|
+
d1.getDate() === d2.getDate();
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Check if two dates are the same month
|
|
322
|
+
*/
|
|
323
|
+
export function isSameMonth(a, b) {
|
|
324
|
+
const d1 = toDate(a);
|
|
325
|
+
const d2 = toDate(b);
|
|
326
|
+
return d1.getFullYear() === d2.getFullYear() &&
|
|
327
|
+
d1.getMonth() === d2.getMonth();
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Check if two dates are the same year
|
|
331
|
+
*/
|
|
332
|
+
export function isSameYear(a, b) {
|
|
333
|
+
return toDate(a).getFullYear() === toDate(b).getFullYear();
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Check if date is before another
|
|
337
|
+
*/
|
|
338
|
+
export function isBefore(a, b) {
|
|
339
|
+
return toDate(a).getTime() < toDate(b).getTime();
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Check if date is after another
|
|
343
|
+
*/
|
|
344
|
+
export function isAfter(a, b) {
|
|
345
|
+
return toDate(a).getTime() > toDate(b).getTime();
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* Check if date is between two dates
|
|
349
|
+
*/
|
|
350
|
+
export function isBetween(input, start, end) {
|
|
351
|
+
const t = toDate(input).getTime();
|
|
352
|
+
return t >= toDate(start).getTime() && t <= toDate(end).getTime();
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Check if date is today
|
|
356
|
+
*/
|
|
357
|
+
export function isToday(input) {
|
|
358
|
+
return isSameDay(input, new Date());
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Check if date is yesterday
|
|
362
|
+
*/
|
|
363
|
+
export function isYesterday(input) {
|
|
364
|
+
return isSameDay(input, subDays(new Date(), 1));
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* Check if date is tomorrow
|
|
368
|
+
*/
|
|
369
|
+
export function isTomorrow(input) {
|
|
370
|
+
return isSameDay(input, addDays(new Date(), 1));
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* Check if date is in the past
|
|
374
|
+
*/
|
|
375
|
+
export function isPast(input) {
|
|
376
|
+
return toDate(input).getTime() < Date.now();
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* Check if date is in the future
|
|
380
|
+
*/
|
|
381
|
+
export function isFuture(input) {
|
|
382
|
+
return toDate(input).getTime() > Date.now();
|
|
383
|
+
}
|
|
384
|
+
// ============================================
|
|
385
|
+
// Difference
|
|
386
|
+
// ============================================
|
|
387
|
+
/**
|
|
388
|
+
* Get difference between two dates in specified unit
|
|
389
|
+
*/
|
|
390
|
+
export function diff(a, b, unit) {
|
|
391
|
+
const d1 = toDate(a);
|
|
392
|
+
const d2 = toDate(b);
|
|
393
|
+
const diffMs = d1.getTime() - d2.getTime();
|
|
394
|
+
switch (unit) {
|
|
395
|
+
case 'year':
|
|
396
|
+
return d1.getFullYear() - d2.getFullYear();
|
|
397
|
+
case 'month':
|
|
398
|
+
return (d1.getFullYear() - d2.getFullYear()) * 12 + (d1.getMonth() - d2.getMonth());
|
|
399
|
+
case 'week':
|
|
400
|
+
return Math.floor(diffMs / (7 * 24 * 60 * 60 * 1000));
|
|
401
|
+
case 'day':
|
|
402
|
+
return Math.floor(diffMs / (24 * 60 * 60 * 1000));
|
|
403
|
+
case 'hour':
|
|
404
|
+
return Math.floor(diffMs / (60 * 60 * 1000));
|
|
405
|
+
case 'minute':
|
|
406
|
+
return Math.floor(diffMs / (60 * 1000));
|
|
407
|
+
case 'second':
|
|
408
|
+
return Math.floor(diffMs / 1000);
|
|
409
|
+
case 'millisecond':
|
|
410
|
+
return diffMs;
|
|
411
|
+
default:
|
|
412
|
+
return diffMs;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
export const diffInYears = (a, b) => diff(a, b, 'year');
|
|
416
|
+
export const diffInMonths = (a, b) => diff(a, b, 'month');
|
|
417
|
+
export const diffInWeeks = (a, b) => diff(a, b, 'week');
|
|
418
|
+
export const diffInDays = (a, b) => diff(a, b, 'day');
|
|
419
|
+
export const diffInHours = (a, b) => diff(a, b, 'hour');
|
|
420
|
+
export const diffInMinutes = (a, b) => diff(a, b, 'minute');
|
|
421
|
+
export const diffInSeconds = (a, b) => diff(a, b, 'second');
|
|
422
|
+
// ============================================
|
|
423
|
+
// Getters
|
|
424
|
+
// ============================================
|
|
425
|
+
export const getYear = (input) => toDate(input).getFullYear();
|
|
426
|
+
export const getMonth = (input) => toDate(input).getMonth(); // 0-indexed
|
|
427
|
+
export const getDate = (input) => toDate(input).getDate();
|
|
428
|
+
export const getDay = (input) => toDate(input).getDay(); // 0 = Sunday
|
|
429
|
+
export const getHours = (input) => toDate(input).getHours();
|
|
430
|
+
export const getMinutes = (input) => toDate(input).getMinutes();
|
|
431
|
+
export const getSeconds = (input) => toDate(input).getSeconds();
|
|
432
|
+
export const getMilliseconds = (input) => toDate(input).getMilliseconds();
|
|
433
|
+
export const getTime = (input) => toDate(input).getTime();
|
|
434
|
+
// ============================================
|
|
435
|
+
// Start/End of Period
|
|
436
|
+
// ============================================
|
|
437
|
+
/**
|
|
438
|
+
* Get start of a time period
|
|
439
|
+
*/
|
|
440
|
+
export function startOf(input, unit) {
|
|
441
|
+
const d = toDate(input);
|
|
442
|
+
switch (unit) {
|
|
443
|
+
case 'year':
|
|
444
|
+
return new Date(d.getFullYear(), 0, 1, 0, 0, 0, 0);
|
|
445
|
+
case 'month':
|
|
446
|
+
return new Date(d.getFullYear(), d.getMonth(), 1, 0, 0, 0, 0);
|
|
447
|
+
case 'week': {
|
|
448
|
+
const day = d.getDay();
|
|
449
|
+
const diff = d.getDate() - day;
|
|
450
|
+
return new Date(d.getFullYear(), d.getMonth(), diff, 0, 0, 0, 0);
|
|
451
|
+
}
|
|
452
|
+
case 'day':
|
|
453
|
+
return new Date(d.getFullYear(), d.getMonth(), d.getDate(), 0, 0, 0, 0);
|
|
454
|
+
case 'hour':
|
|
455
|
+
return new Date(d.getFullYear(), d.getMonth(), d.getDate(), d.getHours(), 0, 0, 0);
|
|
456
|
+
case 'minute':
|
|
457
|
+
return new Date(d.getFullYear(), d.getMonth(), d.getDate(), d.getHours(), d.getMinutes(), 0, 0);
|
|
458
|
+
default:
|
|
459
|
+
return d;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
/**
|
|
463
|
+
* Get end of a time period
|
|
464
|
+
*/
|
|
465
|
+
export function endOf(input, unit) {
|
|
466
|
+
const d = toDate(input);
|
|
467
|
+
switch (unit) {
|
|
468
|
+
case 'year':
|
|
469
|
+
return new Date(d.getFullYear(), 11, 31, 23, 59, 59, 999);
|
|
470
|
+
case 'month':
|
|
471
|
+
return new Date(d.getFullYear(), d.getMonth() + 1, 0, 23, 59, 59, 999);
|
|
472
|
+
case 'week': {
|
|
473
|
+
const day = d.getDay();
|
|
474
|
+
const diff = d.getDate() + (6 - day);
|
|
475
|
+
return new Date(d.getFullYear(), d.getMonth(), diff, 23, 59, 59, 999);
|
|
476
|
+
}
|
|
477
|
+
case 'day':
|
|
478
|
+
return new Date(d.getFullYear(), d.getMonth(), d.getDate(), 23, 59, 59, 999);
|
|
479
|
+
case 'hour':
|
|
480
|
+
return new Date(d.getFullYear(), d.getMonth(), d.getDate(), d.getHours(), 59, 59, 999);
|
|
481
|
+
case 'minute':
|
|
482
|
+
return new Date(d.getFullYear(), d.getMonth(), d.getDate(), d.getHours(), d.getMinutes(), 59, 999);
|
|
483
|
+
default:
|
|
484
|
+
return d;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
// ============================================
|
|
488
|
+
// Utilities
|
|
489
|
+
// ============================================
|
|
490
|
+
/**
|
|
491
|
+
* Get days in month
|
|
492
|
+
*/
|
|
493
|
+
export function daysInMonth(input) {
|
|
494
|
+
const d = toDate(input);
|
|
495
|
+
return new Date(d.getFullYear(), d.getMonth() + 1, 0).getDate();
|
|
496
|
+
}
|
|
497
|
+
/**
|
|
498
|
+
* Check if year is a leap year
|
|
499
|
+
*/
|
|
500
|
+
export function isLeapYear(input) {
|
|
501
|
+
const year = toDate(input).getFullYear();
|
|
502
|
+
return (year % 4 === 0 && year % 100 !== 0) || (year % 400 === 0);
|
|
503
|
+
}
|
|
504
|
+
/**
|
|
505
|
+
* Get day of year (1-366)
|
|
506
|
+
*/
|
|
507
|
+
export function dayOfYear(input) {
|
|
508
|
+
const d = toDate(input);
|
|
509
|
+
const start = new Date(d.getFullYear(), 0, 0);
|
|
510
|
+
const diff = d.getTime() - start.getTime();
|
|
511
|
+
return Math.floor(diff / (24 * 60 * 60 * 1000));
|
|
512
|
+
}
|
|
513
|
+
/**
|
|
514
|
+
* Get week of year
|
|
515
|
+
*/
|
|
516
|
+
export function weekOfYear(input) {
|
|
517
|
+
const d = toDate(input);
|
|
518
|
+
const start = new Date(d.getFullYear(), 0, 1);
|
|
519
|
+
const diff = d.getTime() - start.getTime();
|
|
520
|
+
const oneWeek = 7 * 24 * 60 * 60 * 1000;
|
|
521
|
+
return Math.ceil((diff / oneWeek) + 1);
|
|
522
|
+
}
|
|
523
|
+
/**
|
|
524
|
+
* Get quarter (1-4)
|
|
525
|
+
*/
|
|
526
|
+
export function quarter(input) {
|
|
527
|
+
return Math.floor(toDate(input).getMonth() / 3) + 1;
|
|
528
|
+
}
|
|
529
|
+
/**
|
|
530
|
+
* Create a date from components
|
|
531
|
+
*/
|
|
532
|
+
export function create(year, month = 0, day = 1, hour = 0, minute = 0, second = 0, ms = 0) {
|
|
533
|
+
return new Date(year, month, day, hour, minute, second, ms);
|
|
534
|
+
}
|
|
535
|
+
/**
|
|
536
|
+
* Get current timestamp
|
|
537
|
+
*/
|
|
538
|
+
export function now() {
|
|
539
|
+
return Date.now();
|
|
540
|
+
}
|
|
541
|
+
/**
|
|
542
|
+
* Get current date (start of today)
|
|
543
|
+
*/
|
|
544
|
+
export function today() {
|
|
545
|
+
return startOf(new Date(), 'day');
|
|
546
|
+
}
|
|
547
|
+
/**
|
|
548
|
+
* Clone a date
|
|
549
|
+
*/
|
|
550
|
+
export function clone(input) {
|
|
551
|
+
return toDate(input);
|
|
552
|
+
}
|
|
553
|
+
/**
|
|
554
|
+
* Get min date from array
|
|
555
|
+
*/
|
|
556
|
+
export function min(...dates) {
|
|
557
|
+
const timestamps = dates.map(d => toDate(d).getTime());
|
|
558
|
+
return new Date(Math.min(...timestamps));
|
|
559
|
+
}
|
|
560
|
+
/**
|
|
561
|
+
* Get max date from array
|
|
562
|
+
*/
|
|
563
|
+
export function max(...dates) {
|
|
564
|
+
const timestamps = dates.map(d => toDate(d).getTime());
|
|
565
|
+
return new Date(Math.max(...timestamps));
|
|
566
|
+
}
|
|
567
|
+
export function duration(amountOrMs, unit) {
|
|
568
|
+
let totalMs;
|
|
569
|
+
if (unit) {
|
|
570
|
+
switch (unit) {
|
|
571
|
+
case 'year':
|
|
572
|
+
totalMs = amountOrMs * 365 * 24 * 60 * 60 * 1000;
|
|
573
|
+
break;
|
|
574
|
+
case 'month':
|
|
575
|
+
totalMs = amountOrMs * 30 * 24 * 60 * 60 * 1000;
|
|
576
|
+
break;
|
|
577
|
+
case 'week':
|
|
578
|
+
totalMs = amountOrMs * 7 * 24 * 60 * 60 * 1000;
|
|
579
|
+
break;
|
|
580
|
+
case 'day':
|
|
581
|
+
totalMs = amountOrMs * 24 * 60 * 60 * 1000;
|
|
582
|
+
break;
|
|
583
|
+
case 'hour':
|
|
584
|
+
totalMs = amountOrMs * 60 * 60 * 1000;
|
|
585
|
+
break;
|
|
586
|
+
case 'minute':
|
|
587
|
+
totalMs = amountOrMs * 60 * 1000;
|
|
588
|
+
break;
|
|
589
|
+
case 'second':
|
|
590
|
+
totalMs = amountOrMs * 1000;
|
|
591
|
+
break;
|
|
592
|
+
case 'millisecond':
|
|
593
|
+
totalMs = amountOrMs;
|
|
594
|
+
break;
|
|
595
|
+
default: totalMs = amountOrMs;
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
else {
|
|
599
|
+
totalMs = amountOrMs;
|
|
600
|
+
}
|
|
601
|
+
const absMs = Math.abs(totalMs);
|
|
602
|
+
const years = Math.floor(absMs / (365 * 24 * 60 * 60 * 1000));
|
|
603
|
+
const months = Math.floor((absMs % (365 * 24 * 60 * 60 * 1000)) / (30 * 24 * 60 * 60 * 1000));
|
|
604
|
+
const weeks = Math.floor((absMs % (30 * 24 * 60 * 60 * 1000)) / (7 * 24 * 60 * 60 * 1000));
|
|
605
|
+
const days = Math.floor((absMs % (7 * 24 * 60 * 60 * 1000)) / (24 * 60 * 60 * 1000));
|
|
606
|
+
const hours = Math.floor((absMs % (24 * 60 * 60 * 1000)) / (60 * 60 * 1000));
|
|
607
|
+
const minutes = Math.floor((absMs % (60 * 60 * 1000)) / (60 * 1000));
|
|
608
|
+
const seconds = Math.floor((absMs % (60 * 1000)) / 1000);
|
|
609
|
+
const milliseconds = absMs % 1000;
|
|
610
|
+
return {
|
|
611
|
+
years,
|
|
612
|
+
months,
|
|
613
|
+
weeks,
|
|
614
|
+
days,
|
|
615
|
+
hours,
|
|
616
|
+
minutes,
|
|
617
|
+
seconds,
|
|
618
|
+
milliseconds,
|
|
619
|
+
asMilliseconds: () => totalMs,
|
|
620
|
+
asSeconds: () => totalMs / 1000,
|
|
621
|
+
asMinutes: () => totalMs / (60 * 1000),
|
|
622
|
+
asHours: () => totalMs / (60 * 60 * 1000),
|
|
623
|
+
asDays: () => totalMs / (24 * 60 * 60 * 1000),
|
|
624
|
+
asWeeks: () => totalMs / (7 * 24 * 60 * 60 * 1000),
|
|
625
|
+
humanize: (locale = 'en') => {
|
|
626
|
+
const rtf = new Intl.RelativeTimeFormat(locale, { numeric: 'auto' });
|
|
627
|
+
if (years > 0)
|
|
628
|
+
return rtf.format(years, 'year').replace(/^in /, '').replace(/ ago$/, '');
|
|
629
|
+
if (months > 0)
|
|
630
|
+
return rtf.format(months, 'month').replace(/^in /, '').replace(/ ago$/, '');
|
|
631
|
+
if (weeks > 0)
|
|
632
|
+
return rtf.format(weeks, 'week').replace(/^in /, '').replace(/ ago$/, '');
|
|
633
|
+
if (days > 0)
|
|
634
|
+
return rtf.format(days, 'day').replace(/^in /, '').replace(/ ago$/, '');
|
|
635
|
+
if (hours > 0)
|
|
636
|
+
return rtf.format(hours, 'hour').replace(/^in /, '').replace(/ ago$/, '');
|
|
637
|
+
if (minutes > 0)
|
|
638
|
+
return rtf.format(minutes, 'minute').replace(/^in /, '').replace(/ ago$/, '');
|
|
639
|
+
return rtf.format(seconds, 'second').replace(/^in /, '').replace(/ ago$/, '');
|
|
640
|
+
},
|
|
641
|
+
};
|
|
642
|
+
}
|
|
643
|
+
/**
|
|
644
|
+
* Get duration between two dates
|
|
645
|
+
*/
|
|
646
|
+
export function durationBetween(a, b) {
|
|
647
|
+
const d1 = toDate(a);
|
|
648
|
+
const d2 = toDate(b);
|
|
649
|
+
return duration(Math.abs(d1.getTime() - d2.getTime()));
|
|
650
|
+
}
|
|
651
|
+
// ============================================
|
|
652
|
+
// UTC support
|
|
653
|
+
// ============================================
|
|
654
|
+
/**
|
|
655
|
+
* Create a UTC date
|
|
656
|
+
*/
|
|
657
|
+
export function utc(input) {
|
|
658
|
+
if (!input) {
|
|
659
|
+
return new Date(Date.now());
|
|
660
|
+
}
|
|
661
|
+
const d = toDate(input);
|
|
662
|
+
return new Date(Date.UTC(d.getFullYear(), d.getMonth(), d.getDate(), d.getHours(), d.getMinutes(), d.getSeconds(), d.getMilliseconds()));
|
|
663
|
+
}
|
|
664
|
+
/**
|
|
665
|
+
* Get UTC offset in minutes
|
|
666
|
+
*/
|
|
667
|
+
export function utcOffset(input) {
|
|
668
|
+
return -toDate(input).getTimezoneOffset();
|
|
669
|
+
}
|
|
670
|
+
/**
|
|
671
|
+
* Check if date is a weekend (Saturday or Sunday)
|
|
672
|
+
*/
|
|
673
|
+
export function isWeekend(input) {
|
|
674
|
+
const day = toDate(input).getDay();
|
|
675
|
+
return day === 0 || day === 6;
|
|
676
|
+
}
|
|
677
|
+
/**
|
|
678
|
+
* Check if date is a weekday (Monday-Friday)
|
|
679
|
+
*/
|
|
680
|
+
export function isWeekday(input) {
|
|
681
|
+
return !isWeekend(input);
|
|
682
|
+
}
|
|
683
|
+
/**
|
|
684
|
+
* Get the name of the day
|
|
685
|
+
*/
|
|
686
|
+
export function dayName(input, locale = 'en-US', style = 'long') {
|
|
687
|
+
return new Intl.DateTimeFormat(locale, { weekday: style }).format(toDate(input));
|
|
688
|
+
}
|
|
689
|
+
/**
|
|
690
|
+
* Get the name of the month
|
|
691
|
+
*/
|
|
692
|
+
export function monthName(input, locale = 'en-US', style = 'long') {
|
|
693
|
+
return new Intl.DateTimeFormat(locale, { month: style }).format(toDate(input));
|
|
694
|
+
}
|
|
695
|
+
//# sourceMappingURL=index.js.map
|