@stacksjs/datetime 0.70.88 → 0.70.91

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,37 @@
1
+ /**
2
+ * Format a date using token-based format strings.
3
+ *
4
+ * Supported tokens:
5
+ * - YYYY: 4-digit year
6
+ * - YY: 2-digit year
7
+ * - MMMM: Full month name (January)
8
+ * - MMM: Short month name (Jan)
9
+ * - MM: 2-digit month (01-12)
10
+ * - M: Month (1-12)
11
+ * - DD: 2-digit day (01-31)
12
+ * - D: Day (1-31)
13
+ * - dddd: Full weekday name (Wednesday)
14
+ * - ddd: Short weekday name (Wed)
15
+ * - d: Narrow weekday (W)
16
+ * - HH: 24-hour padded (00-23)
17
+ * - H: 24-hour (0-23)
18
+ * - hh: 12-hour padded (01-12)
19
+ * - h: 12-hour (1-12)
20
+ * - mm: Minutes padded (00-59)
21
+ * - m: Minutes (0-59)
22
+ * - ss: Seconds padded (00-59)
23
+ * - s: Seconds (0-59)
24
+ * - A: AM/PM
25
+ * - a: am/pm
26
+ * - Z: Timezone offset (+0800)
27
+ *
28
+ * @param inputDate - A Date object or ISO 8601 string
29
+ * @param formatStr - Token-based format string (default: 'YYYY-MM-DD')
30
+ * @param localeOrOptions - A locale string or options object with locale and tz (IANA timezone)
31
+ */
32
+ export declare function format(inputDate: DateInput, formatStr?: string, localeOrOptions?: string | FormatOptions): string;
33
+ declare interface FormatOptions {
34
+ locale?: string
35
+ tz?: string
36
+ }
37
+ declare type DateInput = Date | string;
package/dist/format.js ADDED
@@ -0,0 +1,100 @@
1
+ function toDate(input) {
2
+ if (input instanceof Date)
3
+ return input;
4
+ const d = new Date(input);
5
+ if (Number.isNaN(d.getTime()))
6
+ throw Error(`Invalid date: ${input}`);
7
+ return d;
8
+ }
9
+ function pad(n, len = 2) {
10
+ return String(n).padStart(len, "0");
11
+ }
12
+ function getPartsInTz(date, tz, locale) {
13
+ const parts = new Intl.DateTimeFormat("en-US", {
14
+ timeZone: tz,
15
+ year: "numeric",
16
+ month: "2-digit",
17
+ day: "2-digit",
18
+ hour: "2-digit",
19
+ minute: "2-digit",
20
+ second: "2-digit",
21
+ hour12: !1
22
+ }).formatToParts(date), get = (type) => parts.find((p) => p.type === type)?.value ?? "", year = Number.parseInt(get("year"), 10), month = Number.parseInt(get("month"), 10), day = Number.parseInt(get("day"), 10);
23
+ let hour = Number.parseInt(get("hour"), 10);
24
+ if (hour === 24)
25
+ hour = 0;
26
+ const minute = Number.parseInt(get("minute"), 10), second = Number.parseInt(get("second"), 10), weekday = new Intl.DateTimeFormat(locale, { timeZone: tz, weekday: "long" }).format(date), weekdayShort = new Intl.DateTimeFormat(locale, { timeZone: tz, weekday: "short" }).format(date), weekdayNarrow = new Intl.DateTimeFormat(locale, { timeZone: tz, weekday: "narrow" }).format(date), monthLong = new Intl.DateTimeFormat(locale, { timeZone: tz, month: "long" }).format(date), monthShort = new Intl.DateTimeFormat(locale, { timeZone: tz, month: "short" }).format(date), utcParts = new Intl.DateTimeFormat("en-US", {
27
+ timeZone: "UTC",
28
+ year: "numeric",
29
+ month: "2-digit",
30
+ day: "2-digit",
31
+ hour: "2-digit",
32
+ minute: "2-digit",
33
+ second: "2-digit",
34
+ hour12: !1
35
+ }).formatToParts(date), getUtc = (type) => utcParts.find((p) => p.type === type)?.value ?? "", utcDate = new Date(Date.UTC(Number.parseInt(getUtc("year"), 10), Number.parseInt(getUtc("month"), 10) - 1, Number.parseInt(getUtc("day"), 10), Number.parseInt(getUtc("hour"), 10) === 24 ? 0 : Number.parseInt(getUtc("hour"), 10), Number.parseInt(getUtc("minute"), 10), Number.parseInt(getUtc("second"), 10))), offsetMs = new Date(Date.UTC(year, month - 1, day, hour, minute, second)).getTime() - utcDate.getTime(), offsetMin = Math.round(offsetMs / 60000), sign = offsetMin >= 0 ? "+" : "-", absMin = Math.abs(offsetMin), tzOffset = `${sign}${pad(Math.floor(absMin / 60))}${pad(absMin % 60)}`;
36
+ return { year, month, day, hour, minute, second, weekday, weekdayShort, weekdayNarrow, monthLong, monthShort, tzOffset };
37
+ }
38
+ function buildTokens(p) {
39
+ const hours12 = p.hour % 12 || 12;
40
+ return {
41
+ YYYY: String(p.year),
42
+ YY: String(p.year).slice(-2),
43
+ MMMM: p.monthLong,
44
+ MMM: p.monthShort,
45
+ MM: pad(p.month),
46
+ M: String(p.month),
47
+ DD: pad(p.day),
48
+ D: String(p.day),
49
+ dddd: p.weekday,
50
+ ddd: p.weekdayShort,
51
+ d: p.weekdayNarrow,
52
+ HH: pad(p.hour),
53
+ H: String(p.hour),
54
+ hh: pad(hours12),
55
+ h: String(hours12),
56
+ mm: pad(p.minute),
57
+ m: String(p.minute),
58
+ ss: pad(p.second),
59
+ s: String(p.second),
60
+ A: p.hour < 12 ? "AM" : "PM",
61
+ a: p.hour < 12 ? "am" : "pm",
62
+ Z: p.tzOffset
63
+ };
64
+ }
65
+ const TOKEN_KEYS = ["YYYY", "MMMM", "dddd", "MMM", "ddd", "YY", "MM", "DD", "HH", "hh", "mm", "ss", "M", "D", "d", "H", "h", "m", "s", "A", "a", "Z"], TOKEN_PATTERN = new RegExp(TOKEN_KEYS.map((t) => t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|"), "g");
66
+ export function format(inputDate, formatStr = "YYYY-MM-DD", localeOrOptions = "en") {
67
+ const date = toDate(inputDate), opts = typeof localeOrOptions === "string" ? { locale: localeOrOptions } : localeOrOptions, locale = opts.locale ?? "en", tz = opts.tz;
68
+ if (tz) {
69
+ const parts = getPartsInTz(date, tz, locale), tokens = buildTokens(parts);
70
+ return formatStr.replace(TOKEN_PATTERN, (match) => tokens[match] ?? match);
71
+ }
72
+ const hours24 = date.getHours(), hours12 = hours24 % 12 || 12, tokens = {
73
+ YYYY: String(date.getFullYear()),
74
+ YY: String(date.getFullYear()).slice(-2),
75
+ MMMM: new Intl.DateTimeFormat(locale, { month: "long" }).format(date),
76
+ MMM: new Intl.DateTimeFormat(locale, { month: "short" }).format(date),
77
+ MM: pad(date.getMonth() + 1),
78
+ M: String(date.getMonth() + 1),
79
+ DD: pad(date.getDate()),
80
+ D: String(date.getDate()),
81
+ dddd: new Intl.DateTimeFormat(locale, { weekday: "long" }).format(date),
82
+ ddd: new Intl.DateTimeFormat(locale, { weekday: "short" }).format(date),
83
+ d: new Intl.DateTimeFormat(locale, { weekday: "narrow" }).format(date),
84
+ HH: pad(hours24),
85
+ H: String(hours24),
86
+ hh: pad(hours12),
87
+ h: String(hours12),
88
+ mm: pad(date.getMinutes()),
89
+ m: String(date.getMinutes()),
90
+ ss: pad(date.getSeconds()),
91
+ s: String(date.getSeconds()),
92
+ A: hours24 < 12 ? "AM" : "PM",
93
+ a: hours24 < 12 ? "am" : "pm",
94
+ Z: (() => {
95
+ const offset = -date.getTimezoneOffset(), sign = offset >= 0 ? "+" : "-", abs = Math.abs(offset);
96
+ return `${sign}${pad(Math.floor(abs / 60))}${pad(abs % 60)}`;
97
+ })()
98
+ };
99
+ return formatStr.replace(TOKEN_PATTERN, (match) => tokens[match] ?? match);
100
+ }
@@ -0,0 +1,14 @@
1
+ export { DateTime, now } from './now';
2
+ export { format } from './format';
3
+ export { parse } from './parse';
4
+ /**
5
+ * Format a date using a token-based format string.
6
+ * This is a convenience alias for `format()`.
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * dateFormat(new Date(), 'YYYY-MM-DD HH:mm:ss')
11
+ * dateFormat('2024-03-15', 'MMMM D, YYYY')
12
+ * ```
13
+ */
14
+ export { format as dateFormat } from './format';
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export { DateTime, now } from "./now";
2
+ export { format } from "./format";
3
+ export { parse } from "./parse";
4
+ export { format as dateFormat } from "./format";
package/dist/now.d.ts ADDED
@@ -0,0 +1,90 @@
1
+ import { format } from './format';
2
+ import { parse } from './parse';
3
+ /**
4
+ * Get the current date/time as a DateTime instance.
5
+ * Inspired by Laravel's `now()` helper.
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * now().toDateString() // '2024-03-15'
10
+ * now().format('MMMM D, YYYY') // 'March 15, 2024'
11
+ * now().addDays(7).toDateString()
12
+ * now().startOfMonth().toDateString()
13
+ * now().diffInDays(someOtherDate)
14
+ * ```
15
+ */
16
+ export declare function now(): DateTime;
17
+ declare interface FormatOptions {
18
+ locale?: string
19
+ tz?: string
20
+ }
21
+ declare type DateInput = Date | string;
22
+ /**
23
+ * A fluent DateTime wrapper inspired by Laravel's Carbon.
24
+ *
25
+ * Provides chainable date manipulation, formatting, and comparison
26
+ * with zero external dependencies.
27
+ */
28
+ export declare class DateTime {
29
+ constructor(date?: DateInput, formatStr?: string);
30
+ static now(): DateTime;
31
+ static create(year: number, month?: number, day?: number, hour?: number, minute?: number, second?: number): DateTime;
32
+ static fromDate(date: Date): DateTime;
33
+ static parse(dateStr: string, formatStr?: string): DateTime;
34
+ format(formatStr: string, localeOrOptions?: string | FormatOptions): string;
35
+ toDateString(): string;
36
+ toTimeString(): string;
37
+ toDateTimeString(): string;
38
+ toISOString(): string;
39
+ toString(): string;
40
+ get year(): number;
41
+ get month(): number;
42
+ get day(): number;
43
+ get hour(): number;
44
+ get minute(): number;
45
+ get second(): number;
46
+ get dayOfWeek(): number;
47
+ get timestamp(): number;
48
+ setYear(year: number): DateTime;
49
+ setMonth(month: number): DateTime;
50
+ setDay(day: number): DateTime;
51
+ setHour(hour: number): DateTime;
52
+ setMinute(minute: number): DateTime;
53
+ setSecond(second: number): DateTime;
54
+ addSeconds(n: number): DateTime;
55
+ addMinutes(n: number): DateTime;
56
+ addHours(n: number): DateTime;
57
+ addDays(n: number): DateTime;
58
+ addWeeks(n: number): DateTime;
59
+ addMonths(n: number): DateTime;
60
+ addYears(n: number): DateTime;
61
+ subSeconds(n: number): DateTime;
62
+ subMinutes(n: number): DateTime;
63
+ subHours(n: number): DateTime;
64
+ subDays(n: number): DateTime;
65
+ subWeeks(n: number): DateTime;
66
+ subMonths(n: number): DateTime;
67
+ subYears(n: number): DateTime;
68
+ startOfDay(): DateTime;
69
+ endOfDay(): DateTime;
70
+ startOfMonth(): DateTime;
71
+ endOfMonth(): DateTime;
72
+ startOfYear(): DateTime;
73
+ endOfYear(): DateTime;
74
+ isBefore(other: DateTime | Date): boolean;
75
+ isAfter(other: DateTime | Date): boolean;
76
+ isSame(other: DateTime | Date): boolean;
77
+ isSameDay(other: DateTime | Date): boolean;
78
+ isBetween(start: DateTime | Date, end: DateTime | Date): boolean;
79
+ isPast(): boolean;
80
+ isFuture(): boolean;
81
+ isToday(): boolean;
82
+ isLeapYear(): boolean;
83
+ diffInSeconds(other: DateTime | Date): number;
84
+ diffInMinutes(other: DateTime | Date): number;
85
+ diffInHours(other: DateTime | Date): number;
86
+ diffInDays(other: DateTime | Date): number;
87
+ toNativeDate(): Date;
88
+ toJSON(): string;
89
+ valueOf(): number;
90
+ }
package/dist/now.js ADDED
@@ -0,0 +1,231 @@
1
+ import { format } from "./format";
2
+ import { parse } from "./parse";
3
+
4
+ export class DateTime {
5
+ date;
6
+ constructor(date, formatStr) {
7
+ if (!date)
8
+ this.date = new Date;
9
+ else if (date instanceof Date)
10
+ this.date = new Date(date.getTime());
11
+ else if (formatStr)
12
+ this.date = parse(date, formatStr);
13
+ else
14
+ this.date = parse(date);
15
+ }
16
+ static now() {
17
+ return new DateTime;
18
+ }
19
+ static create(year, month = 1, day = 1, hour = 0, minute = 0, second = 0) {
20
+ return new DateTime(new Date(year, month - 1, day, hour, minute, second));
21
+ }
22
+ static fromDate(date) {
23
+ return new DateTime(date);
24
+ }
25
+ static parse(dateStr, formatStr) {
26
+ return new DateTime(dateStr, formatStr);
27
+ }
28
+ format(formatStr, localeOrOptions) {
29
+ return format(this.date, formatStr, localeOrOptions);
30
+ }
31
+ toDateString() {
32
+ return format(this.date, "YYYY-MM-DD");
33
+ }
34
+ toTimeString() {
35
+ return format(this.date, "HH:mm:ss");
36
+ }
37
+ toDateTimeString() {
38
+ return format(this.date, "YYYY-MM-DD HH:mm:ss");
39
+ }
40
+ toISOString() {
41
+ return this.date.toISOString();
42
+ }
43
+ toString() {
44
+ return this.toDateTimeString();
45
+ }
46
+ get year() {
47
+ return this.date.getFullYear();
48
+ }
49
+ get month() {
50
+ return this.date.getMonth() + 1;
51
+ }
52
+ get day() {
53
+ return this.date.getDate();
54
+ }
55
+ get hour() {
56
+ return this.date.getHours();
57
+ }
58
+ get minute() {
59
+ return this.date.getMinutes();
60
+ }
61
+ get second() {
62
+ return this.date.getSeconds();
63
+ }
64
+ get dayOfWeek() {
65
+ return this.date.getDay();
66
+ }
67
+ get timestamp() {
68
+ return this.date.getTime();
69
+ }
70
+ setYear(year) {
71
+ const d = new Date(this.date);
72
+ d.setFullYear(year);
73
+ return new DateTime(d);
74
+ }
75
+ setMonth(month) {
76
+ const d = new Date(this.date);
77
+ d.setMonth(month - 1);
78
+ return new DateTime(d);
79
+ }
80
+ setDay(day) {
81
+ const d = new Date(this.date);
82
+ d.setDate(day);
83
+ return new DateTime(d);
84
+ }
85
+ setHour(hour) {
86
+ const d = new Date(this.date);
87
+ d.setHours(hour);
88
+ return new DateTime(d);
89
+ }
90
+ setMinute(minute) {
91
+ const d = new Date(this.date);
92
+ d.setMinutes(minute);
93
+ return new DateTime(d);
94
+ }
95
+ setSecond(second) {
96
+ const d = new Date(this.date);
97
+ d.setSeconds(second);
98
+ return new DateTime(d);
99
+ }
100
+ addSeconds(n) {
101
+ return new DateTime(new Date(this.date.getTime() + n * 1000));
102
+ }
103
+ addMinutes(n) {
104
+ return new DateTime(new Date(this.date.getTime() + n * 60000));
105
+ }
106
+ addHours(n) {
107
+ return new DateTime(new Date(this.date.getTime() + n * 3600000));
108
+ }
109
+ addDays(n) {
110
+ const d = new Date(this.date);
111
+ d.setDate(d.getDate() + n);
112
+ return new DateTime(d);
113
+ }
114
+ addWeeks(n) {
115
+ return this.addDays(n * 7);
116
+ }
117
+ addMonths(n) {
118
+ const d = new Date(this.date);
119
+ d.setMonth(d.getMonth() + n);
120
+ return new DateTime(d);
121
+ }
122
+ addYears(n) {
123
+ const d = new Date(this.date);
124
+ d.setFullYear(d.getFullYear() + n);
125
+ return new DateTime(d);
126
+ }
127
+ subSeconds(n) {
128
+ return this.addSeconds(-n);
129
+ }
130
+ subMinutes(n) {
131
+ return this.addMinutes(-n);
132
+ }
133
+ subHours(n) {
134
+ return this.addHours(-n);
135
+ }
136
+ subDays(n) {
137
+ return this.addDays(-n);
138
+ }
139
+ subWeeks(n) {
140
+ return this.addWeeks(-n);
141
+ }
142
+ subMonths(n) {
143
+ return this.addMonths(-n);
144
+ }
145
+ subYears(n) {
146
+ return this.addYears(-n);
147
+ }
148
+ startOfDay() {
149
+ const d = new Date(this.date);
150
+ d.setHours(0, 0, 0, 0);
151
+ return new DateTime(d);
152
+ }
153
+ endOfDay() {
154
+ const d = new Date(this.date);
155
+ d.setHours(23, 59, 59, 999);
156
+ return new DateTime(d);
157
+ }
158
+ startOfMonth() {
159
+ const d = new Date(this.date);
160
+ d.setDate(1);
161
+ d.setHours(0, 0, 0, 0);
162
+ return new DateTime(d);
163
+ }
164
+ endOfMonth() {
165
+ const d = new Date(this.date.getFullYear(), this.date.getMonth() + 1, 0, 23, 59, 59, 999);
166
+ return new DateTime(d);
167
+ }
168
+ startOfYear() {
169
+ return new DateTime(new Date(this.date.getFullYear(), 0, 1, 0, 0, 0, 0));
170
+ }
171
+ endOfYear() {
172
+ return new DateTime(new Date(this.date.getFullYear(), 11, 31, 23, 59, 59, 999));
173
+ }
174
+ isBefore(other) {
175
+ const otherTime = other instanceof DateTime ? other.timestamp : other.getTime();
176
+ return this.date.getTime() < otherTime;
177
+ }
178
+ isAfter(other) {
179
+ const otherTime = other instanceof DateTime ? other.timestamp : other.getTime();
180
+ return this.date.getTime() > otherTime;
181
+ }
182
+ isSame(other) {
183
+ const otherTime = other instanceof DateTime ? other.timestamp : other.getTime();
184
+ return this.date.getTime() === otherTime;
185
+ }
186
+ isSameDay(other) {
187
+ const o = other instanceof Date ? other : other.toNativeDate();
188
+ return this.date.getFullYear() === o.getFullYear() && this.date.getMonth() === o.getMonth() && this.date.getDate() === o.getDate();
189
+ }
190
+ isBetween(start, end) {
191
+ return this.isAfter(start) && this.isBefore(end);
192
+ }
193
+ isPast() {
194
+ return this.date.getTime() < Date.now();
195
+ }
196
+ isFuture() {
197
+ return this.date.getTime() > Date.now();
198
+ }
199
+ isToday() {
200
+ return this.isSameDay(new Date);
201
+ }
202
+ isLeapYear() {
203
+ const y = this.date.getFullYear();
204
+ return y % 4 === 0 && y % 100 !== 0 || y % 400 === 0;
205
+ }
206
+ diffInSeconds(other) {
207
+ const otherTime = other instanceof DateTime ? other.timestamp : other.getTime();
208
+ return Math.floor((this.date.getTime() - otherTime) / 1000);
209
+ }
210
+ diffInMinutes(other) {
211
+ return Math.floor(this.diffInSeconds(other) / 60);
212
+ }
213
+ diffInHours(other) {
214
+ return Math.floor(this.diffInSeconds(other) / 3600);
215
+ }
216
+ diffInDays(other) {
217
+ return Math.floor(this.diffInSeconds(other) / 86400);
218
+ }
219
+ toNativeDate() {
220
+ return new Date(this.date.getTime());
221
+ }
222
+ toJSON() {
223
+ return this.toISOString();
224
+ }
225
+ valueOf() {
226
+ return this.date.getTime();
227
+ }
228
+ }
229
+ export function now() {
230
+ return DateTime.now();
231
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Parse a date string into a Date object.
3
+ *
4
+ * When a format string is provided, extracts date parts using the same tokens
5
+ * as the format function (YYYY, MM, DD, HH, mm, ss, etc.).
6
+ *
7
+ * If the format includes a Z token, the parsed offset is applied so the
8
+ * returned Date represents the correct instant in time.
9
+ *
10
+ * When no format is given, falls back to native Date parsing (with a fix
11
+ * for date-only ISO strings being treated as local time, not UTC).
12
+ */
13
+ export declare function parse(dateStr: string, formatStr?: string, _locale?: string): Date;
package/dist/parse.js ADDED
@@ -0,0 +1,81 @@
1
+ export function parse(dateStr, formatStr, _locale) {
2
+ if (!formatStr) {
3
+ if (/^\d{4}-\d{2}-\d{2}$/.test(dateStr)) {
4
+ const [y, m, d] = dateStr.split("-").map(Number);
5
+ if (y === void 0 || m === void 0 || d === void 0)
6
+ throw Error(`Unable to parse date: ${dateStr}`);
7
+ return new Date(y, m - 1, d);
8
+ }
9
+ const d = new Date(dateStr);
10
+ if (Number.isNaN(d.getTime()))
11
+ throw Error(`Unable to parse date: ${dateStr}`);
12
+ return d;
13
+ }
14
+ const tokenDefs = {
15
+ YYYY: { regex: "(\\d{4})", field: "year" },
16
+ YY: { regex: "(\\d{2})", field: "shortYear" },
17
+ MMMM: { regex: "(\\w+)", field: "monthName" },
18
+ MMM: { regex: "(\\w+)", field: "monthNameShort" },
19
+ MM: { regex: "(\\d{2})", field: "month" },
20
+ M: { regex: "(\\d{1,2})", field: "month" },
21
+ DD: { regex: "(\\d{2})", field: "day" },
22
+ D: { regex: "(\\d{1,2})", field: "day" },
23
+ HH: { regex: "(\\d{2})", field: "hours" },
24
+ H: { regex: "(\\d{1,2})", field: "hours" },
25
+ hh: { regex: "(\\d{2})", field: "hours12" },
26
+ h: { regex: "(\\d{1,2})", field: "hours12" },
27
+ mm: { regex: "(\\d{2})", field: "minutes" },
28
+ m: { regex: "(\\d{1,2})", field: "minutes" },
29
+ ss: { regex: "(\\d{2})", field: "seconds" },
30
+ s: { regex: "(\\d{1,2})", field: "seconds" },
31
+ A: { regex: "(AM|PM)", field: "ampm" },
32
+ a: { regex: "(am|pm)", field: "ampm" },
33
+ Z: { regex: "([+-]\\d{4})", field: "tz" }
34
+ }, sortedTokens = Object.keys(tokenDefs).sort((a, b) => b.length - a.length), tokenRegex = new RegExp(sortedTokens.map((t) => t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|"), "g"), fields = [], regexStr = formatStr.replace(tokenRegex, (match) => {
35
+ const def = tokenDefs[match];
36
+ if (def) {
37
+ fields.push(def.field);
38
+ return def.regex;
39
+ }
40
+ return match;
41
+ }), result = new RegExp(`^${regexStr}$`).exec(dateStr);
42
+ if (!result)
43
+ throw Error(`Unable to parse "${dateStr}" with format "${formatStr}"`);
44
+ const parts = {};
45
+ for (let i = 0;i < fields.length; i++) {
46
+ const field = fields[i], value = result[i + 1];
47
+ if (field !== void 0 && value !== void 0)
48
+ parts[field] = value;
49
+ }
50
+ let month = 0;
51
+ if (parts.month)
52
+ month = Number.parseInt(parts.month, 10) - 1;
53
+ else if (parts.monthName || parts.monthNameShort) {
54
+ const name = (parts.monthName || parts.monthNameShort || "").toLowerCase(), months = ["january", "february", "march", "april", "may", "june", "july", "august", "september", "october", "november", "december"], shortMonths = ["jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec"];
55
+ let idx = months.indexOf(name);
56
+ if (idx === -1)
57
+ idx = shortMonths.indexOf(name);
58
+ if (idx === -1)
59
+ throw Error(`Unknown month: ${parts.monthName || parts.monthNameShort}`);
60
+ month = idx;
61
+ }
62
+ let year = parts.year ? Number.parseInt(parts.year, 10) : new Date().getFullYear();
63
+ if (parts.shortYear) {
64
+ const shortYear = Number.parseInt(parts.shortYear, 10);
65
+ year = shortYear >= 70 ? 1900 + shortYear : 2000 + shortYear;
66
+ }
67
+ let hours = Number.parseInt(parts.hours || parts.hours12 || "0", 10);
68
+ if (parts.ampm) {
69
+ const isPM = parts.ampm.toLowerCase() === "pm";
70
+ if (isPM && hours < 12)
71
+ hours += 12;
72
+ if (!isPM && hours === 12)
73
+ hours = 0;
74
+ }
75
+ const day = Number.parseInt(parts.day || "1", 10), minutes = Number.parseInt(parts.minutes || "0", 10), seconds = Number.parseInt(parts.seconds || "0", 10);
76
+ if (parts.tz) {
77
+ const sign = parts.tz[0] === "+" ? 1 : -1, tzHours = Number.parseInt(parts.tz.slice(1, 3), 10), tzMinutes = Number.parseInt(parts.tz.slice(3, 5), 10), offsetMs = sign * (tzHours * 60 + tzMinutes) * 60000, utcMs = Date.UTC(year, month, day, hours, minutes, seconds) - offsetMs;
78
+ return new Date(utcMs);
79
+ }
80
+ return new Date(year, month, day, hours, minutes, seconds);
81
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@stacksjs/datetime",
3
3
  "type": "module",
4
- "version": "0.70.88",
4
+ "version": "0.70.91",
5
5
  "description": "The Stacks datetime helpers.",
6
6
  "author": "Chris Breuer",
7
7
  "contributors": [
@@ -54,7 +54,7 @@
54
54
  },
55
55
  "devDependencies": {
56
56
  "better-dx": "^0.2.16",
57
- "@stacksjs/utils": "0.70.88"
57
+ "@stacksjs/utils": "0.70.91"
58
58
  },
59
59
  "sideEffects": false
60
60
  }