@stacksjs/datetime 0.58.73 → 0.59.2

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.
@@ -0,0 +1,5 @@
1
+ import { useDateFormat, useNow } from '@stacksjs/utils';
2
+ declare const now: typeof useNow;
3
+ declare const dateFormat: typeof useDateFormat;
4
+ export { now, dateFormat };
5
+ export { format, parse } from '@formkit/tempo';
package/dist/index.js CHANGED
@@ -1,9 +1,704 @@
1
1
  // @bun
2
2
  // src/index.ts
3
3
  import {useDateFormat, useNow} from "@stacksjs/utils";
4
+
5
+ // ../../../../node_modules/@formkit/tempo/dist/index.mjs
6
+ var iso8601 = function(date2) {
7
+ const matches = date2.match(iso8601Match);
8
+ if (matches) {
9
+ const month = Number(matches[2]);
10
+ if (month < 1 || month > 12)
11
+ return false;
12
+ if (typeof matches[3] !== undefined) {
13
+ const date3 = Number(matches[3]);
14
+ if (date3 < 1 || date3 > 31)
15
+ return false;
16
+ }
17
+ if (typeof matches[4] !== undefined) {
18
+ const hours = Number(matches[4]);
19
+ if (hours < 0 || hours > 23)
20
+ return false;
21
+ }
22
+ return true;
23
+ }
24
+ return false;
25
+ };
26
+ var normalize = function(date2) {
27
+ const matches = date2.match(iso8601Match);
28
+ if (matches && typeof matches[4] === "undefined") {
29
+ return date2 += "T00:00:00";
30
+ }
31
+ return date2;
32
+ };
33
+ var date = function(date2) {
34
+ if (!date2) {
35
+ date2 = new Date;
36
+ }
37
+ if (date2 instanceof Date) {
38
+ const d = new Date(date2);
39
+ d.setMilliseconds(0);
40
+ return d;
41
+ }
42
+ date2 = date2.trim();
43
+ if (iso8601(date2)) {
44
+ return new Date(normalize(date2));
45
+ }
46
+ throw new Error(`Non ISO 8601 compliant date (${date2}).`);
47
+ };
48
+ var monthEnd = function(inputDate) {
49
+ const d = date(inputDate);
50
+ d.setDate(1);
51
+ d.setMonth(d.getMonth() + 1);
52
+ d.setDate(0);
53
+ return d;
54
+ };
55
+ var monthDays = function(inputDate) {
56
+ const d = monthEnd(inputDate);
57
+ return d.getDate();
58
+ };
59
+ var normStr = function(part) {
60
+ if (part.type === "literal") {
61
+ part.value = part.value.normalize("NFKC");
62
+ }
63
+ return part;
64
+ };
65
+ var fill = function(inputDate, parts2, locale, genitive = false, offset2 = null) {
66
+ const partMap = createPartMap(inputDate, parts2, locale, genitive);
67
+ const d = date(inputDate);
68
+ function value({ partName, partValue, token }) {
69
+ if (partName === "literal")
70
+ return partValue;
71
+ const value2 = partMap[partName];
72
+ if (partName === "hour" && token === "H") {
73
+ return value2.replace(/^0/, "");
74
+ }
75
+ if ((partName === "minute" || partName === "second") && (token === "mm" || token === "ss") && value2.length === 1) {
76
+ return `0${value2}`;
77
+ }
78
+ if (partName === "dayPeriod") {
79
+ const p = ap(d.getUTCHours() < 12 ? "am" : "pm", locale);
80
+ return token === "A" ? p.toUpperCase() : p.toLowerCase();
81
+ }
82
+ if (partName === "timeZoneName") {
83
+ return offset2 != null ? offset2 : minsToOffset(-1 * d.getTimezoneOffset());
84
+ }
85
+ return value2;
86
+ }
87
+ return parts2.map((part) => {
88
+ return {
89
+ ...part,
90
+ value: value(part)
91
+ };
92
+ });
93
+ };
94
+ var createPartMap = function(inputDate, parts2, locale, genitive = false) {
95
+ const d = date(inputDate);
96
+ const hour12 = parts2.filter((part) => part.hour12);
97
+ const hour24 = parts2.filter((part) => !part.hour12);
98
+ const valueParts = [];
99
+ const genitiveParts = [];
100
+ function addValues(requestedParts, hour122 = false) {
101
+ const preciseLocale = `${locale}-u-hc-${hour122 ? "h12" : "h23"}`;
102
+ valueParts.push(...new Intl.DateTimeFormat(preciseLocale, requestedParts.reduce((options, part) => {
103
+ if (part.partName === "literal")
104
+ return options;
105
+ if (genitive && genitiveTokens.includes(part.token)) {
106
+ genitiveParts.push(part);
107
+ }
108
+ return Object.assign(options, part.option);
109
+ }, { timeZone: "UTC" })).formatToParts(d).map(normStr));
110
+ if (genitive && genitiveParts.length) {
111
+ for (const part of genitiveParts) {
112
+ let formattedParts = [];
113
+ switch (part.token) {
114
+ case "MMMM":
115
+ formattedParts = new Intl.DateTimeFormat(preciseLocale, {
116
+ dateStyle: "long",
117
+ timeZone: "UTC"
118
+ }).formatToParts(d).map(normStr);
119
+ break;
120
+ case "MMM":
121
+ formattedParts = new Intl.DateTimeFormat(preciseLocale, {
122
+ dateStyle: "medium",
123
+ timeZone: "UTC"
124
+ }).formatToParts(d).map(normStr);
125
+ break;
126
+ }
127
+ const genitiveFormattedPart = formattedParts.find((p) => p.type === part.partName);
128
+ const index = valueParts.findIndex((p) => p.type === part.partName);
129
+ if (genitiveFormattedPart && index > -1) {
130
+ valueParts[index] = genitiveFormattedPart;
131
+ }
132
+ }
133
+ }
134
+ }
135
+ if (hour12.length)
136
+ addValues(hour12, true);
137
+ if (hour24.length)
138
+ addValues(hour24);
139
+ return valueParts.reduce((map, part) => {
140
+ map[part.type] = part.value;
141
+ return map;
142
+ }, {});
143
+ };
144
+ var minsToOffset = function(timeDiffInMins) {
145
+ const hours = String(Math.floor(Math.abs(timeDiffInMins / 60))).padStart(2, "0");
146
+ const mins = String(Math.abs(timeDiffInMins % 60)).padStart(2, "0");
147
+ const sign = timeDiffInMins < 0 ? "-" : "+";
148
+ return `${sign}${hours}${mins}`;
149
+ };
150
+ var offsetToMins = function(offset2) {
151
+ validOffset(offset2);
152
+ const [_, sign, hours, mins] = offset2.match(/([+-])([0-3][0-9])([0-6][0-9])/);
153
+ const offsetInMins = Number(hours) * 60 + Number(mins);
154
+ return sign === "+" ? offsetInMins : -offsetInMins;
155
+ };
156
+ var validOffset = function(offset2) {
157
+ const valid = /^([+-])[0-3][0-9][0-6][0-9]$/.test(offset2);
158
+ if (!valid)
159
+ throw new Error(`Invalid offset: ${offset2}`);
160
+ return offset2;
161
+ };
162
+ var escapeTokens = function(str) {
163
+ return clockAgnostic.concat(clock24).concat(clock12).sort((a, b) => a[0].length > b[0].length ? 1 : -1).reduce((target, part) => {
164
+ return target.replace(part[0], `\\${part[0]}`);
165
+ }, str);
166
+ };
167
+ var isNumeric = function(part) {
168
+ return ["numeric", "2-digit"].includes(part.partValue);
169
+ };
170
+ var validate = function(parts2) {
171
+ let lastPart = undefined;
172
+ for (const part of parts2) {
173
+ if (part.partName === "literal" && !isNaN(parseFloat(part.partValue))) {
174
+ throw new Error(`Numbers in format (${part.partValue}).`);
175
+ }
176
+ if (lastPart && lastPart.partName !== "literal" && part.partName !== "literal") {
177
+ if (!(lastPart.token in fixedLength) && !(part.token in fixedLength) && !(isNumeric(lastPart) && part.token.toLowerCase() === "a")) {
178
+ throw new Error(`Illegal adjacent tokens (${lastPart.token}, ${part.token})`);
179
+ }
180
+ }
181
+ lastPart = part;
182
+ }
183
+ return parts2;
184
+ };
185
+ var ap = function(ampm, locale) {
186
+ const l = dayPeriodMap.get(locale);
187
+ if (l && l[ampm])
188
+ return l[ampm];
189
+ const specimen = new Date(specDate);
190
+ specimen.setUTCHours(ampm === "am" ? 5 : 20);
191
+ const subparts = new Intl.DateTimeFormat(locale, {
192
+ timeStyle: "full",
193
+ timeZone: "UTC",
194
+ hour12: true
195
+ }).formatToParts(specimen).map(normStr);
196
+ const period = subparts.find((part) => part.type === "dayPeriod");
197
+ if (period) {
198
+ const localePeriods = l || {};
199
+ dayPeriodMap.set(locale, Object.assign(localePeriods, { [ampm]: period.value }));
200
+ return period.value;
201
+ }
202
+ return ampm;
203
+ };
204
+ var applyOffset = function(dateInput, offset2 = "+0000") {
205
+ const d = date(dateInput);
206
+ const timeDiffInMins = offsetToMins(offset2);
207
+ return new Date(d.getTime() + timeDiffInMins * 1000 * 60);
208
+ };
209
+ var deviceTZ = function() {
210
+ return Intl.DateTimeFormat().resolvedOptions().timeZone;
211
+ };
212
+ var relativeTime = function(d, timeZone) {
213
+ const utcParts = new Intl.DateTimeFormat("en-US", {
214
+ year: "numeric",
215
+ month: "2-digit",
216
+ day: "2-digit",
217
+ hour: "2-digit",
218
+ minute: "2-digit",
219
+ second: "2-digit",
220
+ timeZone,
221
+ hourCycle: "h23"
222
+ }).formatToParts(d).map(normStr);
223
+ const parts2 = {};
224
+ utcParts.forEach((part) => {
225
+ parts2[part.type] = part.value;
226
+ });
227
+ return new Date(`${parts2.year}-${parts2.month}-${parts2.day}T${parts2.hour}:${parts2.minute}:${parts2.second}Z`);
228
+ };
229
+ var offset = function(utcTime, tzA = "UTC", tzB = "device") {
230
+ tzB = tzB === "device" ? deviceTZ() : tzB;
231
+ const d = date(utcTime);
232
+ const timeA = relativeTime(d, tzA);
233
+ const timeB = relativeTime(d, tzB);
234
+ const timeDiffInMins = (timeB.getTime() - timeA.getTime()) / 1000 / 60;
235
+ return minsToOffset(timeDiffInMins);
236
+ };
237
+ var parts = function(format2, locale) {
238
+ if (styles.includes(format2) || typeof format2 === "object") {
239
+ return styleParts(format2, locale);
240
+ }
241
+ let f = format2;
242
+ let match = 0;
243
+ const testPattern = (pattern) => {
244
+ if (!pattern[2])
245
+ pattern[2] = new RegExp(`(.)?(${pattern[0]})`, "g");
246
+ if (pattern[2].test(f)) {
247
+ let didAdd = 0;
248
+ f = f.replace(pattern[2], (_, prefix, actualMatch) => {
249
+ if (prefix === "\\")
250
+ return actualMatch;
251
+ return `${typeof prefix === "string" ? prefix : ""}{!${didAdd++ ? match : match++}!}`;
252
+ });
253
+ return !!didAdd;
254
+ }
255
+ return false;
256
+ };
257
+ function validate2(patterns) {
258
+ const parts3 = patterns.map((part) => part.partName);
259
+ const deduped = new Set(parts3);
260
+ if (parts3.length > deduped.size) {
261
+ throw new Error(`Cannot reuse format tokens.`);
262
+ }
263
+ return patterns;
264
+ }
265
+ function createPart(hour12, [token, option, exp]) {
266
+ const partName = Object.keys(option)[0];
267
+ const partValue = option[partName];
268
+ return {
269
+ option,
270
+ partName,
271
+ partValue,
272
+ token,
273
+ pattern: exp,
274
+ hour12
275
+ };
276
+ }
277
+ const found24Patterns = clockAgnostic.filter(testPattern).concat(clock24.filter(testPattern)).map(createPart.bind(null, false));
278
+ const parts2 = validate2(found24Patterns.concat(clock12.filter(testPattern).map(createPart.bind(null, true))));
279
+ const extractIndex = /^\{!(\d+)!\}$/;
280
+ return f.split(/(\{!\d+!\})/).map((match2) => {
281
+ const hasIndex = match2.match(extractIndex);
282
+ if (hasIndex) {
283
+ return parts2[Number(hasIndex[1])];
284
+ }
285
+ return {
286
+ option: { literal: match2 },
287
+ partName: "literal",
288
+ partValue: match2,
289
+ token: match2,
290
+ pattern: new RegExp(""),
291
+ hour12: false
292
+ };
293
+ }).filter((part) => !(part.partName === "literal" && part.partValue === ""));
294
+ };
295
+ var styleParts = function(format2, locale) {
296
+ const options = {
297
+ timeZone: "UTC"
298
+ };
299
+ if (typeof format2 === "string") {
300
+ options.dateStyle = format2;
301
+ } else {
302
+ if ("date" in format2)
303
+ options.dateStyle = format2.date;
304
+ if ("time" in format2)
305
+ options.timeStyle = format2.time;
306
+ }
307
+ const formatter = new Intl.DateTimeFormat(locale, options);
308
+ const segments = formatter.formatToParts(new Date(specDate)).map(normStr);
309
+ const hourTypeSegments = formatter.formatToParts(new Date("1999-04-05T23:05:01.000Z")).map(normStr);
310
+ const hourPart = hourTypeSegments.find((segment) => segment.type === "hour");
311
+ const hourType = hourPart && hourPart.value === "23" ? 24 : 12;
312
+ return segments.map((part) => {
313
+ const partName = part.type;
314
+ const formatPattern = guessPattern(part.type, part.value, locale, part.type === "hour" ? hourType : undefined);
315
+ if (formatPattern === undefined)
316
+ return;
317
+ const partValue = formatPattern[1][partName];
318
+ if (!partValue)
319
+ return;
320
+ if (!formatPattern[2])
321
+ formatPattern[2] = new RegExp(`${formatPattern[0]}`, "g");
322
+ return {
323
+ option: { [partName]: partValue },
324
+ partName,
325
+ partValue,
326
+ token: formatPattern[0],
327
+ pattern: formatPattern[2],
328
+ hour12: hourType === 12
329
+ };
330
+ }).filter((part) => !!part);
331
+ };
332
+ var guessPattern = function(partName, partValue, locale, hour) {
333
+ const l = partValue.length;
334
+ const n = !isNaN(Number(partValue));
335
+ let style;
336
+ switch (partName) {
337
+ case "year":
338
+ return l === 2 ? tokens.get("YY") : tokens.get("YYYY");
339
+ case "month":
340
+ if (n)
341
+ return l === 1 ? tokens.get("M") : tokens.get("MM");
342
+ style = partStyle(locale, partName, partValue);
343
+ switch (style) {
344
+ case "long":
345
+ return tokens.get("MMMM");
346
+ default:
347
+ return tokens.get("MMM");
348
+ }
349
+ case "day":
350
+ return l === 1 ? tokens.get("D") : tokens.get("DD");
351
+ case "weekday":
352
+ style = partStyle(locale, partName, partValue);
353
+ switch (style) {
354
+ case "narrow":
355
+ return tokens.get("d");
356
+ case "short":
357
+ return tokens.get("ddd");
358
+ default:
359
+ return tokens.get("dddd");
360
+ }
361
+ case "hour":
362
+ if (hour === 12)
363
+ return l === 1 ? tokens.get("h") : tokens.get("hh");
364
+ return l === 1 ? tokens.get("H") : tokens.get("HH");
365
+ case "minute":
366
+ return l === 1 ? tokens.get("m") : tokens.get("mm");
367
+ case "second":
368
+ return l === 1 ? tokens.get("s") : tokens.get("ss");
369
+ case "dayPeriod":
370
+ return /^[A-Z]+$/u.test(partValue) ? tokens.get("A") : tokens.get("a");
371
+ case "literal":
372
+ return [partValue, { literal: partValue }, new RegExp("")];
373
+ case "timeZoneName":
374
+ const offset2 = partValue.split("-");
375
+ return offset2.length === 2 && offset2[1].length === 4 ? tokens.get("ZZ") : tokens.get("Z");
376
+ default:
377
+ return;
378
+ }
379
+ };
380
+ var partStyle = function(locale, part, value) {
381
+ if (!memoParts.has(locale)) {
382
+ const date2 = new Date(specDate);
383
+ const weekdays = [3, 8, 9, 7, 6, 4, 3];
384
+ const parts2 = ["weekday", "month", "dayPeriod"];
385
+ const partStyles = ["long", "short", "narrow"];
386
+ const formats2 = {};
387
+ for (let i = 0;i < 12; i++) {
388
+ date2.setMonth(0 + i);
389
+ if (i in weekdays)
390
+ date2.setDate(weekdays[i]);
391
+ date2.setUTCHours(8 + i);
392
+ for (const style of partStyles) {
393
+ const segments = new Intl.DateTimeFormat(locale, parts2.reduce((options, part2) => Object.assign(options, { [part2]: style }), { hour12: true, timeZone: "UTC" })).formatToParts(date2).map(normStr);
394
+ if (style === "long" || style === "short") {
395
+ const genitiveFormattedParts = new Intl.DateTimeFormat(locale, {
396
+ dateStyle: style === "short" ? "medium" : "long",
397
+ timeZone: "UTC"
398
+ }).formatToParts(date2).map(normStr);
399
+ const genitiveMonth = genitiveFormattedParts.find((part2) => part2.type === "month");
400
+ const index = segments.findIndex((part2) => part2.type === "month");
401
+ if (index > -1 && genitiveMonth)
402
+ segments[index] = genitiveMonth;
403
+ }
404
+ segments.forEach((part2) => {
405
+ if (part2.type === "literal")
406
+ return;
407
+ const type = part2.type;
408
+ formats2[type] = Object.assign(formats2[type] || {}, {
409
+ [part2.value]: style
410
+ });
411
+ });
412
+ }
413
+ }
414
+ memoParts.set(locale, formats2);
415
+ }
416
+ const formats = memoParts.get(locale);
417
+ return formats ? formats[part][value] : undefined;
418
+ };
419
+ var removeOffset = function(dateInput, offset2 = "+0000") {
420
+ const positive = offset2.slice(0, 1) === "+";
421
+ return applyOffset(dateInput, offset2.replace(positive ? "+" : "-", positive ? "-" : "+"));
422
+ };
423
+ var deviceLocale = function() {
424
+ return Intl.DateTimeFormat().resolvedOptions().locale;
425
+ };
426
+ var format = function(inputDateOrOptions, format2 = "long", locale = "device", genitive = false, partFilter) {
427
+ let tz, forceOffset;
428
+ if (typeof inputDateOrOptions === "object" && !(inputDateOrOptions instanceof Date)) {
429
+ ({
430
+ date: inputDateOrOptions,
431
+ format: format2,
432
+ locale,
433
+ genitive,
434
+ partFilter,
435
+ tz
436
+ } = inputDateOrOptions);
437
+ }
438
+ if (format2 === "ISO8601")
439
+ return date(inputDateOrOptions).toISOString();
440
+ if (tz) {
441
+ forceOffset = offset(inputDateOrOptions, "utc", tz);
442
+ }
443
+ tz != null || (tz = deviceTZ());
444
+ if (tz.toLowerCase() !== "utc") {
445
+ inputDateOrOptions = removeOffset(inputDateOrOptions, offset(inputDateOrOptions, tz, "utc"));
446
+ }
447
+ if (!locale || locale === "device") {
448
+ locale = deviceLocale();
449
+ }
450
+ return fill(inputDateOrOptions, parts(format2, locale).filter(partFilter != null ? partFilter : () => true), locale, genitive, forceOffset).map((p) => p.value).join("");
451
+ };
452
+ var formatStr = function(format2, locale = "en", escapeLiterals = false, filterParts = () => true) {
453
+ return parts(format2, locale).filter(filterParts).reduce((f, p) => f += escapeLiterals && p.partName === "literal" ? escapeTokens(p.token) : p.token, "").normalize("NFKC");
454
+ };
455
+ var fourDigitYear = function(value) {
456
+ const y = (new Date()).getFullYear();
457
+ const currentYear = y % 100;
458
+ const century = Math.floor(y / 100);
459
+ const parsedYear = Number(value);
460
+ return (century + (parsedYear > currentYear + 20 ? -1 : 0)) * 100 + parsedYear;
461
+ };
462
+ var range = function(token, locale = "en", genitive = false) {
463
+ const r = (n, c) => Array(n).fill("").map((_, i) => `${c(i)}`);
464
+ if (token === "M")
465
+ return r(12, (i) => i + 1);
466
+ if (token === "MM")
467
+ return r(12, (i) => {
468
+ const m = i + 1;
469
+ return m < 10 ? `0${m}` : m;
470
+ });
471
+ if (token.startsWith("M"))
472
+ return range("MM").map((m) => format(`2000-${m}-05`, token, locale, genitive));
473
+ if (token.startsWith("d"))
474
+ return r(7, (i) => `0${i + 2}`).map((d) => format(`2022-10-${d}`, token, locale));
475
+ if (token === "a")
476
+ return [ap("am", locale).toLowerCase(), ap("pm", locale).toLowerCase()];
477
+ if (token === "A")
478
+ return [ap("am", locale).toUpperCase(), ap("pm", locale).toUpperCase()];
479
+ if (token.startsWith("Y")) {
480
+ const year = (new Date()).getFullYear();
481
+ return r(120, (i) => i + 1).reduce((ranges, i) => {
482
+ if (i !== "120")
483
+ ranges.push(format(`${year + Number(i)}-06-06`, token, locale));
484
+ ranges.unshift(format(`${year - Number(i)}-06-06`, token, locale));
485
+ return ranges;
486
+ }, [format(`${year}-06-06`, token, locale)]);
487
+ }
488
+ if (token.startsWith("D"))
489
+ return r(31, (i) => `${token === "DD" && i < 9 ? "0" : ""}${i + 1}`);
490
+ if (token.startsWith("H"))
491
+ return r(24, (i) => `${token === "HH" && i < 10 ? "0" : ""}${i}`);
492
+ if (token.startsWith("h"))
493
+ return r(12, (i) => `${token === "hh" && i < 9 ? "0" : ""}${i + 1}`);
494
+ if (token.startsWith("m") || token.startsWith("s"))
495
+ return r(60, (i) => `${token.length > 1 && i < 10 ? "0" : ""}${i}`);
496
+ return [];
497
+ };
498
+ var parse = function(dateStrOrOptions, format2 = "ISO8601", locale = "device") {
499
+ let partFilter = () => true;
500
+ let dateStr;
501
+ let dateOverflow = "backward";
502
+ if (typeof dateStrOrOptions === "object") {
503
+ ({
504
+ date: dateStr,
505
+ format: format2 = "ISO8601",
506
+ locale = "device",
507
+ dateOverflow = "backward",
508
+ partFilter = () => true
509
+ } = dateStrOrOptions);
510
+ } else {
511
+ dateStr = dateStrOrOptions;
512
+ }
513
+ if (!dateStr)
514
+ throw new Error("parse() requires a date string.");
515
+ const invalid = () => {
516
+ throw new Error(`Date (${dateStr}) does not match format (${formatStr(format2, locale)})`);
517
+ };
518
+ if (format2 === "ISO8601")
519
+ return date(dateStr);
520
+ const genitive = styles.includes(format2) || typeof format2 === "object";
521
+ const formatParts = validate(parts(format2, locale).filter(partFilter));
522
+ if (!formatParts.length)
523
+ throw new Error("parse() requires a pattern.");
524
+ let parsedParts;
525
+ try {
526
+ parsedParts = parseParts(dateStr, formatParts);
527
+ } catch {
528
+ return invalid();
529
+ }
530
+ const now = new Date;
531
+ const parsed = new Map([
532
+ ["YYYY", now.getFullYear()],
533
+ ["MM", now.getMonth() + 1],
534
+ ["DD", now.getDate()],
535
+ ["HH", 0],
536
+ ["mm", 0],
537
+ ["ss", 0]
538
+ ]);
539
+ let a = null;
540
+ let offset2 = "";
541
+ parsedParts.forEach((part) => {
542
+ if (part.partName === "literal")
543
+ return;
544
+ if (part.token === part.value)
545
+ return invalid();
546
+ const v = Number(part.value);
547
+ if (parsed.has(part.token)) {
548
+ parsed.set(part.token, v);
549
+ } else if (part.token === "YY") {
550
+ parsed.set("YYYY", fourDigitYear(part.value));
551
+ } else {
552
+ const t = part.token;
553
+ if (t.startsWith("d")) {
554
+ return;
555
+ } else if (t === "D") {
556
+ parsed.set("DD", v);
557
+ } else if (t === "H" || t.startsWith("h")) {
558
+ parsed.set("HH", v);
559
+ } else if (t === "M") {
560
+ parsed.set("MM", v);
561
+ } else if (t === "a" || t === "A") {
562
+ a = part.value.toLowerCase() === ap("am", locale).toLowerCase();
563
+ } else if (t === "Z") {
564
+ offset2 = validOffset(part.value);
565
+ } else {
566
+ const values = range(t, locale, genitive);
567
+ const index = values.indexOf(part.value);
568
+ if (index !== -1) {
569
+ switch (t) {
570
+ case "MMM":
571
+ case "MMMM":
572
+ parsed.set("MM", index + 1);
573
+ break;
574
+ }
575
+ }
576
+ }
577
+ }
578
+ });
579
+ let hours = parsed.get("HH") || 0;
580
+ if (a === false) {
581
+ hours += hours === 12 ? 0 : 12;
582
+ parsed.set("HH", hours === 24 ? 0 : hours);
583
+ } else if (a === true && hours === 12) {
584
+ parsed.set("HH", 0);
585
+ }
586
+ parsed.set("MM", (parsed.get("MM") || 1) - 1);
587
+ let [Y, M, D, h, m, s] = Array.from(parsed.values());
588
+ const maxDaysInMonth = monthDays(new Date(`${four(Y)}-${two(M + 1)}-10`));
589
+ if (maxDaysInMonth < D && dateOverflow === "throw")
590
+ throw new Error(`Invalid date ${four(Y)}-${two(M + 1)}-${two(D)}`);
591
+ D = dateOverflow === "backward" ? Math.min(D, maxDaysInMonth) : D;
592
+ const isoString = `${four(Y)}-${two(M + 1)}-${two(D)}T${two(h)}:${two(m)}:${two(s)}${offset2}`;
593
+ const d = new Date(isoString);
594
+ if (isFinite(+d))
595
+ return d;
596
+ return invalid();
597
+ };
598
+ var parseParts = function(dateStr, formatParts) {
599
+ let i = 0;
600
+ const advance = (parts2) => [
601
+ parts2[i++],
602
+ parts2[i]
603
+ ];
604
+ let pos = 0;
605
+ const parsed = [];
606
+ let n = undefined;
607
+ do {
608
+ const [current, next] = advance(formatParts);
609
+ n = next;
610
+ let len = 1;
611
+ if (current.partName === "literal") {
612
+ len = current.partValue.length;
613
+ } else if (current.token in fixedLength) {
614
+ len = fixedLength[current.token];
615
+ } else if (next) {
616
+ if (next.partName === "literal") {
617
+ len = dateStr.indexOf(next.partValue, pos) - pos;
618
+ if (len < 0)
619
+ throw new Error;
620
+ } else if (next.partName === "dayPeriod") {
621
+ for (let i2 = 1;i2 <= 4; i2++) {
622
+ if (isNaN(Number(dateStr.charAt(pos + i2)))) {
623
+ len = i2;
624
+ break;
625
+ }
626
+ }
627
+ } else {
628
+ const nextChar = dateStr.substring(pos).search(/\d/);
629
+ if (nextChar !== -1)
630
+ len = pos + nextChar;
631
+ }
632
+ } else {
633
+ len = dateStr.length;
634
+ }
635
+ parsed.push({ ...current, value: dateStr.substring(pos, pos + len) });
636
+ pos += len;
637
+ } while (n);
638
+ return parsed;
639
+ };
640
+ var iso8601Match = /^([0-9]{4})-([0-1][0-9])(?:-([0-3][0-9]))?(?:[T ]?([0-2][0-9])(?::([0-5][0-9]))?(?::([0-5][0-9]))?)?(?:\.[0-9]+)?(Z|(?:\+|\-)[0-9]{4})?$/;
641
+ var specDate = "1999-03-04T02:05:01.000Z";
642
+ var memoParts = new Map;
643
+ var clockAgnostic = [
644
+ ["YYYY", { year: "numeric" }],
645
+ ["YY", { year: "2-digit" }],
646
+ ["MMMM", { month: "long" }],
647
+ ["MMM", { month: "short" }],
648
+ ["MM", { month: "2-digit" }],
649
+ ["M", { month: "numeric" }],
650
+ ["DD", { day: "2-digit" }],
651
+ ["D", { day: "numeric" }],
652
+ ["dddd", { weekday: "long" }],
653
+ ["ddd", { weekday: "short" }],
654
+ ["d", { weekday: "narrow" }],
655
+ ["mm", { minute: "2-digit" }],
656
+ ["m", { minute: "numeric" }],
657
+ ["ss", { second: "2-digit" }],
658
+ ["s", { second: "numeric" }],
659
+ ["Z", { timeZoneName: "short" }]
660
+ ];
661
+ var clock24 = [
662
+ ["HH", { hour: "2-digit" }],
663
+ ["H", { hour: "numeric" }]
664
+ ];
665
+ var clock12 = [
666
+ ["hh", { hour: "2-digit" }],
667
+ ["h", { hour: "numeric" }],
668
+ ["a", { dayPeriod: "narrow" }],
669
+ ["A", { dayPeriod: "narrow" }]
670
+ ];
671
+ var fixedLength = {
672
+ DD: 2,
673
+ HH: 2,
674
+ MM: 2,
675
+ YY: 2,
676
+ YYYY: 4,
677
+ hh: 2,
678
+ mm: 2,
679
+ ss: 2,
680
+ Z: 5
681
+ };
682
+ var genitiveTokens = ["MMMM", "MMM", "dddd", "ddd"];
683
+ var tokens = new Map([...clockAgnostic, ...clock24, ...clock12].map((format2) => {
684
+ return [format2[0], format2];
685
+ }));
686
+ var dayPeriodMap = new Map;
687
+ var styles = [
688
+ "full",
689
+ "long",
690
+ "medium",
691
+ "short"
692
+ ];
693
+ var two = (n) => String(n).padStart(2, "0");
694
+ var four = (n) => String(n).padStart(2, "0");
695
+
696
+ // src/index.ts
4
697
  var now = useNow;
5
698
  var dateFormat = useDateFormat;
6
699
  export {
700
+ parse,
7
701
  now,
702
+ format,
8
703
  dateFormat
9
704
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@stacksjs/datetime",
3
3
  "type": "module",
4
- "version": "0.58.73",
4
+ "version": "0.59.2",
5
5
  "description": "The Stacks datetime helpers.",
6
6
  "author": "Chris Breuer",
7
7
  "license": "MIT",
@@ -49,6 +49,7 @@
49
49
  "prepublishOnly": "bun --bun run build"
50
50
  },
51
51
  "dependencies": {
52
+ "@formkit/tempo": "^0.0.14",
52
53
  "@stacksjs/utils": "latest"
53
54
  },
54
55
  "devDependencies": {
package/src/index.ts CHANGED
@@ -5,3 +5,5 @@ const dateFormat = useDateFormat
5
5
 
6
6
  // useNow and useDateFormat are exported from @stacksjs/utils
7
7
  export { now, dateFormat }
8
+
9
+ export { format, parse } from '@formkit/tempo'