@intech-software/chronera 0.1.2 → 0.1.4

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.
@@ -7,6 +7,47 @@ import { absoluteDayFromGregorianFields } from "../core/absolute-day.js";
7
7
  import { getDayOfYearFromAbsoluteDay } from "../core/day-of-year.js";
8
8
  import { getIsoDayOfWeek, getIsoWeekFromAbsoluteDay, } from "../core/iso-week.js";
9
9
  import { ChroneraError } from "../errors/errors.js";
10
+ function formatIsoOffset(offsetStr, token) {
11
+ if (offsetStr === "Z" || offsetStr === "+00:00" || offsetStr === "-00:00") {
12
+ switch (token) {
13
+ case "X":
14
+ case "XX":
15
+ case "XXX":
16
+ return "Z";
17
+ case "x":
18
+ return "+00";
19
+ case "xx":
20
+ return "+0000";
21
+ case "xxx":
22
+ return "+00:00";
23
+ default:
24
+ return "Z";
25
+ }
26
+ }
27
+ const m = offsetStr.match(/^([+-])(\d{2}):(\d{2})$/);
28
+ if (!m) {
29
+ return offsetStr;
30
+ }
31
+ const sign = m[1];
32
+ const h = m[2];
33
+ const min = m[3];
34
+ switch (token) {
35
+ case "X":
36
+ return min === "00" ? `${sign}${h}` : `${sign}${h}${min}`;
37
+ case "XX":
38
+ return `${sign}${h}${min}`;
39
+ case "XXX":
40
+ return `${sign}${h}:${min}`;
41
+ case "x":
42
+ return min === "00" ? `${sign}${h}` : `${sign}${h}${min}`;
43
+ case "xx":
44
+ return `${sign}${h}${min}`;
45
+ case "xxx":
46
+ return `${sign}${h}:${min}`;
47
+ default:
48
+ return offsetStr;
49
+ }
50
+ }
10
51
  export function formatWithPatternWithRegistry(registry, input, pattern, options = {}) {
11
52
  const tokens = scanPattern(pattern);
12
53
  const localeInfo = validateAndResolveLocale(options.locale);
@@ -26,6 +67,8 @@ export function formatWithPatternWithRegistry(registry, input, pattern, options
26
67
  let second = 0;
27
68
  let millisecond = 0;
28
69
  let offsetString = "Z";
70
+ let resolvedInstant;
71
+ let tzId = "UTC";
29
72
  if (isLocalDateTime && localDt) {
30
73
  calDate = {
31
74
  kind: "calendar-date",
@@ -48,8 +91,10 @@ export function formatWithPatternWithRegistry(registry, input, pattern, options
48
91
  calDate = resolved.calendarDate;
49
92
  absDay = resolved.absoluteDay;
50
93
  if (resolved.instant) {
94
+ resolvedInstant = resolved.instant;
95
+ tzId = resolved.timeZone ?? "UTC";
51
96
  const date = new Date(resolved.instant.epochMilliseconds);
52
- const tz = resolved.timeZone ?? "UTC";
97
+ const tz = tzId;
53
98
  // Project fields using Intl
54
99
  const dtf = new Intl.DateTimeFormat("en-US", {
55
100
  timeZone: tz,
@@ -81,6 +126,43 @@ export function formatWithPatternWithRegistry(registry, input, pattern, options
81
126
  millisecond = ((resolved.instant.epochMilliseconds % 1000) + 1000) % 1000;
82
127
  }
83
128
  }
129
+ let tzShortName;
130
+ let tzLongName;
131
+ const getTzShort = () => {
132
+ if (tzShortName !== undefined)
133
+ return tzShortName;
134
+ if (!resolvedInstant) {
135
+ tzShortName = offsetString === "Z" ? "UTC" : offsetString;
136
+ return tzShortName;
137
+ }
138
+ const d = new Date(resolvedInstant.epochMilliseconds);
139
+ const parts = new Intl.DateTimeFormat(locale, {
140
+ timeZone: tzId,
141
+ timeZoneName: "short",
142
+ }).formatToParts(d);
143
+ const p = parts.find((part) => part.type === "timeZoneName");
144
+ tzShortName = p?.value ?? (offsetString === "Z" ? "UTC" : offsetString);
145
+ return tzShortName;
146
+ };
147
+ const getTzLong = () => {
148
+ if (tzLongName !== undefined)
149
+ return tzLongName;
150
+ if (!resolvedInstant) {
151
+ tzLongName =
152
+ offsetString === "Z" ? "Coordinated Universal Time" : offsetString;
153
+ return tzLongName;
154
+ }
155
+ const d = new Date(resolvedInstant.epochMilliseconds);
156
+ const parts = new Intl.DateTimeFormat(locale, {
157
+ timeZone: tzId,
158
+ timeZoneName: "long",
159
+ }).formatToParts(d);
160
+ const p = parts.find((part) => part.type === "timeZoneName");
161
+ tzLongName =
162
+ p?.value ??
163
+ (offsetString === "Z" ? "Coordinated Universal Time" : offsetString);
164
+ return tzLongName;
165
+ };
84
166
  const month = calDate.month ?? Number.parseInt(calDate.monthCode.slice(1), 10);
85
167
  const year = calDate.eraYear ?? calDate.year;
86
168
  // Helper for localized text
@@ -200,8 +282,21 @@ export function formatWithPatternWithRegistry(registry, input, pattern, options
200
282
  case "SSS":
201
283
  out += formatNumberWithSystem(String(millisecond).padStart(3, "0"), numberingSystem);
202
284
  break;
285
+ case "X":
286
+ case "XX":
203
287
  case "XXX":
204
- out += offsetString === "+00:00" ? "Z" : offsetString;
288
+ case "x":
289
+ case "xx":
290
+ case "xxx":
291
+ out += formatIsoOffset(offsetString, t.symbol);
292
+ break;
293
+ case "z":
294
+ case "zz":
295
+ case "zzz":
296
+ out += getTzShort();
297
+ break;
298
+ case "zzzz":
299
+ out += getTzLong();
205
300
  break;
206
301
  case "Q": {
207
302
  const qNum = Math.floor((month - 1) / 3) + 1;
@@ -1 +1 @@
1
- {"version":3,"file":"format-pattern.js","sourceRoot":"","sources":["../../src/format/format-pattern.ts"],"names":[],"mappings":"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","sourcesContent":["import { scanPattern } from \"./pattern-scanner.js\";\nimport { formatNumberWithSystem } from \"../locale/numbering-system.js\";\nimport { resolveDateFormattingInput } from \"./resolve-date-input.js\";\nimport { defaultCalendarRegistry } from \"../calendar/registry.js\";\nimport { validateAndResolveLocale } from \"../locale/resolve-locale.js\";\nimport { absoluteDayFromGregorianFields } from \"../core/absolute-day.js\";\nimport { getDayOfYearFromAbsoluteDay } from \"../core/day-of-year.js\";\nimport {\n getIsoDayOfWeek,\n getIsoWeekFromAbsoluteDay,\n} from \"../core/iso-week.js\";\nimport { ChroneraError } from \"../errors/errors.js\";\n\nimport type { CalendarRegistry } from \"../calendar/registry.js\";\nimport type {\n CalendarDate,\n FormatDateInput,\n LocalDateTime,\n PatternFormatOptions,\n} from \"../public-types.js\";\n\nexport function formatWithPatternWithRegistry(\n registry: CalendarRegistry,\n input: FormatDateInput | LocalDateTime,\n pattern: string,\n options: Readonly<PatternFormatOptions> = {},\n): string {\n const tokens = scanPattern(pattern);\n const localeInfo = validateAndResolveLocale(options.locale);\n const locale = localeInfo.baseLocale;\n const numberingSystem = options.numberingSystem ?? \"latn\";\n\n // Check if input is LocalDateTime\n let isLocalDateTime = false;\n let localDt: LocalDateTime | undefined;\n if (\"kind\" in input && input.kind === \"local-date-time\") {\n isLocalDateTime = true;\n localDt = input;\n }\n\n let calDate: CalendarDate;\n let absDay: number;\n let hour = 0;\n let minute = 0;\n let second = 0;\n let millisecond = 0;\n let offsetString = \"Z\";\n\n if (isLocalDateTime && localDt) {\n calDate = {\n kind: \"calendar-date\",\n calendar: \"gregory\",\n year: localDt.date.year,\n monthCode: `M${String(localDt.date.month).padStart(2, \"0\")}`,\n month: localDt.date.month,\n day: localDt.date.day,\n era: \"CE\",\n eraYear: localDt.date.year,\n };\n absDay = absoluteDayFromGregorianFields(\n localDt.date.year,\n localDt.date.month,\n localDt.date.day,\n );\n hour = localDt.time.hour;\n minute = localDt.time.minute;\n second = localDt.time.second;\n millisecond = localDt.time.millisecond;\n } else {\n const resolved = resolveDateFormattingInput(\n registry,\n input as FormatDateInput,\n options,\n );\n calDate = resolved.calendarDate;\n absDay = resolved.absoluteDay;\n\n if (resolved.instant) {\n const date = new Date(resolved.instant.epochMilliseconds);\n const tz = resolved.timeZone ?? \"UTC\";\n\n // Project fields using Intl\n const dtf = new Intl.DateTimeFormat(\"en-US\", {\n timeZone: tz,\n hourCycle: \"h23\",\n hour: \"numeric\",\n minute: \"numeric\",\n second: \"numeric\",\n timeZoneName: \"longOffset\",\n });\n\n const parts = dtf.formatToParts(date);\n for (const p of parts) {\n if (p.type === \"hour\") hour = Number.parseInt(p.value, 10);\n if (p.type === \"minute\") minute = Number.parseInt(p.value, 10);\n if (p.type === \"second\") second = Number.parseInt(p.value, 10);\n if (p.type === \"timeZoneName\") {\n // e.g. \"GMT+07:00\" -> \"+07:00\"\n const m = p.value.match(/GMT([+-]\\d{2}:\\d{2})/);\n if (m && m[1]) {\n offsetString = m[1];\n } else if (p.value === \"GMT\") {\n offsetString = \"Z\";\n }\n }\n }\n millisecond = ((resolved.instant.epochMilliseconds % 1000) + 1000) % 1000;\n }\n }\n\n const month =\n calDate.month ?? Number.parseInt(calDate.monthCode.slice(1), 10);\n const year = calDate.eraYear ?? calDate.year;\n\n // Helper for localized text\n const localizedDate = new Date(\n Date.UTC(calDate.year, month - 1, calDate.day),\n );\n\n let out = \"\";\n for (const t of tokens) {\n if (t.type === \"literal\") {\n out += t.value;\n continue;\n }\n\n switch (t.symbol) {\n case \"y\":\n out += formatNumberWithSystem(year, numberingSystem);\n break;\n case \"yy\":\n out += formatNumberWithSystem(\n String(year % 100).padStart(2, \"0\"),\n numberingSystem,\n );\n break;\n case \"yyyy\":\n out += formatNumberWithSystem(\n String(year).padStart(4, \"0\"),\n numberingSystem,\n );\n break;\n case \"M\":\n out += formatNumberWithSystem(month, numberingSystem);\n break;\n case \"MM\":\n out += formatNumberWithSystem(\n String(month).padStart(2, \"0\"),\n numberingSystem,\n );\n break;\n case \"MMM\": {\n const dtf = new Intl.DateTimeFormat(locale, {\n calendar: calDate.calendar,\n month: \"short\",\n timeZone: \"UTC\",\n });\n out += dtf.format(localizedDate);\n break;\n }\n case \"MMMM\": {\n const dtf = new Intl.DateTimeFormat(locale, {\n calendar: calDate.calendar,\n month: \"long\",\n timeZone: \"UTC\",\n });\n out += dtf.format(localizedDate);\n break;\n }\n case \"d\":\n out += formatNumberWithSystem(calDate.day, numberingSystem);\n break;\n case \"dd\":\n out += formatNumberWithSystem(\n String(calDate.day).padStart(2, \"0\"),\n numberingSystem,\n );\n break;\n case \"E\": {\n const dtf = new Intl.DateTimeFormat(locale, {\n calendar: calDate.calendar,\n weekday: \"short\",\n timeZone: \"UTC\",\n });\n out += dtf.format(localizedDate);\n break;\n }\n case \"EEEE\": {\n const dtf = new Intl.DateTimeFormat(locale, {\n calendar: calDate.calendar,\n weekday: \"long\",\n timeZone: \"UTC\",\n });\n out += dtf.format(localizedDate);\n break;\n }\n case \"G\":\n out += calDate.era ?? (year >= 0 ? \"AD\" : \"BC\");\n break;\n case \"GGGG\": {\n const dtf = new Intl.DateTimeFormat(locale, {\n calendar: calDate.calendar,\n era: \"long\",\n timeZone: \"UTC\",\n });\n out += dtf.format(localizedDate);\n break;\n }\n case \"H\":\n out += formatNumberWithSystem(hour, numberingSystem);\n break;\n case \"HH\":\n out += formatNumberWithSystem(\n String(hour).padStart(2, \"0\"),\n numberingSystem,\n );\n break;\n case \"h\": {\n const h12 = hour % 12 === 0 ? 12 : hour % 12;\n out += formatNumberWithSystem(h12, numberingSystem);\n break;\n }\n case \"hh\": {\n const h12 = hour % 12 === 0 ? 12 : hour % 12;\n out += formatNumberWithSystem(\n String(h12).padStart(2, \"0\"),\n numberingSystem,\n );\n break;\n }\n case \"a\":\n out += hour < 12 ? \"AM\" : \"PM\";\n break;\n case \"m\":\n out += formatNumberWithSystem(minute, numberingSystem);\n break;\n case \"mm\":\n out += formatNumberWithSystem(\n String(minute).padStart(2, \"0\"),\n numberingSystem,\n );\n break;\n case \"s\":\n out += formatNumberWithSystem(second, numberingSystem);\n break;\n case \"ss\":\n out += formatNumberWithSystem(\n String(second).padStart(2, \"0\"),\n numberingSystem,\n );\n break;\n case \"S\": {\n const frac1 = Math.floor(millisecond / 100);\n out += formatNumberWithSystem(frac1, numberingSystem);\n break;\n }\n case \"SSS\":\n out += formatNumberWithSystem(\n String(millisecond).padStart(3, \"0\"),\n numberingSystem,\n );\n break;\n case \"XXX\":\n out += offsetString === \"+00:00\" ? \"Z\" : offsetString;\n break;\n case \"Q\": {\n const qNum = Math.floor((month - 1) / 3) + 1;\n out += formatNumberWithSystem(qNum, numberingSystem);\n break;\n }\n case \"QQQ\": {\n const qNum = Math.floor((month - 1) / 3) + 1;\n out += `Q${formatNumberWithSystem(qNum, numberingSystem)}`;\n break;\n }\n case \"QQQQ\": {\n const qIndex = Math.floor((month - 1) / 3);\n const qNames = [\n \"1st quarter\",\n \"2nd quarter\",\n \"3rd quarter\",\n \"4th quarter\",\n ];\n out += qNames[qIndex]!;\n break;\n }\n case \"D\": {\n const doy = getDayOfYearFromAbsoluteDay(absDay).dayOfYear;\n out += formatNumberWithSystem(doy, numberingSystem);\n break;\n }\n case \"DDD\": {\n const doy = getDayOfYearFromAbsoluteDay(absDay).dayOfYear;\n out += formatNumberWithSystem(\n String(doy).padStart(3, \"0\"),\n numberingSystem,\n );\n break;\n }\n case \"w\": {\n const wn = getIsoWeekFromAbsoluteDay(absDay).weekNumber;\n out += formatNumberWithSystem(wn, numberingSystem);\n break;\n }\n case \"ww\": {\n const wn = getIsoWeekFromAbsoluteDay(absDay).weekNumber;\n out += formatNumberWithSystem(\n String(wn).padStart(2, \"0\"),\n numberingSystem,\n );\n break;\n }\n case \"e\": {\n const dow = getIsoDayOfWeek(absDay);\n out += formatNumberWithSystem(dow, numberingSystem);\n break;\n }\n case \"ee\": {\n const dow = getIsoDayOfWeek(absDay);\n out += formatNumberWithSystem(\n String(dow).padStart(2, \"0\"),\n numberingSystem,\n );\n break;\n }\n default:\n throw new ChroneraError(\n \"CHRONERA_PATTERN_TOO_COMPLEX\",\n `Unhandled pattern symbol: ${t.symbol}`,\n );\n }\n }\n\n return out;\n}\n\nexport function formatWithPattern(\n input: FormatDateInput | LocalDateTime,\n pattern: string,\n options?: Readonly<PatternFormatOptions>,\n): string {\n return formatWithPatternWithRegistry(\n defaultCalendarRegistry,\n input,\n pattern,\n options,\n );\n}\n"]}
1
+ {"version":3,"file":"format-pattern.js","sourceRoot":"","sources":["../../src/format/format-pattern.ts"],"names":[],"mappings":"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","sourcesContent":["import { scanPattern } from \"./pattern-scanner.js\";\nimport { formatNumberWithSystem } from \"../locale/numbering-system.js\";\nimport { resolveDateFormattingInput } from \"./resolve-date-input.js\";\nimport { defaultCalendarRegistry } from \"../calendar/registry.js\";\nimport { validateAndResolveLocale } from \"../locale/resolve-locale.js\";\nimport { absoluteDayFromGregorianFields } from \"../core/absolute-day.js\";\nimport { getDayOfYearFromAbsoluteDay } from \"../core/day-of-year.js\";\nimport {\n getIsoDayOfWeek,\n getIsoWeekFromAbsoluteDay,\n} from \"../core/iso-week.js\";\nimport { ChroneraError } from \"../errors/errors.js\";\n\nimport type { CalendarRegistry } from \"../calendar/registry.js\";\nimport type {\n CalendarDate,\n FormatDateInput,\n Instant,\n LocalDateTime,\n PatternFormatOptions,\n} from \"../public-types.js\";\n\nfunction formatIsoOffset(offsetStr: string, token: string): string {\n if (offsetStr === \"Z\" || offsetStr === \"+00:00\" || offsetStr === \"-00:00\") {\n switch (token) {\n case \"X\":\n case \"XX\":\n case \"XXX\":\n return \"Z\";\n case \"x\":\n return \"+00\";\n case \"xx\":\n return \"+0000\";\n case \"xxx\":\n return \"+00:00\";\n default:\n return \"Z\";\n }\n }\n\n const m = offsetStr.match(/^([+-])(\\d{2}):(\\d{2})$/);\n if (!m) {\n return offsetStr;\n }\n const sign = m[1]!;\n const h = m[2]!;\n const min = m[3]!;\n\n switch (token) {\n case \"X\":\n return min === \"00\" ? `${sign}${h}` : `${sign}${h}${min}`;\n case \"XX\":\n return `${sign}${h}${min}`;\n case \"XXX\":\n return `${sign}${h}:${min}`;\n case \"x\":\n return min === \"00\" ? `${sign}${h}` : `${sign}${h}${min}`;\n case \"xx\":\n return `${sign}${h}${min}`;\n case \"xxx\":\n return `${sign}${h}:${min}`;\n default:\n return offsetStr;\n }\n}\n\nexport function formatWithPatternWithRegistry(\n registry: CalendarRegistry,\n input: FormatDateInput | LocalDateTime,\n pattern: string,\n options: Readonly<PatternFormatOptions> = {},\n): string {\n const tokens = scanPattern(pattern);\n const localeInfo = validateAndResolveLocale(options.locale);\n const locale = localeInfo.baseLocale;\n const numberingSystem = options.numberingSystem ?? \"latn\";\n\n // Check if input is LocalDateTime\n let isLocalDateTime = false;\n let localDt: LocalDateTime | undefined;\n if (\"kind\" in input && input.kind === \"local-date-time\") {\n isLocalDateTime = true;\n localDt = input;\n }\n\n let calDate: CalendarDate;\n let absDay: number;\n let hour = 0;\n let minute = 0;\n let second = 0;\n let millisecond = 0;\n let offsetString = \"Z\";\n let resolvedInstant: Instant | undefined;\n let tzId = \"UTC\";\n\n if (isLocalDateTime && localDt) {\n calDate = {\n kind: \"calendar-date\",\n calendar: \"gregory\",\n year: localDt.date.year,\n monthCode: `M${String(localDt.date.month).padStart(2, \"0\")}`,\n month: localDt.date.month,\n day: localDt.date.day,\n era: \"CE\",\n eraYear: localDt.date.year,\n };\n absDay = absoluteDayFromGregorianFields(\n localDt.date.year,\n localDt.date.month,\n localDt.date.day,\n );\n hour = localDt.time.hour;\n minute = localDt.time.minute;\n second = localDt.time.second;\n millisecond = localDt.time.millisecond;\n } else {\n const resolved = resolveDateFormattingInput(\n registry,\n input as FormatDateInput,\n options,\n );\n calDate = resolved.calendarDate;\n absDay = resolved.absoluteDay;\n\n if (resolved.instant) {\n resolvedInstant = resolved.instant;\n tzId = resolved.timeZone ?? \"UTC\";\n const date = new Date(resolved.instant.epochMilliseconds);\n const tz = tzId;\n\n // Project fields using Intl\n const dtf = new Intl.DateTimeFormat(\"en-US\", {\n timeZone: tz,\n hourCycle: \"h23\",\n hour: \"numeric\",\n minute: \"numeric\",\n second: \"numeric\",\n timeZoneName: \"longOffset\",\n });\n\n const parts = dtf.formatToParts(date);\n for (const p of parts) {\n if (p.type === \"hour\") hour = Number.parseInt(p.value, 10);\n if (p.type === \"minute\") minute = Number.parseInt(p.value, 10);\n if (p.type === \"second\") second = Number.parseInt(p.value, 10);\n if (p.type === \"timeZoneName\") {\n // e.g. \"GMT+07:00\" -> \"+07:00\"\n const m = p.value.match(/GMT([+-]\\d{2}:\\d{2})/);\n if (m && m[1]) {\n offsetString = m[1];\n } else if (p.value === \"GMT\") {\n offsetString = \"Z\";\n }\n }\n }\n millisecond = ((resolved.instant.epochMilliseconds % 1000) + 1000) % 1000;\n }\n }\n\n let tzShortName: string | undefined;\n let tzLongName: string | undefined;\n\n const getTzShort = (): string => {\n if (tzShortName !== undefined) return tzShortName;\n if (!resolvedInstant) {\n tzShortName = offsetString === \"Z\" ? \"UTC\" : offsetString;\n return tzShortName;\n }\n const d = new Date(resolvedInstant.epochMilliseconds);\n const parts = new Intl.DateTimeFormat(locale, {\n timeZone: tzId,\n timeZoneName: \"short\",\n }).formatToParts(d);\n const p = parts.find((part) => part.type === \"timeZoneName\");\n tzShortName = p?.value ?? (offsetString === \"Z\" ? \"UTC\" : offsetString);\n return tzShortName;\n };\n\n const getTzLong = (): string => {\n if (tzLongName !== undefined) return tzLongName;\n if (!resolvedInstant) {\n tzLongName =\n offsetString === \"Z\" ? \"Coordinated Universal Time\" : offsetString;\n return tzLongName;\n }\n const d = new Date(resolvedInstant.epochMilliseconds);\n const parts = new Intl.DateTimeFormat(locale, {\n timeZone: tzId,\n timeZoneName: \"long\",\n }).formatToParts(d);\n const p = parts.find((part) => part.type === \"timeZoneName\");\n tzLongName =\n p?.value ??\n (offsetString === \"Z\" ? \"Coordinated Universal Time\" : offsetString);\n return tzLongName;\n };\n\n const month =\n calDate.month ?? Number.parseInt(calDate.monthCode.slice(1), 10);\n const year = calDate.eraYear ?? calDate.year;\n\n // Helper for localized text\n const localizedDate = new Date(\n Date.UTC(calDate.year, month - 1, calDate.day),\n );\n\n let out = \"\";\n for (const t of tokens) {\n if (t.type === \"literal\") {\n out += t.value;\n continue;\n }\n\n switch (t.symbol) {\n case \"y\":\n out += formatNumberWithSystem(year, numberingSystem);\n break;\n case \"yy\":\n out += formatNumberWithSystem(\n String(year % 100).padStart(2, \"0\"),\n numberingSystem,\n );\n break;\n case \"yyyy\":\n out += formatNumberWithSystem(\n String(year).padStart(4, \"0\"),\n numberingSystem,\n );\n break;\n case \"M\":\n out += formatNumberWithSystem(month, numberingSystem);\n break;\n case \"MM\":\n out += formatNumberWithSystem(\n String(month).padStart(2, \"0\"),\n numberingSystem,\n );\n break;\n case \"MMM\": {\n const dtf = new Intl.DateTimeFormat(locale, {\n calendar: calDate.calendar,\n month: \"short\",\n timeZone: \"UTC\",\n });\n out += dtf.format(localizedDate);\n break;\n }\n case \"MMMM\": {\n const dtf = new Intl.DateTimeFormat(locale, {\n calendar: calDate.calendar,\n month: \"long\",\n timeZone: \"UTC\",\n });\n out += dtf.format(localizedDate);\n break;\n }\n case \"d\":\n out += formatNumberWithSystem(calDate.day, numberingSystem);\n break;\n case \"dd\":\n out += formatNumberWithSystem(\n String(calDate.day).padStart(2, \"0\"),\n numberingSystem,\n );\n break;\n case \"E\": {\n const dtf = new Intl.DateTimeFormat(locale, {\n calendar: calDate.calendar,\n weekday: \"short\",\n timeZone: \"UTC\",\n });\n out += dtf.format(localizedDate);\n break;\n }\n case \"EEEE\": {\n const dtf = new Intl.DateTimeFormat(locale, {\n calendar: calDate.calendar,\n weekday: \"long\",\n timeZone: \"UTC\",\n });\n out += dtf.format(localizedDate);\n break;\n }\n case \"G\":\n out += calDate.era ?? (year >= 0 ? \"AD\" : \"BC\");\n break;\n case \"GGGG\": {\n const dtf = new Intl.DateTimeFormat(locale, {\n calendar: calDate.calendar,\n era: \"long\",\n timeZone: \"UTC\",\n });\n out += dtf.format(localizedDate);\n break;\n }\n case \"H\":\n out += formatNumberWithSystem(hour, numberingSystem);\n break;\n case \"HH\":\n out += formatNumberWithSystem(\n String(hour).padStart(2, \"0\"),\n numberingSystem,\n );\n break;\n case \"h\": {\n const h12 = hour % 12 === 0 ? 12 : hour % 12;\n out += formatNumberWithSystem(h12, numberingSystem);\n break;\n }\n case \"hh\": {\n const h12 = hour % 12 === 0 ? 12 : hour % 12;\n out += formatNumberWithSystem(\n String(h12).padStart(2, \"0\"),\n numberingSystem,\n );\n break;\n }\n case \"a\":\n out += hour < 12 ? \"AM\" : \"PM\";\n break;\n case \"m\":\n out += formatNumberWithSystem(minute, numberingSystem);\n break;\n case \"mm\":\n out += formatNumberWithSystem(\n String(minute).padStart(2, \"0\"),\n numberingSystem,\n );\n break;\n case \"s\":\n out += formatNumberWithSystem(second, numberingSystem);\n break;\n case \"ss\":\n out += formatNumberWithSystem(\n String(second).padStart(2, \"0\"),\n numberingSystem,\n );\n break;\n case \"S\": {\n const frac1 = Math.floor(millisecond / 100);\n out += formatNumberWithSystem(frac1, numberingSystem);\n break;\n }\n case \"SSS\":\n out += formatNumberWithSystem(\n String(millisecond).padStart(3, \"0\"),\n numberingSystem,\n );\n break;\n case \"X\":\n case \"XX\":\n case \"XXX\":\n case \"x\":\n case \"xx\":\n case \"xxx\":\n out += formatIsoOffset(offsetString, t.symbol);\n break;\n case \"z\":\n case \"zz\":\n case \"zzz\":\n out += getTzShort();\n break;\n case \"zzzz\":\n out += getTzLong();\n break;\n case \"Q\": {\n const qNum = Math.floor((month - 1) / 3) + 1;\n out += formatNumberWithSystem(qNum, numberingSystem);\n break;\n }\n case \"QQQ\": {\n const qNum = Math.floor((month - 1) / 3) + 1;\n out += `Q${formatNumberWithSystem(qNum, numberingSystem)}`;\n break;\n }\n case \"QQQQ\": {\n const qIndex = Math.floor((month - 1) / 3);\n const qNames = [\n \"1st quarter\",\n \"2nd quarter\",\n \"3rd quarter\",\n \"4th quarter\",\n ];\n out += qNames[qIndex]!;\n break;\n }\n case \"D\": {\n const doy = getDayOfYearFromAbsoluteDay(absDay).dayOfYear;\n out += formatNumberWithSystem(doy, numberingSystem);\n break;\n }\n case \"DDD\": {\n const doy = getDayOfYearFromAbsoluteDay(absDay).dayOfYear;\n out += formatNumberWithSystem(\n String(doy).padStart(3, \"0\"),\n numberingSystem,\n );\n break;\n }\n case \"w\": {\n const wn = getIsoWeekFromAbsoluteDay(absDay).weekNumber;\n out += formatNumberWithSystem(wn, numberingSystem);\n break;\n }\n case \"ww\": {\n const wn = getIsoWeekFromAbsoluteDay(absDay).weekNumber;\n out += formatNumberWithSystem(\n String(wn).padStart(2, \"0\"),\n numberingSystem,\n );\n break;\n }\n case \"e\": {\n const dow = getIsoDayOfWeek(absDay);\n out += formatNumberWithSystem(dow, numberingSystem);\n break;\n }\n case \"ee\": {\n const dow = getIsoDayOfWeek(absDay);\n out += formatNumberWithSystem(\n String(dow).padStart(2, \"0\"),\n numberingSystem,\n );\n break;\n }\n default:\n throw new ChroneraError(\n \"CHRONERA_PATTERN_TOO_COMPLEX\",\n `Unhandled pattern symbol: ${t.symbol}`,\n );\n }\n }\n\n return out;\n}\n\nexport function formatWithPattern(\n input: FormatDateInput | LocalDateTime,\n pattern: string,\n options?: Readonly<PatternFormatOptions>,\n): string {\n return formatWithPatternWithRegistry(\n defaultCalendarRegistry,\n input,\n pattern,\n options,\n );\n}\n"]}
@@ -24,7 +24,16 @@ const VALID_PATTERN_TOKENS = new Set([
24
24
  "ss",
25
25
  "S",
26
26
  "SSS",
27
+ "X",
28
+ "XX",
27
29
  "XXX",
30
+ "x",
31
+ "xx",
32
+ "xxx",
33
+ "z",
34
+ "zz",
35
+ "zzz",
36
+ "zzzz",
28
37
  "Q",
29
38
  "QQQ",
30
39
  "QQQQ",
@@ -1 +1 @@
1
- {"version":3,"file":"pattern-scanner.js","sourceRoot":"","sources":["../../src/format/pattern-scanner.ts"],"names":[],"mappings":"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","sourcesContent":["import { ChroneraError } from \"../errors/errors.js\";\n\nexport type PatternToken =\n { type: \"token\"; symbol: string } | { type: \"literal\"; value: string };\n\nconst VALID_PATTERN_TOKENS = new Set([\n \"y\",\n \"yy\",\n \"yyyy\",\n \"M\",\n \"MM\",\n \"MMM\",\n \"MMMM\",\n \"d\",\n \"dd\",\n \"E\",\n \"EEEE\",\n \"G\",\n \"GGGG\",\n \"H\",\n \"HH\",\n \"h\",\n \"hh\",\n \"a\",\n \"m\",\n \"mm\",\n \"s\",\n \"ss\",\n \"S\",\n \"SSS\",\n \"XXX\",\n \"Q\",\n \"QQQ\",\n \"QQQQ\",\n \"D\",\n \"DDD\",\n \"w\",\n \"ww\",\n \"e\",\n \"ee\",\n]);\n\nexport function scanPattern(pattern: string): PatternToken[] {\n if (typeof pattern !== \"string\") {\n throw new ChroneraError(\n \"CHRONERA_PATTERN_TOO_COMPLEX\",\n \"Pattern must be a string.\",\n );\n }\n\n if (pattern.length > 256) {\n throw new ChroneraError(\n \"CHRONERA_PATTERN_TOO_LONG\",\n `Pattern length ${pattern.length} exceeds maximum limit of 256 code units.`,\n );\n }\n\n const tokens: PatternToken[] = [];\n let i = 0;\n\n while (i < pattern.length) {\n if (tokens.length >= 64) {\n throw new ChroneraError(\n \"CHRONERA_PATTERN_TOO_COMPLEX\",\n \"Pattern token count exceeds maximum limit of 64 tokens.\",\n );\n }\n\n const ch = pattern[i]!;\n\n // Literal escaped in single quotes\n if (ch === \"'\") {\n i++;\n let literal = \"\";\n while (i < pattern.length) {\n if (pattern[i] === \"'\") {\n if (i + 1 < pattern.length && pattern[i + 1] === \"'\") {\n literal += \"'\";\n i += 2;\n } else {\n i++;\n break;\n }\n } else {\n literal += pattern[i];\n i++;\n }\n }\n tokens.push({ type: \"literal\", value: literal });\n }\n // Letters are tokens\n else if (/[A-Za-z]/.test(ch)) {\n let run = ch;\n i++;\n while (i < pattern.length && pattern[i] === ch) {\n run += pattern[i];\n i++;\n }\n if (!VALID_PATTERN_TOKENS.has(run)) {\n throw new ChroneraError(\n \"CHRONERA_PATTERN_TOO_COMPLEX\",\n `Unsupported or unknown pattern token: \"${run}\".`,\n );\n }\n tokens.push({ type: \"token\", symbol: run });\n }\n // Non-letter characters outside quotes are treated as raw literals\n else {\n let literal = ch;\n i++;\n while (\n i < pattern.length &&\n pattern[i] !== \"'\" &&\n !/[A-Za-z]/.test(pattern[i]!)\n ) {\n literal += pattern[i];\n i++;\n }\n tokens.push({ type: \"literal\", value: literal });\n }\n }\n\n return tokens;\n}\n"]}
1
+ {"version":3,"file":"pattern-scanner.js","sourceRoot":"","sources":["../../src/format/pattern-scanner.ts"],"names":[],"mappings":"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","sourcesContent":["import { ChroneraError } from \"../errors/errors.js\";\n\nexport type PatternToken =\n { type: \"token\"; symbol: string } | { type: \"literal\"; value: string };\n\nconst VALID_PATTERN_TOKENS = new Set([\n \"y\",\n \"yy\",\n \"yyyy\",\n \"M\",\n \"MM\",\n \"MMM\",\n \"MMMM\",\n \"d\",\n \"dd\",\n \"E\",\n \"EEEE\",\n \"G\",\n \"GGGG\",\n \"H\",\n \"HH\",\n \"h\",\n \"hh\",\n \"a\",\n \"m\",\n \"mm\",\n \"s\",\n \"ss\",\n \"S\",\n \"SSS\",\n \"X\",\n \"XX\",\n \"XXX\",\n \"x\",\n \"xx\",\n \"xxx\",\n \"z\",\n \"zz\",\n \"zzz\",\n \"zzzz\",\n \"Q\",\n \"QQQ\",\n \"QQQQ\",\n \"D\",\n \"DDD\",\n \"w\",\n \"ww\",\n \"e\",\n \"ee\",\n]);\n\nexport function scanPattern(pattern: string): PatternToken[] {\n if (typeof pattern !== \"string\") {\n throw new ChroneraError(\n \"CHRONERA_PATTERN_TOO_COMPLEX\",\n \"Pattern must be a string.\",\n );\n }\n\n if (pattern.length > 256) {\n throw new ChroneraError(\n \"CHRONERA_PATTERN_TOO_LONG\",\n `Pattern length ${pattern.length} exceeds maximum limit of 256 code units.`,\n );\n }\n\n const tokens: PatternToken[] = [];\n let i = 0;\n\n while (i < pattern.length) {\n if (tokens.length >= 64) {\n throw new ChroneraError(\n \"CHRONERA_PATTERN_TOO_COMPLEX\",\n \"Pattern token count exceeds maximum limit of 64 tokens.\",\n );\n }\n\n const ch = pattern[i]!;\n\n // Literal escaped in single quotes\n if (ch === \"'\") {\n i++;\n let literal = \"\";\n while (i < pattern.length) {\n if (pattern[i] === \"'\") {\n if (i + 1 < pattern.length && pattern[i + 1] === \"'\") {\n literal += \"'\";\n i += 2;\n } else {\n i++;\n break;\n }\n } else {\n literal += pattern[i];\n i++;\n }\n }\n tokens.push({ type: \"literal\", value: literal });\n }\n // Letters are tokens\n else if (/[A-Za-z]/.test(ch)) {\n let run = ch;\n i++;\n while (i < pattern.length && pattern[i] === ch) {\n run += pattern[i];\n i++;\n }\n if (!VALID_PATTERN_TOKENS.has(run)) {\n throw new ChroneraError(\n \"CHRONERA_PATTERN_TOO_COMPLEX\",\n `Unsupported or unknown pattern token: \"${run}\".`,\n );\n }\n tokens.push({ type: \"token\", symbol: run });\n }\n // Non-letter characters outside quotes are treated as raw literals\n else {\n let literal = ch;\n i++;\n while (\n i < pattern.length &&\n pattern[i] !== \"'\" &&\n !/[A-Za-z]/.test(pattern[i]!)\n ) {\n literal += pattern[i];\n i++;\n }\n tokens.push({ type: \"literal\", value: literal });\n }\n }\n\n return tokens;\n}\n"]}
package/dist/index.d.ts CHANGED
@@ -2,6 +2,8 @@ export { createChronera } from "./create-chronera.js";
2
2
  export { compareInstants, compareLocalDates, sameAbsoluteDate, sameCalendarDate, } from "./operations/compare.js";
3
3
  export { getAbsoluteDay, isBefore, isAfter, isEqual, isSameDay, isBetween, isToday, addDays, subtractDays, addMonths, subtractMonths, addYears, subtractYears, diffInDays, startOfMonth, endOfMonth, startOfYear, endOfYear, } from "./operations/convenience.js";
4
4
  export { startOfDay, endOfDay, isPast, isFuture, addHours, subtractHours, addMinutes, subtractMinutes, addSeconds, subtractSeconds, } from "./operations/time-convenience.js";
5
+ export { isWeekend, isWeekday, addBusinessDays, subtractBusinessDays, diffInBusinessDays, } from "./operations/business-days.js";
6
+ export { formatInTimeZone, getTimeZoneOffset, isSameTimeZone, } from "./operations/timezone.js";
5
7
  export { convertCalendarDate } from "./operations/convert-calendar-date.js";
6
8
  export { daysInMonth, getCalendarCapabilities, isLeapYear, isValidCalendarDate, } from "./operations/validate.js";
7
9
  export { getIsoWeek, formatIsoWeek } from "./operations/iso-week.js";
@@ -18,4 +20,4 @@ export { localTime } from "./core/local-time.js";
18
20
  export { localDateTime } from "./core/local-date-time.js";
19
21
  export { dateRange } from "./core/range.js";
20
22
  export { ChroneraError, ChroneraParseError, ChroneraRangeError, ChroneraUnsupportedError, } from "./errors/index.js";
21
- export type { BuiltInCalendarId, CalendarPlugin, CalendarCapabilities, CalendarConversionMetadata, CalendarConversionResult, CalendarDate, CalendarId, ChroneraErrorCode, ChroneraConfig, ChroneraInstance, ChroneraIssue, Comparison, ConvertCalendarOptions, DateOrCalendarDate, DateRange, DayOfYearFields, Duration, EraId, FiscalFields, FiscalOptions, FormatDateBaseOptions, FormatDateInput, FormatDateOptions, FormatDateRangeOptions, FormatDateTimeOptions, FormatRelativeOptions, FormatTimeOptions, Instant, IntervalInclusivity, IsoWeekFields, LocalDate, LocalDateTime, LocalTime, LocaleId, MonthCode, NumberingSystemId, PatternFormatOptions, ParseInstantOptions, ParseLocalDateOptions, PresetName, QuarterNumber, ResolvedChroneraOptions, Rfc2822Options, RuntimeCapabilities, SafeParseResult, TimeZoneId, TimeOrDateTimeOrInstant, ZonedDateTime, } from "./public-types.js";
23
+ export type { BuiltInCalendarId, CalendarPlugin, CalendarCapabilities, CalendarConversionMetadata, CalendarConversionResult, CalendarDate, CalendarId, ChroneraErrorCode, ChroneraConfig, ChroneraInstance, ChroneraIssue, Comparison, ConvertCalendarOptions, DateOrCalendarDate, DateRange, DayOfYearFields, Duration, EraId, FiscalFields, FiscalOptions, FormatDateBaseOptions, FormatDateInput, FormatDateOptions, FormatDateRangeOptions, FormatDateTimeOptions, FormatInTimeZoneOptions, FormatRelativeOptions, FormatTimeOptions, Instant, IntervalInclusivity, IsoWeekFields, LocalDate, LocalDateTime, LocalTime, LocaleId, MonthCode, NumberingSystemId, PatternFormatOptions, ParseInstantOptions, ParseLocalDateOptions, PresetName, QuarterNumber, ResolvedChroneraOptions, Rfc2822Options, RuntimeCapabilities, SafeParseResult, SameTimeZoneOptions, TimeZoneId, TimeZoneOffsetFormat, TimeZoneOffsetInfo, TimeOrDateTimeOrInstant, ZonedDateTime, } from "./public-types.js";
package/dist/index.js CHANGED
@@ -2,6 +2,8 @@ export { createChronera } from "./create-chronera.js";
2
2
  export { compareInstants, compareLocalDates, sameAbsoluteDate, sameCalendarDate, } from "./operations/compare.js";
3
3
  export { getAbsoluteDay, isBefore, isAfter, isEqual, isSameDay, isBetween, isToday, addDays, subtractDays, addMonths, subtractMonths, addYears, subtractYears, diffInDays, startOfMonth, endOfMonth, startOfYear, endOfYear, } from "./operations/convenience.js";
4
4
  export { startOfDay, endOfDay, isPast, isFuture, addHours, subtractHours, addMinutes, subtractMinutes, addSeconds, subtractSeconds, } from "./operations/time-convenience.js";
5
+ export { isWeekend, isWeekday, addBusinessDays, subtractBusinessDays, diffInBusinessDays, } from "./operations/business-days.js";
6
+ export { formatInTimeZone, getTimeZoneOffset, isSameTimeZone, } from "./operations/timezone.js";
5
7
  export { convertCalendarDate } from "./operations/convert-calendar-date.js";
6
8
  export { daysInMonth, getCalendarCapabilities, isLeapYear, isValidCalendarDate, } from "./operations/validate.js";
7
9
  export { getIsoWeek, formatIsoWeek } from "./operations/iso-week.js";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EACL,cAAc,EACd,QAAQ,EACR,OAAO,EACP,OAAO,EACP,SAAS,EACT,SAAS,EACT,OAAO,EACP,OAAO,EACP,YAAY,EACZ,SAAS,EACT,cAAc,EACd,QAAQ,EACR,aAAa,EACb,UAAU,EACV,YAAY,EACZ,UAAU,EACV,WAAW,EACX,SAAS,GACV,MAAM,6BAA6B,CAAC;AAErC,OAAO,EACL,UAAU,EACV,QAAQ,EACR,MAAM,EACN,QAAQ,EACR,QAAQ,EACR,aAAa,EACb,UAAU,EACV,eAAe,EACf,UAAU,EACV,eAAe,GAChB,MAAM,kCAAkC,CAAC;AAE1C,OAAO,EAAE,mBAAmB,EAAE,MAAM,uCAAuC,CAAC;AAE5E,OAAO,EACL,WAAW,EACX,uBAAuB,EACvB,UAAU,EACV,mBAAmB,GACpB,MAAM,0BAA0B,CAAC;AAElC,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAErE,OAAO,EACL,YAAY,EACZ,wBAAwB,EACxB,iBAAiB,GAClB,MAAM,6BAA6B,CAAC;AAErC,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,4BAA4B,EAC5B,8BAA8B,GAC/B,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAEnE,OAAO,EACL,UAAU,EACV,eAAe,EACf,cAAc,EACd,cAAc,EACd,UAAU,EACV,iBAAiB,EACjB,aAAa,EACb,4BAA4B,EAC5B,uCAAuC,EACvC,0BAA0B,EAC1B,wBAAwB,EACxB,2BAA2B,EAC3B,uBAAuB,EACvB,wBAAwB,EACxB,2BAA2B,EAC3B,8BAA8B,EAC9B,sBAAsB,EACtB,0BAA0B,EAC1B,6BAA6B,EAC7B,6BAA6B,EAC7B,sBAAsB,EACtB,6BAA6B,EAC7B,4BAA4B,EAC5B,2BAA2B,EAC3B,uBAAuB,EACvB,2BAA2B,EAC3B,8BAA8B,EAC9B,yBAAyB,EACzB,yBAAyB,EACzB,kBAAkB,EAClB,sBAAsB,EACtB,yBAAyB,EACzB,kBAAkB,EAClB,sBAAsB,EACtB,yBAAyB,GAC1B,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,YAAY,EACZ,cAAc,EACd,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,eAAe,EACf,4BAA4B,EAC5B,uBAAuB,GACxB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AAEnE,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEvD,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEjD,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEjD,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAE1D,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,kBAAkB,EAClB,wBAAwB,GACzB,MAAM,mBAAmB,CAAC","sourcesContent":["export { createChronera } from \"./create-chronera.js\";\n\nexport {\n compareInstants,\n compareLocalDates,\n sameAbsoluteDate,\n sameCalendarDate,\n} from \"./operations/compare.js\";\n\nexport {\n getAbsoluteDay,\n isBefore,\n isAfter,\n isEqual,\n isSameDay,\n isBetween,\n isToday,\n addDays,\n subtractDays,\n addMonths,\n subtractMonths,\n addYears,\n subtractYears,\n diffInDays,\n startOfMonth,\n endOfMonth,\n startOfYear,\n endOfYear,\n} from \"./operations/convenience.js\";\n\nexport {\n startOfDay,\n endOfDay,\n isPast,\n isFuture,\n addHours,\n subtractHours,\n addMinutes,\n subtractMinutes,\n addSeconds,\n subtractSeconds,\n} from \"./operations/time-convenience.js\";\n\nexport { convertCalendarDate } from \"./operations/convert-calendar-date.js\";\n\nexport {\n daysInMonth,\n getCalendarCapabilities,\n isLeapYear,\n isValidCalendarDate,\n} from \"./operations/validate.js\";\n\nexport { getIsoWeek, formatIsoWeek } from \"./operations/iso-week.js\";\n\nexport {\n getDayOfYear,\n getDayOfYearWithRegistry,\n formatOrdinalDate,\n} from \"./operations/day-of-year.js\";\n\nexport {\n toJulianDayNumber,\n toModifiedJulianDay,\n localDateFromJulianDayNumber,\n localDateFromModifiedJulianDay,\n} from \"./operations/julian-day.js\";\n\nexport { getQuarter, getFiscalYear } from \"./operations/fiscal.js\";\n\nexport {\n formatDate,\n formatDateRange,\n formatDateTime,\n formatRelative,\n formatTime,\n formatWithPattern,\n formatRfc2822,\n formatJapaneseOfficialPreset,\n formatJapaneseOfficialWithWeekdayPreset,\n formatTaiwanOfficialPreset,\n formatThaiOfficialPreset,\n formatArabicGregorianPreset,\n formatArabicHijriPreset,\n formatChineseShortPreset,\n formatChineseStandardPreset,\n formatChineseWithWeekdayPreset,\n formatFrenchLongPreset,\n formatFrenchStandardPreset,\n formatFrenchWithWeekdayPreset,\n formatGermanDinStandardPreset,\n formatGermanLongPreset,\n formatGermanWithWeekdayPreset,\n formatJapaneseEraShortPreset,\n formatJapaneseSeirekiPreset,\n formatSpanishLongPreset,\n formatSpanishStandardPreset,\n formatSpanishWithWeekdayPreset,\n formatThaiShortDatePreset,\n formatThaiSlashDatePreset,\n formatUkLongPreset,\n formatUkStandardPreset,\n formatUkWithWeekdayPreset,\n formatUsLongPreset,\n formatUsStandardPreset,\n formatUsWithWeekdayPreset,\n} from \"./format/index.js\";\n\nexport {\n parseInstant,\n parseLocalDate,\n safeParseInstant,\n safeParseLocalDate,\n} from \"./parse/index.js\";\n\nexport {\n instantFromDate,\n instantFromEpochMilliseconds,\n instantFromEpochSeconds,\n} from \"./core/instant.js\";\n\nexport { getRuntimeCapabilities } from \"./runtime/capabilities.js\";\n\nexport { calendarDate } from \"./core/calendar-date.js\";\n\nexport { localDate } from \"./core/local-date.js\";\n\nexport { localTime } from \"./core/local-time.js\";\n\nexport { localDateTime } from \"./core/local-date-time.js\";\n\nexport { dateRange } from \"./core/range.js\";\n\nexport {\n ChroneraError,\n ChroneraParseError,\n ChroneraRangeError,\n ChroneraUnsupportedError,\n} from \"./errors/index.js\";\n\nexport type {\n BuiltInCalendarId,\n CalendarPlugin,\n CalendarCapabilities,\n CalendarConversionMetadata,\n CalendarConversionResult,\n CalendarDate,\n CalendarId,\n ChroneraErrorCode,\n ChroneraConfig,\n ChroneraInstance,\n ChroneraIssue,\n Comparison,\n ConvertCalendarOptions,\n DateOrCalendarDate,\n DateRange,\n DayOfYearFields,\n Duration,\n EraId,\n FiscalFields,\n FiscalOptions,\n FormatDateBaseOptions,\n FormatDateInput,\n FormatDateOptions,\n FormatDateRangeOptions,\n FormatDateTimeOptions,\n FormatRelativeOptions,\n FormatTimeOptions,\n Instant,\n IntervalInclusivity,\n IsoWeekFields,\n LocalDate,\n LocalDateTime,\n LocalTime,\n LocaleId,\n MonthCode,\n NumberingSystemId,\n PatternFormatOptions,\n ParseInstantOptions,\n ParseLocalDateOptions,\n PresetName,\n QuarterNumber,\n ResolvedChroneraOptions,\n Rfc2822Options,\n RuntimeCapabilities,\n SafeParseResult,\n TimeZoneId,\n TimeOrDateTimeOrInstant,\n ZonedDateTime,\n} from \"./public-types.js\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EACL,cAAc,EACd,QAAQ,EACR,OAAO,EACP,OAAO,EACP,SAAS,EACT,SAAS,EACT,OAAO,EACP,OAAO,EACP,YAAY,EACZ,SAAS,EACT,cAAc,EACd,QAAQ,EACR,aAAa,EACb,UAAU,EACV,YAAY,EACZ,UAAU,EACV,WAAW,EACX,SAAS,GACV,MAAM,6BAA6B,CAAC;AAErC,OAAO,EACL,UAAU,EACV,QAAQ,EACR,MAAM,EACN,QAAQ,EACR,QAAQ,EACR,aAAa,EACb,UAAU,EACV,eAAe,EACf,UAAU,EACV,eAAe,GAChB,MAAM,kCAAkC,CAAC;AAE1C,OAAO,EACL,SAAS,EACT,SAAS,EACT,eAAe,EACf,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,+BAA+B,CAAC;AAEvC,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,cAAc,GACf,MAAM,0BAA0B,CAAC;AAElC,OAAO,EAAE,mBAAmB,EAAE,MAAM,uCAAuC,CAAC;AAE5E,OAAO,EACL,WAAW,EACX,uBAAuB,EACvB,UAAU,EACV,mBAAmB,GACpB,MAAM,0BAA0B,CAAC;AAElC,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAErE,OAAO,EACL,YAAY,EACZ,wBAAwB,EACxB,iBAAiB,GAClB,MAAM,6BAA6B,CAAC;AAErC,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,4BAA4B,EAC5B,8BAA8B,GAC/B,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAEnE,OAAO,EACL,UAAU,EACV,eAAe,EACf,cAAc,EACd,cAAc,EACd,UAAU,EACV,iBAAiB,EACjB,aAAa,EACb,4BAA4B,EAC5B,uCAAuC,EACvC,0BAA0B,EAC1B,wBAAwB,EACxB,2BAA2B,EAC3B,uBAAuB,EACvB,wBAAwB,EACxB,2BAA2B,EAC3B,8BAA8B,EAC9B,sBAAsB,EACtB,0BAA0B,EAC1B,6BAA6B,EAC7B,6BAA6B,EAC7B,sBAAsB,EACtB,6BAA6B,EAC7B,4BAA4B,EAC5B,2BAA2B,EAC3B,uBAAuB,EACvB,2BAA2B,EAC3B,8BAA8B,EAC9B,yBAAyB,EACzB,yBAAyB,EACzB,kBAAkB,EAClB,sBAAsB,EACtB,yBAAyB,EACzB,kBAAkB,EAClB,sBAAsB,EACtB,yBAAyB,GAC1B,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,YAAY,EACZ,cAAc,EACd,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,eAAe,EACf,4BAA4B,EAC5B,uBAAuB,GACxB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AAEnE,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEvD,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEjD,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEjD,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAE1D,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,kBAAkB,EAClB,wBAAwB,GACzB,MAAM,mBAAmB,CAAC","sourcesContent":["export { createChronera } from \"./create-chronera.js\";\n\nexport {\n compareInstants,\n compareLocalDates,\n sameAbsoluteDate,\n sameCalendarDate,\n} from \"./operations/compare.js\";\n\nexport {\n getAbsoluteDay,\n isBefore,\n isAfter,\n isEqual,\n isSameDay,\n isBetween,\n isToday,\n addDays,\n subtractDays,\n addMonths,\n subtractMonths,\n addYears,\n subtractYears,\n diffInDays,\n startOfMonth,\n endOfMonth,\n startOfYear,\n endOfYear,\n} from \"./operations/convenience.js\";\n\nexport {\n startOfDay,\n endOfDay,\n isPast,\n isFuture,\n addHours,\n subtractHours,\n addMinutes,\n subtractMinutes,\n addSeconds,\n subtractSeconds,\n} from \"./operations/time-convenience.js\";\n\nexport {\n isWeekend,\n isWeekday,\n addBusinessDays,\n subtractBusinessDays,\n diffInBusinessDays,\n} from \"./operations/business-days.js\";\n\nexport {\n formatInTimeZone,\n getTimeZoneOffset,\n isSameTimeZone,\n} from \"./operations/timezone.js\";\n\nexport { convertCalendarDate } from \"./operations/convert-calendar-date.js\";\n\nexport {\n daysInMonth,\n getCalendarCapabilities,\n isLeapYear,\n isValidCalendarDate,\n} from \"./operations/validate.js\";\n\nexport { getIsoWeek, formatIsoWeek } from \"./operations/iso-week.js\";\n\nexport {\n getDayOfYear,\n getDayOfYearWithRegistry,\n formatOrdinalDate,\n} from \"./operations/day-of-year.js\";\n\nexport {\n toJulianDayNumber,\n toModifiedJulianDay,\n localDateFromJulianDayNumber,\n localDateFromModifiedJulianDay,\n} from \"./operations/julian-day.js\";\n\nexport { getQuarter, getFiscalYear } from \"./operations/fiscal.js\";\n\nexport {\n formatDate,\n formatDateRange,\n formatDateTime,\n formatRelative,\n formatTime,\n formatWithPattern,\n formatRfc2822,\n formatJapaneseOfficialPreset,\n formatJapaneseOfficialWithWeekdayPreset,\n formatTaiwanOfficialPreset,\n formatThaiOfficialPreset,\n formatArabicGregorianPreset,\n formatArabicHijriPreset,\n formatChineseShortPreset,\n formatChineseStandardPreset,\n formatChineseWithWeekdayPreset,\n formatFrenchLongPreset,\n formatFrenchStandardPreset,\n formatFrenchWithWeekdayPreset,\n formatGermanDinStandardPreset,\n formatGermanLongPreset,\n formatGermanWithWeekdayPreset,\n formatJapaneseEraShortPreset,\n formatJapaneseSeirekiPreset,\n formatSpanishLongPreset,\n formatSpanishStandardPreset,\n formatSpanishWithWeekdayPreset,\n formatThaiShortDatePreset,\n formatThaiSlashDatePreset,\n formatUkLongPreset,\n formatUkStandardPreset,\n formatUkWithWeekdayPreset,\n formatUsLongPreset,\n formatUsStandardPreset,\n formatUsWithWeekdayPreset,\n} from \"./format/index.js\";\n\nexport {\n parseInstant,\n parseLocalDate,\n safeParseInstant,\n safeParseLocalDate,\n} from \"./parse/index.js\";\n\nexport {\n instantFromDate,\n instantFromEpochMilliseconds,\n instantFromEpochSeconds,\n} from \"./core/instant.js\";\n\nexport { getRuntimeCapabilities } from \"./runtime/capabilities.js\";\n\nexport { calendarDate } from \"./core/calendar-date.js\";\n\nexport { localDate } from \"./core/local-date.js\";\n\nexport { localTime } from \"./core/local-time.js\";\n\nexport { localDateTime } from \"./core/local-date-time.js\";\n\nexport { dateRange } from \"./core/range.js\";\n\nexport {\n ChroneraError,\n ChroneraParseError,\n ChroneraRangeError,\n ChroneraUnsupportedError,\n} from \"./errors/index.js\";\n\nexport type {\n BuiltInCalendarId,\n CalendarPlugin,\n CalendarCapabilities,\n CalendarConversionMetadata,\n CalendarConversionResult,\n CalendarDate,\n CalendarId,\n ChroneraErrorCode,\n ChroneraConfig,\n ChroneraInstance,\n ChroneraIssue,\n Comparison,\n ConvertCalendarOptions,\n DateOrCalendarDate,\n DateRange,\n DayOfYearFields,\n Duration,\n EraId,\n FiscalFields,\n FiscalOptions,\n FormatDateBaseOptions,\n FormatDateInput,\n FormatDateOptions,\n FormatDateRangeOptions,\n FormatDateTimeOptions,\n FormatInTimeZoneOptions,\n FormatRelativeOptions,\n FormatTimeOptions,\n Instant,\n IntervalInclusivity,\n IsoWeekFields,\n LocalDate,\n LocalDateTime,\n LocalTime,\n LocaleId,\n MonthCode,\n NumberingSystemId,\n PatternFormatOptions,\n ParseInstantOptions,\n ParseLocalDateOptions,\n PresetName,\n QuarterNumber,\n ResolvedChroneraOptions,\n Rfc2822Options,\n RuntimeCapabilities,\n SafeParseResult,\n SameTimeZoneOptions,\n TimeZoneId,\n TimeZoneOffsetFormat,\n TimeZoneOffsetInfo,\n TimeOrDateTimeOrInstant,\n ZonedDateTime,\n} from \"./public-types.js\";\n"]}
@@ -0,0 +1,27 @@
1
+ import type { DateOrCalendarDate } from "../public-types.js";
2
+ /**
3
+ * Returns true if the specified date falls on a weekend (Saturday or Sunday).
4
+ * Works across all calendars (Gregorian, Thai Buddhist, Japanese, Hijri, etc.).
5
+ */
6
+ export declare function isWeekend(date: DateOrCalendarDate): boolean;
7
+ /**
8
+ * Returns true if the specified date falls on a weekday (Monday through Friday).
9
+ * Works across all calendars (Gregorian, Thai Buddhist, Japanese, Hijri, etc.).
10
+ */
11
+ export declare function isWeekday(date: DateOrCalendarDate): boolean;
12
+ /**
13
+ * Adds business days to a LocalDate or CalendarDate, skipping Saturdays and Sundays.
14
+ * Supports positive, negative, and zero day additions.
15
+ * Uses O(1) mathematical week advancement for large intervals while preserving exact calendar semantics.
16
+ */
17
+ export declare function addBusinessDays<T extends DateOrCalendarDate>(date: T, amount: number): T;
18
+ /**
19
+ * Subtracts business days from a LocalDate or CalendarDate, skipping weekends.
20
+ */
21
+ export declare function subtractBusinessDays<T extends DateOrCalendarDate>(date: T, amount: number): T;
22
+ /**
23
+ * Returns the signed count of business days between two dates (left - right).
24
+ * Positive if left is after right, negative if left is before right, 0 if identical.
25
+ * Works across all calendar systems with O(1) mathematical week acceleration.
26
+ */
27
+ export declare function diffInBusinessDays(left: DateOrCalendarDate, right: DateOrCalendarDate): number;
@@ -0,0 +1,93 @@
1
+ import { getIsoDayOfWeek } from "../core/iso-week.js";
2
+ import { ChroneraError } from "../errors/errors.js";
3
+ import { addDays, getAbsoluteDay } from "./convenience.js";
4
+ /**
5
+ * Returns true if the specified date falls on a weekend (Saturday or Sunday).
6
+ * Works across all calendars (Gregorian, Thai Buddhist, Japanese, Hijri, etc.).
7
+ */
8
+ export function isWeekend(date) {
9
+ const abs = getAbsoluteDay(date);
10
+ const dow = getIsoDayOfWeek(abs);
11
+ return dow === 6 || dow === 7;
12
+ }
13
+ /**
14
+ * Returns true if the specified date falls on a weekday (Monday through Friday).
15
+ * Works across all calendars (Gregorian, Thai Buddhist, Japanese, Hijri, etc.).
16
+ */
17
+ export function isWeekday(date) {
18
+ return !isWeekend(date);
19
+ }
20
+ /**
21
+ * Adds business days to a LocalDate or CalendarDate, skipping Saturdays and Sundays.
22
+ * Supports positive, negative, and zero day additions.
23
+ * Uses O(1) mathematical week advancement for large intervals while preserving exact calendar semantics.
24
+ */
25
+ export function addBusinessDays(date, amount) {
26
+ if (!Number.isFinite(amount)) {
27
+ throw new ChroneraError("CHRONERA_OUT_OF_RANGE", "Amount must be a finite integer.");
28
+ }
29
+ const intAmount = Math.trunc(amount);
30
+ if (intAmount === 0) {
31
+ return date;
32
+ }
33
+ const startAbs = getAbsoluteDay(date);
34
+ let currentAbs = startAbs;
35
+ let remaining = intAmount;
36
+ const step = remaining > 0 ? 1 : -1;
37
+ while (remaining !== 0) {
38
+ const currentDow = getIsoDayOfWeek(currentAbs);
39
+ if (currentDow !== 6 && currentDow !== 7 && Math.abs(remaining) >= 5) {
40
+ const fullWeeks = Math.trunc(remaining / 5);
41
+ currentAbs += fullWeeks * 7;
42
+ remaining %= 5;
43
+ }
44
+ else {
45
+ currentAbs += step;
46
+ const dow = getIsoDayOfWeek(currentAbs);
47
+ if (dow !== 6 && dow !== 7) {
48
+ remaining -= step;
49
+ }
50
+ }
51
+ }
52
+ const deltaDays = currentAbs - startAbs;
53
+ return addDays(date, deltaDays);
54
+ }
55
+ /**
56
+ * Subtracts business days from a LocalDate or CalendarDate, skipping weekends.
57
+ */
58
+ export function subtractBusinessDays(date, amount) {
59
+ return addBusinessDays(date, -amount);
60
+ }
61
+ /**
62
+ * Returns the signed count of business days between two dates (left - right).
63
+ * Positive if left is after right, negative if left is before right, 0 if identical.
64
+ * Works across all calendar systems with O(1) mathematical week acceleration.
65
+ */
66
+ export function diffInBusinessDays(left, right) {
67
+ const absLeft = getAbsoluteDay(left);
68
+ const absRight = getAbsoluteDay(right);
69
+ if (absLeft === absRight) {
70
+ return 0;
71
+ }
72
+ if (absLeft < absRight) {
73
+ return -diffInBusinessDays(right, left);
74
+ }
75
+ let count = 0;
76
+ let current = absRight;
77
+ // O(1) acceleration: any consecutive 7 calendar days contains exactly 5 business days
78
+ const fullWeeks = Math.floor((absLeft - current) / 7);
79
+ if (fullWeeks > 0) {
80
+ count += fullWeeks * 5;
81
+ current += fullWeeks * 7;
82
+ }
83
+ // Step through remainder (at most 6 days)
84
+ while (current < absLeft) {
85
+ current++;
86
+ const dow = getIsoDayOfWeek(current);
87
+ if (dow !== 6 && dow !== 7) {
88
+ count++;
89
+ }
90
+ }
91
+ return count;
92
+ }
93
+ //# sourceMappingURL=business-days.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"business-days.js","sourceRoot":"","sources":["../../src/operations/business-days.ts"],"names":[],"mappings":"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","sourcesContent":["import { getIsoDayOfWeek } from \"../core/iso-week.js\";\nimport { ChroneraError } from \"../errors/errors.js\";\nimport { addDays, getAbsoluteDay } from \"./convenience.js\";\n\nimport type { DateOrCalendarDate } from \"../public-types.js\";\n\n/**\n * Returns true if the specified date falls on a weekend (Saturday or Sunday).\n * Works across all calendars (Gregorian, Thai Buddhist, Japanese, Hijri, etc.).\n */\nexport function isWeekend(date: DateOrCalendarDate): boolean {\n const abs = getAbsoluteDay(date);\n const dow = getIsoDayOfWeek(abs);\n return dow === 6 || dow === 7;\n}\n\n/**\n * Returns true if the specified date falls on a weekday (Monday through Friday).\n * Works across all calendars (Gregorian, Thai Buddhist, Japanese, Hijri, etc.).\n */\nexport function isWeekday(date: DateOrCalendarDate): boolean {\n return !isWeekend(date);\n}\n\n/**\n * Adds business days to a LocalDate or CalendarDate, skipping Saturdays and Sundays.\n * Supports positive, negative, and zero day additions.\n * Uses O(1) mathematical week advancement for large intervals while preserving exact calendar semantics.\n */\nexport function addBusinessDays<T extends DateOrCalendarDate>(\n date: T,\n amount: number,\n): T {\n if (!Number.isFinite(amount)) {\n throw new ChroneraError(\n \"CHRONERA_OUT_OF_RANGE\",\n \"Amount must be a finite integer.\",\n );\n }\n\n const intAmount = Math.trunc(amount);\n if (intAmount === 0) {\n return date;\n }\n\n const startAbs = getAbsoluteDay(date);\n let currentAbs = startAbs;\n let remaining = intAmount;\n const step = remaining > 0 ? 1 : -1;\n\n while (remaining !== 0) {\n const currentDow = getIsoDayOfWeek(currentAbs);\n if (currentDow !== 6 && currentDow !== 7 && Math.abs(remaining) >= 5) {\n const fullWeeks = Math.trunc(remaining / 5);\n currentAbs += fullWeeks * 7;\n remaining %= 5;\n } else {\n currentAbs += step;\n const dow = getIsoDayOfWeek(currentAbs);\n if (dow !== 6 && dow !== 7) {\n remaining -= step;\n }\n }\n }\n\n const deltaDays = currentAbs - startAbs;\n return addDays(date, deltaDays);\n}\n\n/**\n * Subtracts business days from a LocalDate or CalendarDate, skipping weekends.\n */\nexport function subtractBusinessDays<T extends DateOrCalendarDate>(\n date: T,\n amount: number,\n): T {\n return addBusinessDays(date, -amount);\n}\n\n/**\n * Returns the signed count of business days between two dates (left - right).\n * Positive if left is after right, negative if left is before right, 0 if identical.\n * Works across all calendar systems with O(1) mathematical week acceleration.\n */\nexport function diffInBusinessDays(\n left: DateOrCalendarDate,\n right: DateOrCalendarDate,\n): number {\n const absLeft = getAbsoluteDay(left);\n const absRight = getAbsoluteDay(right);\n\n if (absLeft === absRight) {\n return 0;\n }\n\n if (absLeft < absRight) {\n return -diffInBusinessDays(right, left);\n }\n\n let count = 0;\n let current = absRight;\n\n // O(1) acceleration: any consecutive 7 calendar days contains exactly 5 business days\n const fullWeeks = Math.floor((absLeft - current) / 7);\n if (fullWeeks > 0) {\n count += fullWeeks * 5;\n current += fullWeeks * 7;\n }\n\n // Step through remainder (at most 6 days)\n while (current < absLeft) {\n current++;\n const dow = getIsoDayOfWeek(current);\n if (dow !== 6 && dow !== 7) {\n count++;\n }\n }\n\n return count;\n}\n"]}
@@ -0,0 +1,28 @@
1
+ import type { FormatInTimeZoneOptions, Instant, SameTimeZoneOptions, TimeZoneId, TimeZoneOffsetFormat, TimeZoneOffsetInfo } from "../public-types.js";
2
+ /**
3
+ * Formats an Instant or Date in the specified IANA target time zone using a pattern string.
4
+ *
5
+ * @param instant - The source Instant or JavaScript Date.
6
+ * @param timeZone - The canonical or valid IANA time zone identifier (e.g. "Asia/Bangkok", "America/New_York").
7
+ * @param pattern - An LDML pattern string (e.g. "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm:ss XXX", "hh:mm a zzz").
8
+ * @param optionsOrLocale - Optional locale string or FormatInTimeZoneOptions object.
9
+ * @returns The formatted date/time string.
10
+ */
11
+ export declare function formatInTimeZone(instant: Instant | Date, timeZone: TimeZoneId, pattern: string, optionsOrLocale?: string | Readonly<FormatInTimeZoneOptions>): string;
12
+ /**
13
+ * Computes the time zone offset at the given instant (or current time if omitted).
14
+ */
15
+ export declare function getTimeZoneOffset(timeZone: TimeZoneId, instant?: Instant | Date, format?: "string"): string;
16
+ export declare function getTimeZoneOffset(timeZone: TimeZoneId, instant: Instant | Date | undefined, format: "minutes"): number;
17
+ export declare function getTimeZoneOffset(timeZone: TimeZoneId, instant: Instant | Date | undefined, format: "totalSeconds"): number;
18
+ export declare function getTimeZoneOffset(timeZone: TimeZoneId, instant: Instant | Date | undefined, format: "object"): TimeZoneOffsetInfo;
19
+ export declare function getTimeZoneOffset(timeZone: TimeZoneId, instant?: Instant | Date, format?: TimeZoneOffsetFormat): string | number | TimeZoneOffsetInfo;
20
+ /**
21
+ * Checks whether two IANA time zone identifiers are equivalent.
22
+ *
23
+ * @param tz1 - The first time zone identifier.
24
+ * @param tz2 - The second time zone identifier.
25
+ * @param options - Mode ("canonical" | "offset") and optional reference instant for offset comparison.
26
+ * @returns true if equivalent according to the specified mode; otherwise false.
27
+ */
28
+ export declare function isSameTimeZone(tz1: TimeZoneId, tz2: TimeZoneId, options?: "canonical" | "offset" | SameTimeZoneOptions): boolean;
@@ -0,0 +1,120 @@
1
+ import { projectInstantToZonedFields, validateTimeZone, } from "../runtime/timezone.js";
2
+ import { formatWithPatternWithRegistry } from "../format/format-pattern.js";
3
+ import { defaultCalendarRegistry } from "../calendar/registry.js";
4
+ import { instantFromDate } from "../core/instant.js";
5
+ import { ChroneraError } from "../errors/errors.js";
6
+ function toInstant(input) {
7
+ if (input instanceof Date) {
8
+ return instantFromDate(input);
9
+ }
10
+ if (typeof input === "object" &&
11
+ input !== null &&
12
+ "kind" in input &&
13
+ "epochMilliseconds" in input &&
14
+ input.kind === "instant" &&
15
+ typeof input.epochMilliseconds === "number") {
16
+ return input;
17
+ }
18
+ throw new ChroneraError("CHRONERA_INVALID_DATE", "Expected a valid Instant or Date object.");
19
+ }
20
+ /**
21
+ * Formats an Instant or Date in the specified IANA target time zone using a pattern string.
22
+ *
23
+ * @param instant - The source Instant or JavaScript Date.
24
+ * @param timeZone - The canonical or valid IANA time zone identifier (e.g. "Asia/Bangkok", "America/New_York").
25
+ * @param pattern - An LDML pattern string (e.g. "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm:ss XXX", "hh:mm a zzz").
26
+ * @param optionsOrLocale - Optional locale string or FormatInTimeZoneOptions object.
27
+ * @returns The formatted date/time string.
28
+ */
29
+ export function formatInTimeZone(instant, timeZone, pattern, optionsOrLocale) {
30
+ validateTimeZone(timeZone);
31
+ const targetInstant = toInstant(instant);
32
+ const options = typeof optionsOrLocale === "string"
33
+ ? { locale: optionsOrLocale }
34
+ : (optionsOrLocale ?? {});
35
+ return formatWithPatternWithRegistry(defaultCalendarRegistry, targetInstant, pattern, {
36
+ ...options,
37
+ timeZone,
38
+ });
39
+ }
40
+ export function getTimeZoneOffset(timeZone, instant, format) {
41
+ validateTimeZone(timeZone);
42
+ const targetInstant = instant === undefined
43
+ ? { kind: "instant", epochMilliseconds: Date.now() }
44
+ : toInstant(instant);
45
+ const fields = projectInstantToZonedFields(targetInstant, timeZone);
46
+ const zonedUtcMs = Date.UTC(fields.year, fields.month - 1, fields.day, fields.hour, fields.minute, fields.second, fields.millisecond);
47
+ const offsetMs = zonedUtcMs - targetInstant.epochMilliseconds;
48
+ const minutes = Math.round(offsetMs / 60000);
49
+ const totalSeconds = Math.round(offsetMs / 1000);
50
+ const sign = minutes >= 0 ? "+" : "-";
51
+ const absMinutes = Math.abs(minutes);
52
+ const hours = Math.floor(absMinutes / 60);
53
+ const mins = absMinutes % 60;
54
+ const formatted = `${sign}${String(hours).padStart(2, "0")}:${String(mins).padStart(2, "0")}`;
55
+ const selectedFormat = format ?? "string";
56
+ if (selectedFormat === "string") {
57
+ return formatted;
58
+ }
59
+ if (selectedFormat === "minutes") {
60
+ return minutes;
61
+ }
62
+ if (selectedFormat === "totalSeconds") {
63
+ return totalSeconds;
64
+ }
65
+ // format === "object": determine DST
66
+ const janInstant = {
67
+ kind: "instant",
68
+ epochMilliseconds: Date.UTC(fields.year, 0, 1, 12, 0, 0),
69
+ };
70
+ const julInstant = {
71
+ kind: "instant",
72
+ epochMilliseconds: Date.UTC(fields.year, 6, 1, 12, 0, 0),
73
+ };
74
+ const janFields = projectInstantToZonedFields(janInstant, timeZone);
75
+ const julFields = projectInstantToZonedFields(julInstant, timeZone);
76
+ const janOffsetMs = Date.UTC(janFields.year, janFields.month - 1, janFields.day, janFields.hour, janFields.minute, janFields.second) - janInstant.epochMilliseconds;
77
+ const julOffsetMs = Date.UTC(julFields.year, julFields.month - 1, julFields.day, julFields.hour, julFields.minute, julFields.second) - julInstant.epochMilliseconds;
78
+ const standardOffsetMs = Math.min(janOffsetMs, julOffsetMs);
79
+ const isDst = offsetMs > standardOffsetMs && janOffsetMs !== julOffsetMs;
80
+ return {
81
+ formatted,
82
+ minutes,
83
+ totalSeconds,
84
+ isDst,
85
+ };
86
+ }
87
+ /**
88
+ * Checks whether two IANA time zone identifiers are equivalent.
89
+ *
90
+ * @param tz1 - The first time zone identifier.
91
+ * @param tz2 - The second time zone identifier.
92
+ * @param options - Mode ("canonical" | "offset") and optional reference instant for offset comparison.
93
+ * @returns true if equivalent according to the specified mode; otherwise false.
94
+ */
95
+ export function isSameTimeZone(tz1, tz2, options) {
96
+ validateTimeZone(tz1);
97
+ validateTimeZone(tz2);
98
+ const mode = typeof options === "string" ? options : (options?.mode ?? "canonical");
99
+ if (mode === "canonical") {
100
+ const trimmed1 = tz1.trim();
101
+ const trimmed2 = tz2.trim();
102
+ if (trimmed1 === trimmed2)
103
+ return true;
104
+ const canonical1 = new Intl.DateTimeFormat(undefined, {
105
+ timeZone: trimmed1,
106
+ }).resolvedOptions().timeZone;
107
+ const canonical2 = new Intl.DateTimeFormat(undefined, {
108
+ timeZone: trimmed2,
109
+ }).resolvedOptions().timeZone;
110
+ return canonical1 === canonical2;
111
+ }
112
+ // mode === "offset"
113
+ const refInstant = typeof options === "object" && options?.instant !== undefined
114
+ ? options.instant
115
+ : undefined;
116
+ const offset1 = getTimeZoneOffset(tz1, refInstant, "minutes");
117
+ const offset2 = getTimeZoneOffset(tz2, refInstant, "minutes");
118
+ return offset1 === offset2;
119
+ }
120
+ //# sourceMappingURL=timezone.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timezone.js","sourceRoot":"","sources":["../../src/operations/timezone.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n projectInstantToZonedFields,\n validateTimeZone,\n} from \"../runtime/timezone.js\";\nimport { formatWithPatternWithRegistry } from \"../format/format-pattern.js\";\nimport { defaultCalendarRegistry } from \"../calendar/registry.js\";\nimport { instantFromDate } from \"../core/instant.js\";\nimport { ChroneraError } from \"../errors/errors.js\";\n\nimport type {\n FormatInTimeZoneOptions,\n Instant,\n SameTimeZoneOptions,\n TimeZoneId,\n TimeZoneOffsetFormat,\n TimeZoneOffsetInfo,\n} from \"../public-types.js\";\n\nfunction toInstant(input: unknown): Instant {\n if (input instanceof Date) {\n return instantFromDate(input);\n }\n if (\n typeof input === \"object\" &&\n input !== null &&\n \"kind\" in input &&\n \"epochMilliseconds\" in input &&\n (input as Record<string, unknown>).kind === \"instant\" &&\n typeof (input as Record<string, unknown>).epochMilliseconds === \"number\"\n ) {\n return input as Instant;\n }\n throw new ChroneraError(\n \"CHRONERA_INVALID_DATE\",\n \"Expected a valid Instant or Date object.\",\n );\n}\n\n/**\n * Formats an Instant or Date in the specified IANA target time zone using a pattern string.\n *\n * @param instant - The source Instant or JavaScript Date.\n * @param timeZone - The canonical or valid IANA time zone identifier (e.g. \"Asia/Bangkok\", \"America/New_York\").\n * @param pattern - An LDML pattern string (e.g. \"yyyy-MM-dd HH:mm:ss\", \"yyyy-MM-dd HH:mm:ss XXX\", \"hh:mm a zzz\").\n * @param optionsOrLocale - Optional locale string or FormatInTimeZoneOptions object.\n * @returns The formatted date/time string.\n */\nexport function formatInTimeZone(\n instant: Instant | Date,\n timeZone: TimeZoneId,\n pattern: string,\n optionsOrLocale?: string | Readonly<FormatInTimeZoneOptions>,\n): string {\n validateTimeZone(timeZone);\n const targetInstant = toInstant(instant);\n\n const options: FormatInTimeZoneOptions =\n typeof optionsOrLocale === \"string\"\n ? { locale: optionsOrLocale }\n : (optionsOrLocale ?? {});\n\n return formatWithPatternWithRegistry(\n defaultCalendarRegistry,\n targetInstant,\n pattern,\n {\n ...options,\n timeZone,\n },\n );\n}\n\n/**\n * Computes the time zone offset at the given instant (or current time if omitted).\n */\nexport function getTimeZoneOffset(\n timeZone: TimeZoneId,\n instant?: Instant | Date,\n format?: \"string\",\n): string;\nexport function getTimeZoneOffset(\n timeZone: TimeZoneId,\n instant: Instant | Date | undefined,\n format: \"minutes\",\n): number;\nexport function getTimeZoneOffset(\n timeZone: TimeZoneId,\n instant: Instant | Date | undefined,\n format: \"totalSeconds\",\n): number;\nexport function getTimeZoneOffset(\n timeZone: TimeZoneId,\n instant: Instant | Date | undefined,\n format: \"object\",\n): TimeZoneOffsetInfo;\nexport function getTimeZoneOffset(\n timeZone: TimeZoneId,\n instant?: Instant | Date,\n format?: TimeZoneOffsetFormat,\n): string | number | TimeZoneOffsetInfo;\nexport function getTimeZoneOffset(\n timeZone: TimeZoneId,\n instant?: Instant | Date,\n format?: TimeZoneOffsetFormat,\n): string | number | TimeZoneOffsetInfo {\n validateTimeZone(timeZone);\n\n const targetInstant: Instant =\n instant === undefined\n ? { kind: \"instant\", epochMilliseconds: Date.now() }\n : toInstant(instant);\n\n const fields = projectInstantToZonedFields(targetInstant, timeZone);\n const zonedUtcMs = Date.UTC(\n fields.year,\n fields.month - 1,\n fields.day,\n fields.hour,\n fields.minute,\n fields.second,\n fields.millisecond,\n );\n\n const offsetMs = zonedUtcMs - targetInstant.epochMilliseconds;\n const minutes = Math.round(offsetMs / 60000);\n const totalSeconds = Math.round(offsetMs / 1000);\n\n const sign = minutes >= 0 ? \"+\" : \"-\";\n const absMinutes = Math.abs(minutes);\n const hours = Math.floor(absMinutes / 60);\n const mins = absMinutes % 60;\n const formatted = `${sign}${String(hours).padStart(2, \"0\")}:${String(mins).padStart(2, \"0\")}`;\n\n const selectedFormat = format ?? \"string\";\n if (selectedFormat === \"string\") {\n return formatted;\n }\n if (selectedFormat === \"minutes\") {\n return minutes;\n }\n if (selectedFormat === \"totalSeconds\") {\n return totalSeconds;\n }\n\n // format === \"object\": determine DST\n const janInstant: Instant = {\n kind: \"instant\",\n epochMilliseconds: Date.UTC(fields.year, 0, 1, 12, 0, 0),\n };\n const julInstant: Instant = {\n kind: \"instant\",\n epochMilliseconds: Date.UTC(fields.year, 6, 1, 12, 0, 0),\n };\n\n const janFields = projectInstantToZonedFields(janInstant, timeZone);\n const julFields = projectInstantToZonedFields(julInstant, timeZone);\n\n const janOffsetMs =\n Date.UTC(\n janFields.year,\n janFields.month - 1,\n janFields.day,\n janFields.hour,\n janFields.minute,\n janFields.second,\n ) - janInstant.epochMilliseconds;\n\n const julOffsetMs =\n Date.UTC(\n julFields.year,\n julFields.month - 1,\n julFields.day,\n julFields.hour,\n julFields.minute,\n julFields.second,\n ) - julInstant.epochMilliseconds;\n\n const standardOffsetMs = Math.min(janOffsetMs, julOffsetMs);\n const isDst = offsetMs > standardOffsetMs && janOffsetMs !== julOffsetMs;\n\n return {\n formatted,\n minutes,\n totalSeconds,\n isDst,\n };\n}\n\n/**\n * Checks whether two IANA time zone identifiers are equivalent.\n *\n * @param tz1 - The first time zone identifier.\n * @param tz2 - The second time zone identifier.\n * @param options - Mode (\"canonical\" | \"offset\") and optional reference instant for offset comparison.\n * @returns true if equivalent according to the specified mode; otherwise false.\n */\nexport function isSameTimeZone(\n tz1: TimeZoneId,\n tz2: TimeZoneId,\n options?: \"canonical\" | \"offset\" | SameTimeZoneOptions,\n): boolean {\n validateTimeZone(tz1);\n validateTimeZone(tz2);\n\n const mode =\n typeof options === \"string\" ? options : (options?.mode ?? \"canonical\");\n\n if (mode === \"canonical\") {\n const trimmed1 = tz1.trim();\n const trimmed2 = tz2.trim();\n if (trimmed1 === trimmed2) return true;\n\n const canonical1 = new Intl.DateTimeFormat(undefined, {\n timeZone: trimmed1,\n }).resolvedOptions().timeZone;\n const canonical2 = new Intl.DateTimeFormat(undefined, {\n timeZone: trimmed2,\n }).resolvedOptions().timeZone;\n\n return canonical1 === canonical2;\n }\n\n // mode === \"offset\"\n const refInstant =\n typeof options === \"object\" && options?.instant !== undefined\n ? options.instant\n : undefined;\n\n const offset1 = getTimeZoneOffset(tz1, refInstant, \"minutes\");\n const offset2 = getTimeZoneOffset(tz2, refInstant, \"minutes\");\n\n return offset1 === offset2;\n}\n"]}
@@ -210,3 +210,19 @@ export interface ChroneraInstance {
210
210
  resolvedOptions(): ResolvedChroneraOptions;
211
211
  }
212
212
  export type { IsoWeekFields } from "./core/iso-week.js";
213
+ export interface FormatInTimeZoneOptions {
214
+ readonly locale?: string;
215
+ readonly numberingSystem?: NumberingSystemId;
216
+ readonly calendar?: CalendarId;
217
+ }
218
+ export type TimeZoneOffsetFormat = "string" | "minutes" | "totalSeconds" | "object";
219
+ export interface TimeZoneOffsetInfo {
220
+ readonly formatted: string;
221
+ readonly minutes: number;
222
+ readonly totalSeconds: number;
223
+ readonly isDst: boolean;
224
+ }
225
+ export interface SameTimeZoneOptions {
226
+ readonly instant?: Instant | Date;
227
+ readonly mode?: "canonical" | "offset";
228
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"public-types.js","sourceRoot":"","sources":["../src/public-types.ts"],"names":[],"mappings":"","sourcesContent":["import type { DayOfYearFields } from \"./core/day-of-year.js\";\nimport type {\n FiscalFields,\n FiscalOptions,\n QuarterNumber,\n} from \"./core/fiscal.js\";\nimport type { ChroneraErrorCode } from \"./errors/error-codes.js\";\nimport type { PresetName } from \"./format/presets/types.js\";\nimport type { Rfc2822Options } from \"./format/rfc2822.js\";\n\nexport type {\n ChroneraErrorCode,\n DayOfYearFields,\n FiscalFields,\n FiscalOptions,\n PresetName,\n QuarterNumber,\n Rfc2822Options,\n};\n\nexport type BuiltInCalendarId =\n | \"iso8601\"\n | \"gregory\"\n | \"buddhist\"\n | \"islamic\"\n | \"islamic-civil\"\n | \"islamic-tbla\"\n | \"islamic-umalqura\"\n | \"persian\"\n | \"hebrew\"\n | \"japanese\"\n | \"roc\"\n | \"indian\"\n | \"coptic\"\n | \"ethiopic\"\n | \"chinese\"\n | \"dangi\";\n\ntype ExtensibleIdentifier = string & Record<never, never>;\n\nexport type CalendarId = BuiltInCalendarId | ExtensibleIdentifier;\n\nexport type LocaleId = string;\nexport type TimeZoneId = string;\nexport type NumberingSystemId = string;\nexport type EraId = string;\nexport type MonthCode = `M${string}`;\n\nexport interface Instant {\n readonly kind: \"instant\";\n readonly epochMilliseconds: number;\n}\n\nexport interface LocalDate {\n readonly kind: \"local-date\";\n readonly year: number;\n readonly month: number;\n readonly day: number;\n}\n\nexport interface LocalTime {\n readonly kind: \"local-time\";\n readonly hour: number;\n readonly minute: number;\n readonly second: number;\n readonly millisecond: number;\n}\n\nexport interface LocalDateTime {\n readonly kind: \"local-date-time\";\n readonly date: LocalDate;\n readonly time: LocalTime;\n}\n\nexport interface CalendarDate {\n readonly kind: \"calendar-date\";\n readonly calendar: CalendarId;\n readonly era?: EraId;\n readonly eraYear?: number;\n readonly year: number;\n readonly monthCode: MonthCode;\n readonly month?: number;\n readonly day: number;\n}\n\nexport interface ZonedDateTime {\n readonly kind: \"zoned-date-time\";\n readonly instant: Instant;\n readonly timeZone: TimeZoneId;\n readonly calendar: CalendarId;\n}\n\nexport type FormatDateInput = LocalDate | CalendarDate | Instant | Date;\nexport type DateOrCalendarDate = LocalDate | CalendarDate;\nexport type TimeOrDateTimeOrInstant = LocalTime | LocalDateTime | Instant;\nexport type IntervalInclusivity = \"()\" | \"[]\" | \"[)\" | \"(]\";\n\nexport interface Duration {\n readonly years?: number;\n readonly months?: number;\n readonly weeks?: number;\n readonly days?: number;\n readonly hours?: number;\n readonly minutes?: number;\n readonly seconds?: number;\n readonly milliseconds?: number;\n}\n\nexport interface DateRange<TDate> {\n readonly start: TDate;\n readonly end: TDate;\n readonly startInclusive: boolean;\n readonly endInclusive: boolean;\n}\n\nexport interface CalendarConversionMetadata {\n readonly requestedCalendar: CalendarId;\n readonly resolvedCalendar: CalendarId;\n readonly engine: \"chronera\" | \"runtime-intl\" | \"custom\";\n readonly algorithm: string;\n readonly deterministic: boolean;\n readonly dataVersion?: string;\n readonly validFrom?: LocalDate;\n readonly validTo?: LocalDate;\n}\n\nexport interface CalendarConversionResult {\n readonly value: CalendarDate;\n readonly metadata: CalendarConversionMetadata;\n}\n\nexport interface ChroneraIssue {\n readonly code: ChroneraErrorCode;\n readonly message: string;\n readonly path?: readonly (string | number)[];\n}\n\nexport type SafeParseResult<T> =\n | {\n readonly success: true;\n readonly value: T;\n }\n | {\n readonly success: false;\n readonly error: ChroneraIssue;\n };\n\nexport type Comparison = -1 | 0 | 1;\n\nexport interface CalendarPlugin {\n readonly id: CalendarId;\n readonly algorithm: string;\n readonly deterministic: boolean;\n readonly validFrom: LocalDate;\n readonly validTo: LocalDate;\n toIsoDate(date: CalendarDate): LocalDate;\n fromIsoDate(date: LocalDate): CalendarDate;\n validate(date: CalendarDate): readonly ChroneraIssue[];\n}\n\nexport interface ChroneraConfig {\n readonly locale?: LocaleId;\n readonly calendar?: CalendarId;\n readonly numberingSystem?: NumberingSystemId;\n readonly timeZone?: TimeZoneId;\n readonly calendars?: readonly CalendarPlugin[];\n readonly formatterCacheSize?: number;\n}\n\nexport interface ResolvedChroneraOptions {\n readonly locale: LocaleId;\n readonly calendar: CalendarId;\n readonly numberingSystem?: NumberingSystemId;\n readonly timeZone: TimeZoneId;\n readonly formatterCacheSize: number;\n}\n\nexport interface FormatDateBaseOptions {\n readonly locale?: LocaleId;\n readonly calendar?: CalendarId;\n readonly numberingSystem?: NumberingSystemId;\n readonly timeZone?: TimeZoneId;\n readonly fallback?: \"error\";\n}\n\nexport type FormatDateOptions = FormatDateBaseOptions &\n (\n | {\n readonly style?: \"numeric\" | \"short\" | \"medium\" | \"long\" | \"full\";\n readonly preset?: never;\n }\n | {\n readonly style?: never;\n readonly preset: PresetName;\n }\n );\n\nexport interface FormatTimeOptions {\n readonly locale?: LocaleId;\n readonly numberingSystem?: NumberingSystemId;\n readonly timeZone?: TimeZoneId;\n readonly style?: \"short\" | \"medium\" | \"long\" | \"full\";\n readonly hourCycle?: \"h11\" | \"h12\" | \"h23\" | \"h24\";\n}\n\nexport interface FormatDateTimeOptions extends FormatDateBaseOptions {\n readonly dateStyle?: \"short\" | \"medium\" | \"long\" | \"full\";\n readonly timeStyle?: \"short\" | \"medium\" | \"long\" | \"full\";\n readonly hourCycle?: \"h11\" | \"h12\" | \"h23\" | \"h24\";\n}\n\nexport type FormatDateRangeOptions = FormatDateOptions & {\n readonly collapse?: \"auto\" | \"none\";\n};\n\nexport interface FormatRelativeOptions {\n readonly relativeTo: Instant | LocalDate;\n readonly locale?: LocaleId;\n readonly numeric?: \"always\" | \"auto\";\n readonly unit?:\n \"second\" | \"minute\" | \"hour\" | \"day\" | \"week\" | \"month\" | \"year\";\n readonly timeZone?: TimeZoneId;\n}\n\nexport interface PatternFormatOptions {\n readonly locale?: LocaleId;\n readonly calendar?: CalendarId;\n readonly numberingSystem?: NumberingSystemId;\n readonly timeZone?: TimeZoneId;\n}\n\nexport interface ParseLocalDateOptions {\n readonly pattern?: string;\n readonly locale?: LocaleId;\n readonly calendar?: \"gregory\" | \"iso8601\";\n readonly numberingSystem?: NumberingSystemId;\n}\n\nexport interface ParseInstantOptions {\n readonly excessFractionalSeconds?: \"reject\" | \"truncate\" | \"round\";\n}\n\nexport interface ConvertCalendarOptions {\n readonly fallback?: \"error\";\n}\n\nexport interface CalendarCapabilities {\n readonly calendar: CalendarId;\n readonly maturity:\n \"stable\" | \"experimental\" | \"runtime-dependent\" | \"planned\" | \"unsupported\";\n readonly canFormat: boolean;\n readonly canParse: boolean;\n readonly canConvertFromAbsoluteDate: boolean;\n readonly canConvertToAbsoluteDate: boolean;\n readonly canValidate: boolean;\n readonly canAddYears: boolean;\n readonly canAddMonths: boolean;\n readonly deterministic: boolean;\n readonly algorithm?: string;\n readonly dataVersion?: string;\n readonly validFrom?: LocalDate;\n readonly validTo?: LocalDate;\n}\n\nexport interface RuntimeCapabilities {\n readonly hasDateTimeFormat: boolean;\n readonly hasFormatToParts: boolean;\n readonly hasFormatRange: boolean;\n readonly hasRelativeTimeFormat: boolean;\n readonly hasLocale: boolean;\n readonly hasSupportedValuesOf: boolean;\n readonly hasTemporal: boolean;\n readonly calendars: Readonly<Record<string, boolean>>;\n readonly timeZones: Readonly<Record<string, boolean>>;\n}\n\nexport interface ChroneraInstance {\n formatDate(\n input: FormatDateInput,\n options?: Readonly<FormatDateOptions>,\n ): string;\n parseLocalDate(\n input: string,\n options?: Readonly<ParseLocalDateOptions>,\n ): LocalDate;\n convertCalendarDate(\n source: CalendarDate,\n targetCalendar: CalendarId,\n options?: Readonly<ConvertCalendarOptions>,\n ): CalendarConversionResult;\n resolvedOptions(): ResolvedChroneraOptions;\n}\n\nexport type { IsoWeekFields } from \"./core/iso-week.js\";\n"]}
1
+ {"version":3,"file":"public-types.js","sourceRoot":"","sources":["../src/public-types.ts"],"names":[],"mappings":"","sourcesContent":["import type { DayOfYearFields } from \"./core/day-of-year.js\";\nimport type {\n FiscalFields,\n FiscalOptions,\n QuarterNumber,\n} from \"./core/fiscal.js\";\nimport type { ChroneraErrorCode } from \"./errors/error-codes.js\";\nimport type { PresetName } from \"./format/presets/types.js\";\nimport type { Rfc2822Options } from \"./format/rfc2822.js\";\n\nexport type {\n ChroneraErrorCode,\n DayOfYearFields,\n FiscalFields,\n FiscalOptions,\n PresetName,\n QuarterNumber,\n Rfc2822Options,\n};\n\nexport type BuiltInCalendarId =\n | \"iso8601\"\n | \"gregory\"\n | \"buddhist\"\n | \"islamic\"\n | \"islamic-civil\"\n | \"islamic-tbla\"\n | \"islamic-umalqura\"\n | \"persian\"\n | \"hebrew\"\n | \"japanese\"\n | \"roc\"\n | \"indian\"\n | \"coptic\"\n | \"ethiopic\"\n | \"chinese\"\n | \"dangi\";\n\ntype ExtensibleIdentifier = string & Record<never, never>;\n\nexport type CalendarId = BuiltInCalendarId | ExtensibleIdentifier;\n\nexport type LocaleId = string;\nexport type TimeZoneId = string;\nexport type NumberingSystemId = string;\nexport type EraId = string;\nexport type MonthCode = `M${string}`;\n\nexport interface Instant {\n readonly kind: \"instant\";\n readonly epochMilliseconds: number;\n}\n\nexport interface LocalDate {\n readonly kind: \"local-date\";\n readonly year: number;\n readonly month: number;\n readonly day: number;\n}\n\nexport interface LocalTime {\n readonly kind: \"local-time\";\n readonly hour: number;\n readonly minute: number;\n readonly second: number;\n readonly millisecond: number;\n}\n\nexport interface LocalDateTime {\n readonly kind: \"local-date-time\";\n readonly date: LocalDate;\n readonly time: LocalTime;\n}\n\nexport interface CalendarDate {\n readonly kind: \"calendar-date\";\n readonly calendar: CalendarId;\n readonly era?: EraId;\n readonly eraYear?: number;\n readonly year: number;\n readonly monthCode: MonthCode;\n readonly month?: number;\n readonly day: number;\n}\n\nexport interface ZonedDateTime {\n readonly kind: \"zoned-date-time\";\n readonly instant: Instant;\n readonly timeZone: TimeZoneId;\n readonly calendar: CalendarId;\n}\n\nexport type FormatDateInput = LocalDate | CalendarDate | Instant | Date;\nexport type DateOrCalendarDate = LocalDate | CalendarDate;\nexport type TimeOrDateTimeOrInstant = LocalTime | LocalDateTime | Instant;\nexport type IntervalInclusivity = \"()\" | \"[]\" | \"[)\" | \"(]\";\n\nexport interface Duration {\n readonly years?: number;\n readonly months?: number;\n readonly weeks?: number;\n readonly days?: number;\n readonly hours?: number;\n readonly minutes?: number;\n readonly seconds?: number;\n readonly milliseconds?: number;\n}\n\nexport interface DateRange<TDate> {\n readonly start: TDate;\n readonly end: TDate;\n readonly startInclusive: boolean;\n readonly endInclusive: boolean;\n}\n\nexport interface CalendarConversionMetadata {\n readonly requestedCalendar: CalendarId;\n readonly resolvedCalendar: CalendarId;\n readonly engine: \"chronera\" | \"runtime-intl\" | \"custom\";\n readonly algorithm: string;\n readonly deterministic: boolean;\n readonly dataVersion?: string;\n readonly validFrom?: LocalDate;\n readonly validTo?: LocalDate;\n}\n\nexport interface CalendarConversionResult {\n readonly value: CalendarDate;\n readonly metadata: CalendarConversionMetadata;\n}\n\nexport interface ChroneraIssue {\n readonly code: ChroneraErrorCode;\n readonly message: string;\n readonly path?: readonly (string | number)[];\n}\n\nexport type SafeParseResult<T> =\n | {\n readonly success: true;\n readonly value: T;\n }\n | {\n readonly success: false;\n readonly error: ChroneraIssue;\n };\n\nexport type Comparison = -1 | 0 | 1;\n\nexport interface CalendarPlugin {\n readonly id: CalendarId;\n readonly algorithm: string;\n readonly deterministic: boolean;\n readonly validFrom: LocalDate;\n readonly validTo: LocalDate;\n toIsoDate(date: CalendarDate): LocalDate;\n fromIsoDate(date: LocalDate): CalendarDate;\n validate(date: CalendarDate): readonly ChroneraIssue[];\n}\n\nexport interface ChroneraConfig {\n readonly locale?: LocaleId;\n readonly calendar?: CalendarId;\n readonly numberingSystem?: NumberingSystemId;\n readonly timeZone?: TimeZoneId;\n readonly calendars?: readonly CalendarPlugin[];\n readonly formatterCacheSize?: number;\n}\n\nexport interface ResolvedChroneraOptions {\n readonly locale: LocaleId;\n readonly calendar: CalendarId;\n readonly numberingSystem?: NumberingSystemId;\n readonly timeZone: TimeZoneId;\n readonly formatterCacheSize: number;\n}\n\nexport interface FormatDateBaseOptions {\n readonly locale?: LocaleId;\n readonly calendar?: CalendarId;\n readonly numberingSystem?: NumberingSystemId;\n readonly timeZone?: TimeZoneId;\n readonly fallback?: \"error\";\n}\n\nexport type FormatDateOptions = FormatDateBaseOptions &\n (\n | {\n readonly style?: \"numeric\" | \"short\" | \"medium\" | \"long\" | \"full\";\n readonly preset?: never;\n }\n | {\n readonly style?: never;\n readonly preset: PresetName;\n }\n );\n\nexport interface FormatTimeOptions {\n readonly locale?: LocaleId;\n readonly numberingSystem?: NumberingSystemId;\n readonly timeZone?: TimeZoneId;\n readonly style?: \"short\" | \"medium\" | \"long\" | \"full\";\n readonly hourCycle?: \"h11\" | \"h12\" | \"h23\" | \"h24\";\n}\n\nexport interface FormatDateTimeOptions extends FormatDateBaseOptions {\n readonly dateStyle?: \"short\" | \"medium\" | \"long\" | \"full\";\n readonly timeStyle?: \"short\" | \"medium\" | \"long\" | \"full\";\n readonly hourCycle?: \"h11\" | \"h12\" | \"h23\" | \"h24\";\n}\n\nexport type FormatDateRangeOptions = FormatDateOptions & {\n readonly collapse?: \"auto\" | \"none\";\n};\n\nexport interface FormatRelativeOptions {\n readonly relativeTo: Instant | LocalDate;\n readonly locale?: LocaleId;\n readonly numeric?: \"always\" | \"auto\";\n readonly unit?:\n \"second\" | \"minute\" | \"hour\" | \"day\" | \"week\" | \"month\" | \"year\";\n readonly timeZone?: TimeZoneId;\n}\n\nexport interface PatternFormatOptions {\n readonly locale?: LocaleId;\n readonly calendar?: CalendarId;\n readonly numberingSystem?: NumberingSystemId;\n readonly timeZone?: TimeZoneId;\n}\n\nexport interface ParseLocalDateOptions {\n readonly pattern?: string;\n readonly locale?: LocaleId;\n readonly calendar?: \"gregory\" | \"iso8601\";\n readonly numberingSystem?: NumberingSystemId;\n}\n\nexport interface ParseInstantOptions {\n readonly excessFractionalSeconds?: \"reject\" | \"truncate\" | \"round\";\n}\n\nexport interface ConvertCalendarOptions {\n readonly fallback?: \"error\";\n}\n\nexport interface CalendarCapabilities {\n readonly calendar: CalendarId;\n readonly maturity:\n \"stable\" | \"experimental\" | \"runtime-dependent\" | \"planned\" | \"unsupported\";\n readonly canFormat: boolean;\n readonly canParse: boolean;\n readonly canConvertFromAbsoluteDate: boolean;\n readonly canConvertToAbsoluteDate: boolean;\n readonly canValidate: boolean;\n readonly canAddYears: boolean;\n readonly canAddMonths: boolean;\n readonly deterministic: boolean;\n readonly algorithm?: string;\n readonly dataVersion?: string;\n readonly validFrom?: LocalDate;\n readonly validTo?: LocalDate;\n}\n\nexport interface RuntimeCapabilities {\n readonly hasDateTimeFormat: boolean;\n readonly hasFormatToParts: boolean;\n readonly hasFormatRange: boolean;\n readonly hasRelativeTimeFormat: boolean;\n readonly hasLocale: boolean;\n readonly hasSupportedValuesOf: boolean;\n readonly hasTemporal: boolean;\n readonly calendars: Readonly<Record<string, boolean>>;\n readonly timeZones: Readonly<Record<string, boolean>>;\n}\n\nexport interface ChroneraInstance {\n formatDate(\n input: FormatDateInput,\n options?: Readonly<FormatDateOptions>,\n ): string;\n parseLocalDate(\n input: string,\n options?: Readonly<ParseLocalDateOptions>,\n ): LocalDate;\n convertCalendarDate(\n source: CalendarDate,\n targetCalendar: CalendarId,\n options?: Readonly<ConvertCalendarOptions>,\n ): CalendarConversionResult;\n resolvedOptions(): ResolvedChroneraOptions;\n}\n\nexport type { IsoWeekFields } from \"./core/iso-week.js\";\n\nexport interface FormatInTimeZoneOptions {\n readonly locale?: string;\n readonly numberingSystem?: NumberingSystemId;\n readonly calendar?: CalendarId;\n}\n\nexport type TimeZoneOffsetFormat =\n \"string\" | \"minutes\" | \"totalSeconds\" | \"object\";\n\nexport interface TimeZoneOffsetInfo {\n readonly formatted: string;\n readonly minutes: number;\n readonly totalSeconds: number;\n readonly isDst: boolean;\n}\n\nexport interface SameTimeZoneOptions {\n readonly instant?: Instant | Date;\n readonly mode?: \"canonical\" | \"offset\";\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intech-software/chronera",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "A universal, type-safe date, time, calendar, era, locale, and timezone toolkit for JavaScript and TypeScript.",
5
5
  "keywords": [
6
6
  "date",