@intech-software/chronera 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (282) hide show
  1. package/LICENSE +190 -0
  2. package/README.md +6644 -0
  3. package/dist/calendar/buddhist/adapter.d.ts +2 -0
  4. package/dist/calendar/buddhist/adapter.js +33 -0
  5. package/dist/calendar/buddhist/adapter.js.map +1 -0
  6. package/dist/calendar/buddhist/constants.d.ts +3 -0
  7. package/dist/calendar/buddhist/constants.js +14 -0
  8. package/dist/calendar/buddhist/constants.js.map +1 -0
  9. package/dist/calendar/buddhist/index.d.ts +3 -0
  10. package/dist/calendar/buddhist/index.js +4 -0
  11. package/dist/calendar/buddhist/index.js.map +1 -0
  12. package/dist/calendar/buddhist/validator.d.ts +4 -0
  13. package/dist/calendar/buddhist/validator.js +60 -0
  14. package/dist/calendar/buddhist/validator.js.map +1 -0
  15. package/dist/calendar/gregory/absolute-day.d.ts +12 -0
  16. package/dist/calendar/gregory/absolute-day.js +14 -0
  17. package/dist/calendar/gregory/absolute-day.js.map +1 -0
  18. package/dist/calendar/gregory/adapter.d.ts +3 -0
  19. package/dist/calendar/gregory/adapter.js +93 -0
  20. package/dist/calendar/gregory/adapter.js.map +1 -0
  21. package/dist/calendar/gregory/constants.d.ts +3 -0
  22. package/dist/calendar/gregory/constants.js +18 -0
  23. package/dist/calendar/gregory/constants.js.map +1 -0
  24. package/dist/calendar/gregory/index.d.ts +4 -0
  25. package/dist/calendar/gregory/index.js +5 -0
  26. package/dist/calendar/gregory/index.js.map +1 -0
  27. package/dist/calendar/gregory/leap-year.d.ts +1 -0
  28. package/dist/calendar/gregory/leap-year.js +2 -0
  29. package/dist/calendar/gregory/leap-year.js.map +1 -0
  30. package/dist/calendar/gregory/validator.d.ts +2 -0
  31. package/dist/calendar/gregory/validator.js +45 -0
  32. package/dist/calendar/gregory/validator.js.map +1 -0
  33. package/dist/calendar/hijri/civil-adapter.d.ts +12 -0
  34. package/dist/calendar/hijri/civil-adapter.js +132 -0
  35. package/dist/calendar/hijri/civil-adapter.js.map +1 -0
  36. package/dist/calendar/hijri/index.d.ts +3 -0
  37. package/dist/calendar/hijri/index.js +4 -0
  38. package/dist/calendar/hijri/index.js.map +1 -0
  39. package/dist/calendar/hijri/tabular-adapter.d.ts +4 -0
  40. package/dist/calendar/hijri/tabular-adapter.js +79 -0
  41. package/dist/calendar/hijri/tabular-adapter.js.map +1 -0
  42. package/dist/calendar/hijri/umm-al-qura-adapter.d.ts +4 -0
  43. package/dist/calendar/hijri/umm-al-qura-adapter.js +27 -0
  44. package/dist/calendar/hijri/umm-al-qura-adapter.js.map +1 -0
  45. package/dist/calendar/index.d.ts +13 -0
  46. package/dist/calendar/index.js +12 -0
  47. package/dist/calendar/index.js.map +1 -0
  48. package/dist/calendar/indian/adapter.d.ts +2 -0
  49. package/dist/calendar/indian/adapter.js +66 -0
  50. package/dist/calendar/indian/adapter.js.map +1 -0
  51. package/dist/calendar/indian/constants.d.ts +5 -0
  52. package/dist/calendar/indian/constants.js +43 -0
  53. package/dist/calendar/indian/constants.js.map +1 -0
  54. package/dist/calendar/indian/index.d.ts +3 -0
  55. package/dist/calendar/indian/index.js +4 -0
  56. package/dist/calendar/indian/index.js.map +1 -0
  57. package/dist/calendar/indian/validator.d.ts +6 -0
  58. package/dist/calendar/indian/validator.js +65 -0
  59. package/dist/calendar/indian/validator.js.map +1 -0
  60. package/dist/calendar/japanese/adapter.d.ts +3 -0
  61. package/dist/calendar/japanese/adapter.js +63 -0
  62. package/dist/calendar/japanese/adapter.js.map +1 -0
  63. package/dist/calendar/japanese/constants.d.ts +17 -0
  64. package/dist/calendar/japanese/constants.js +85 -0
  65. package/dist/calendar/japanese/constants.js.map +1 -0
  66. package/dist/calendar/japanese/index.d.ts +3 -0
  67. package/dist/calendar/japanese/index.js +4 -0
  68. package/dist/calendar/japanese/index.js.map +1 -0
  69. package/dist/calendar/japanese/validator.d.ts +5 -0
  70. package/dist/calendar/japanese/validator.js +76 -0
  71. package/dist/calendar/japanese/validator.js.map +1 -0
  72. package/dist/calendar/persian/adapter.d.ts +2 -0
  73. package/dist/calendar/persian/adapter.js +42 -0
  74. package/dist/calendar/persian/adapter.js.map +1 -0
  75. package/dist/calendar/persian/constants.d.ts +5 -0
  76. package/dist/calendar/persian/constants.js +43 -0
  77. package/dist/calendar/persian/constants.js.map +1 -0
  78. package/dist/calendar/persian/index.d.ts +4 -0
  79. package/dist/calendar/persian/index.js +5 -0
  80. package/dist/calendar/persian/index.js.map +1 -0
  81. package/dist/calendar/persian/math.d.ts +24 -0
  82. package/dist/calendar/persian/math.js +109 -0
  83. package/dist/calendar/persian/math.js.map +1 -0
  84. package/dist/calendar/persian/validator.d.ts +4 -0
  85. package/dist/calendar/persian/validator.js +52 -0
  86. package/dist/calendar/persian/validator.js.map +1 -0
  87. package/dist/calendar/registry.d.ts +9 -0
  88. package/dist/calendar/registry.js +119 -0
  89. package/dist/calendar/registry.js.map +1 -0
  90. package/dist/calendar/roc/adapter.d.ts +2 -0
  91. package/dist/calendar/roc/adapter.js +47 -0
  92. package/dist/calendar/roc/adapter.js.map +1 -0
  93. package/dist/calendar/roc/constants.d.ts +6 -0
  94. package/dist/calendar/roc/constants.js +34 -0
  95. package/dist/calendar/roc/constants.js.map +1 -0
  96. package/dist/calendar/roc/index.d.ts +3 -0
  97. package/dist/calendar/roc/index.js +4 -0
  98. package/dist/calendar/roc/index.js.map +1 -0
  99. package/dist/calendar/roc/validator.d.ts +4 -0
  100. package/dist/calendar/roc/validator.js +52 -0
  101. package/dist/calendar/roc/validator.js.map +1 -0
  102. package/dist/calendar/types.d.ts +34 -0
  103. package/dist/calendar/types.js +2 -0
  104. package/dist/calendar/types.js.map +1 -0
  105. package/dist/core/absolute-day.d.ts +8 -0
  106. package/dist/core/absolute-day.js +39 -0
  107. package/dist/core/absolute-day.js.map +1 -0
  108. package/dist/core/calendar-date.d.ts +11 -0
  109. package/dist/core/calendar-date.js +37 -0
  110. package/dist/core/calendar-date.js.map +1 -0
  111. package/dist/core/day-of-year.d.ts +16 -0
  112. package/dist/core/day-of-year.js +30 -0
  113. package/dist/core/day-of-year.js.map +1 -0
  114. package/dist/core/duration.d.ts +2 -0
  115. package/dist/core/duration.js +31 -0
  116. package/dist/core/duration.js.map +1 -0
  117. package/dist/core/fiscal.d.ts +31 -0
  118. package/dist/core/fiscal.js +45 -0
  119. package/dist/core/fiscal.js.map +1 -0
  120. package/dist/core/gregorian-math.d.ts +4 -0
  121. package/dist/core/gregorian-math.js +30 -0
  122. package/dist/core/gregorian-math.js.map +1 -0
  123. package/dist/core/instant.d.ts +6 -0
  124. package/dist/core/instant.js +26 -0
  125. package/dist/core/instant.js.map +1 -0
  126. package/dist/core/integer.d.ts +1 -0
  127. package/dist/core/integer.js +7 -0
  128. package/dist/core/integer.js.map +1 -0
  129. package/dist/core/iso-week.d.ts +19 -0
  130. package/dist/core/iso-week.js +41 -0
  131. package/dist/core/iso-week.js.map +1 -0
  132. package/dist/core/julian-day.d.ts +26 -0
  133. package/dist/core/julian-day.js +35 -0
  134. package/dist/core/julian-day.js.map +1 -0
  135. package/dist/core/local-date-time.d.ts +2 -0
  136. package/dist/core/local-date-time.js +15 -0
  137. package/dist/core/local-date-time.js.map +1 -0
  138. package/dist/core/local-date.d.ts +2 -0
  139. package/dist/core/local-date.js +22 -0
  140. package/dist/core/local-date.js.map +1 -0
  141. package/dist/core/local-time.d.ts +2 -0
  142. package/dist/core/local-time.js +28 -0
  143. package/dist/core/local-time.js.map +1 -0
  144. package/dist/core/range.d.ts +2 -0
  145. package/dist/core/range.js +9 -0
  146. package/dist/core/range.js.map +1 -0
  147. package/dist/create-chronera.d.ts +2 -0
  148. package/dist/create-chronera.js +59 -0
  149. package/dist/create-chronera.js.map +1 -0
  150. package/dist/errors/error-codes.d.ts +1 -0
  151. package/dist/errors/error-codes.js +2 -0
  152. package/dist/errors/error-codes.js.map +1 -0
  153. package/dist/errors/errors.d.ts +16 -0
  154. package/dist/errors/errors.js +22 -0
  155. package/dist/errors/errors.js.map +1 -0
  156. package/dist/errors/index.d.ts +2 -0
  157. package/dist/errors/index.js +2 -0
  158. package/dist/errors/index.js.map +1 -0
  159. package/dist/format/format-date-range.d.ts +2 -0
  160. package/dist/format/format-date-range.js +89 -0
  161. package/dist/format/format-date-range.js.map +1 -0
  162. package/dist/format/format-date-time.d.ts +2 -0
  163. package/dist/format/format-date-time.js +51 -0
  164. package/dist/format/format-date-time.js.map +1 -0
  165. package/dist/format/format-date.d.ts +4 -0
  166. package/dist/format/format-date.js +103 -0
  167. package/dist/format/format-date.js.map +1 -0
  168. package/dist/format/format-pattern.d.ts +4 -0
  169. package/dist/format/format-pattern.js +266 -0
  170. package/dist/format/format-pattern.js.map +1 -0
  171. package/dist/format/format-relative.d.ts +2 -0
  172. package/dist/format/format-relative.js +93 -0
  173. package/dist/format/format-relative.js.map +1 -0
  174. package/dist/format/format-time.d.ts +2 -0
  175. package/dist/format/format-time.js +48 -0
  176. package/dist/format/format-time.js.map +1 -0
  177. package/dist/format/index.d.ts +13 -0
  178. package/dist/format/index.js +12 -0
  179. package/dist/format/index.js.map +1 -0
  180. package/dist/format/pattern-scanner.d.ts +8 -0
  181. package/dist/format/pattern-scanner.js +102 -0
  182. package/dist/format/pattern-scanner.js.map +1 -0
  183. package/dist/format/presets/japanese-official.d.ts +8 -0
  184. package/dist/format/presets/japanese-official.js +39 -0
  185. package/dist/format/presets/japanese-official.js.map +1 -0
  186. package/dist/format/presets/taiwan-official.d.ts +6 -0
  187. package/dist/format/presets/taiwan-official.js +23 -0
  188. package/dist/format/presets/taiwan-official.js.map +1 -0
  189. package/dist/format/presets/thai-official.d.ts +2 -0
  190. package/dist/format/presets/thai-official.js +45 -0
  191. package/dist/format/presets/thai-official.js.map +1 -0
  192. package/dist/format/presets/types.d.ts +2 -0
  193. package/dist/format/presets/types.js +2 -0
  194. package/dist/format/presets/types.js.map +1 -0
  195. package/dist/format/presets/world-locales.d.ts +29 -0
  196. package/dist/format/presets/world-locales.js +330 -0
  197. package/dist/format/presets/world-locales.js.map +1 -0
  198. package/dist/format/resolve-date-input.d.ts +9 -0
  199. package/dist/format/resolve-date-input.js +93 -0
  200. package/dist/format/resolve-date-input.js.map +1 -0
  201. package/dist/format/rfc2822.d.ts +17 -0
  202. package/dist/format/rfc2822.js +59 -0
  203. package/dist/format/rfc2822.js.map +1 -0
  204. package/dist/index.d.ts +19 -0
  205. package/dist/index.js +19 -0
  206. package/dist/index.js.map +1 -0
  207. package/dist/internal/engine.d.ts +8 -0
  208. package/dist/internal/engine.js +11 -0
  209. package/dist/internal/engine.js.map +1 -0
  210. package/dist/locale/numbering-system.d.ts +4 -0
  211. package/dist/locale/numbering-system.js +133 -0
  212. package/dist/locale/numbering-system.js.map +1 -0
  213. package/dist/locale/resolve-locale.d.ts +7 -0
  214. package/dist/locale/resolve-locale.js +51 -0
  215. package/dist/locale/resolve-locale.js.map +1 -0
  216. package/dist/locale/types.d.ts +1 -0
  217. package/dist/locale/types.js +2 -0
  218. package/dist/locale/types.js.map +1 -0
  219. package/dist/operations/arithmetic.d.ts +4 -0
  220. package/dist/operations/arithmetic.js +13 -0
  221. package/dist/operations/arithmetic.js.map +1 -0
  222. package/dist/operations/compare.d.ts +5 -0
  223. package/dist/operations/compare.js +50 -0
  224. package/dist/operations/compare.js.map +1 -0
  225. package/dist/operations/convert-calendar-date.d.ts +4 -0
  226. package/dist/operations/convert-calendar-date.js +54 -0
  227. package/dist/operations/convert-calendar-date.js.map +1 -0
  228. package/dist/operations/day-of-year.d.ts +7 -0
  229. package/dist/operations/day-of-year.js +29 -0
  230. package/dist/operations/day-of-year.js.map +1 -0
  231. package/dist/operations/fiscal.d.ts +5 -0
  232. package/dist/operations/fiscal.js +25 -0
  233. package/dist/operations/fiscal.js.map +1 -0
  234. package/dist/operations/iso-week.d.ts +9 -0
  235. package/dist/operations/iso-week.js +29 -0
  236. package/dist/operations/iso-week.js.map +1 -0
  237. package/dist/operations/julian-day.d.ts +6 -0
  238. package/dist/operations/julian-day.js +37 -0
  239. package/dist/operations/julian-day.js.map +1 -0
  240. package/dist/operations/validate.d.ts +10 -0
  241. package/dist/operations/validate.js +55 -0
  242. package/dist/operations/validate.js.map +1 -0
  243. package/dist/parse/field-normalizer.d.ts +1 -0
  244. package/dist/parse/field-normalizer.js +5 -0
  245. package/dist/parse/field-normalizer.js.map +1 -0
  246. package/dist/parse/index.d.ts +4 -0
  247. package/dist/parse/index.js +4 -0
  248. package/dist/parse/index.js.map +1 -0
  249. package/dist/parse/parse-instant.d.ts +2 -0
  250. package/dist/parse/parse-instant.js +97 -0
  251. package/dist/parse/parse-instant.js.map +1 -0
  252. package/dist/parse/parse-local-date.d.ts +2 -0
  253. package/dist/parse/parse-local-date.js +31 -0
  254. package/dist/parse/parse-local-date.js.map +1 -0
  255. package/dist/parse/pattern-parser.d.ts +2 -0
  256. package/dist/parse/pattern-parser.js +150 -0
  257. package/dist/parse/pattern-parser.js.map +1 -0
  258. package/dist/parse/safe-parse.d.ts +3 -0
  259. package/dist/parse/safe-parse.js +46 -0
  260. package/dist/parse/safe-parse.js.map +1 -0
  261. package/dist/public-types.d.ts +209 -0
  262. package/dist/public-types.js +2 -0
  263. package/dist/public-types.js.map +1 -0
  264. package/dist/runtime/bounded-lru.d.ts +11 -0
  265. package/dist/runtime/bounded-lru.js +42 -0
  266. package/dist/runtime/bounded-lru.js.map +1 -0
  267. package/dist/runtime/capabilities.d.ts +5 -0
  268. package/dist/runtime/capabilities.js +61 -0
  269. package/dist/runtime/capabilities.js.map +1 -0
  270. package/dist/runtime/intl-date-time.d.ts +11 -0
  271. package/dist/runtime/intl-date-time.js +38 -0
  272. package/dist/runtime/intl-date-time.js.map +1 -0
  273. package/dist/runtime/intl-number.d.ts +7 -0
  274. package/dist/runtime/intl-number.js +35 -0
  275. package/dist/runtime/intl-number.js.map +1 -0
  276. package/dist/runtime/intl-relative-time.d.ts +7 -0
  277. package/dist/runtime/intl-relative-time.js +35 -0
  278. package/dist/runtime/intl-relative-time.js.map +1 -0
  279. package/dist/runtime/timezone.d.ts +14 -0
  280. package/dist/runtime/timezone.js +95 -0
  281. package/dist/runtime/timezone.js.map +1 -0
  282. package/package.json +155 -0
@@ -0,0 +1,26 @@
1
+ import { ChroneraError } from "../errors/errors.js";
2
+ import { requireInteger } from "./integer.js";
3
+ export const MIN_EPOCH_MILLISECONDS = -62135596800000;
4
+ export const MAX_EPOCH_MILLISECONDS = 253402300799999;
5
+ export function instantFromEpochMilliseconds(epochMilliseconds) {
6
+ requireInteger("epochMilliseconds", epochMilliseconds);
7
+ if (epochMilliseconds < MIN_EPOCH_MILLISECONDS ||
8
+ epochMilliseconds > MAX_EPOCH_MILLISECONDS) {
9
+ throw new ChroneraError("CHRONERA_OUT_OF_RANGE", `Epoch milliseconds must be between ${MIN_EPOCH_MILLISECONDS} and ${MAX_EPOCH_MILLISECONDS}; received ${epochMilliseconds}.`);
10
+ }
11
+ return {
12
+ kind: "instant",
13
+ epochMilliseconds,
14
+ };
15
+ }
16
+ export function instantFromDate(date) {
17
+ if (!(date instanceof Date) || Number.isNaN(date.getTime())) {
18
+ throw new ChroneraError("CHRONERA_INVALID_INSTANT", "Expected a valid Date object.");
19
+ }
20
+ return instantFromEpochMilliseconds(date.getTime());
21
+ }
22
+ export function instantFromEpochSeconds(epochSeconds) {
23
+ requireInteger("epochSeconds", epochSeconds);
24
+ return instantFromEpochMilliseconds(epochSeconds * 1000);
25
+ }
26
+ //# sourceMappingURL=instant.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"instant.js","sourceRoot":"","sources":["../../src/core/instant.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAI9C,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,cAAc,CAAC;AACtD,MAAM,CAAC,MAAM,sBAAsB,GAAG,eAAe,CAAC;AAEtD,MAAM,UAAU,4BAA4B,CAC1C,iBAAyB;IAEzB,cAAc,CAAC,mBAAmB,EAAE,iBAAiB,CAAC,CAAC;IAEvD,IACE,iBAAiB,GAAG,sBAAsB;QAC1C,iBAAiB,GAAG,sBAAsB,EAC1C,CAAC;QACD,MAAM,IAAI,aAAa,CACrB,uBAAuB,EACvB,sCAAsC,sBAAsB,QAAQ,sBAAsB,cAAc,iBAAiB,GAAG,CAC7H,CAAC;IACJ,CAAC;IAED,OAAO;QACL,IAAI,EAAE,SAAS;QACf,iBAAiB;KAClB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,IAAU;IACxC,IAAI,CAAC,CAAC,IAAI,YAAY,IAAI,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;QAC5D,MAAM,IAAI,aAAa,CACrB,0BAA0B,EAC1B,+BAA+B,CAChC,CAAC;IACJ,CAAC;IAED,OAAO,4BAA4B,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;AACtD,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,YAAoB;IAC1D,cAAc,CAAC,cAAc,EAAE,YAAY,CAAC,CAAC;IAC7C,OAAO,4BAA4B,CAAC,YAAY,GAAG,IAAI,CAAC,CAAC;AAC3D,CAAC","sourcesContent":["import { ChroneraError } from \"../errors/errors.js\";\nimport { requireInteger } from \"./integer.js\";\n\nimport type { Instant } from \"../public-types.js\";\n\nexport const MIN_EPOCH_MILLISECONDS = -62135596800000;\nexport const MAX_EPOCH_MILLISECONDS = 253402300799999;\n\nexport function instantFromEpochMilliseconds(\n epochMilliseconds: number,\n): Instant {\n requireInteger(\"epochMilliseconds\", epochMilliseconds);\n\n if (\n epochMilliseconds < MIN_EPOCH_MILLISECONDS ||\n epochMilliseconds > MAX_EPOCH_MILLISECONDS\n ) {\n throw new ChroneraError(\n \"CHRONERA_OUT_OF_RANGE\",\n `Epoch milliseconds must be between ${MIN_EPOCH_MILLISECONDS} and ${MAX_EPOCH_MILLISECONDS}; received ${epochMilliseconds}.`,\n );\n }\n\n return {\n kind: \"instant\",\n epochMilliseconds,\n };\n}\n\nexport function instantFromDate(date: Date): Instant {\n if (!(date instanceof Date) || Number.isNaN(date.getTime())) {\n throw new ChroneraError(\n \"CHRONERA_INVALID_INSTANT\",\n \"Expected a valid Date object.\",\n );\n }\n\n return instantFromEpochMilliseconds(date.getTime());\n}\n\nexport function instantFromEpochSeconds(epochSeconds: number): Instant {\n requireInteger(\"epochSeconds\", epochSeconds);\n return instantFromEpochMilliseconds(epochSeconds * 1000);\n}\n"]}
@@ -0,0 +1 @@
1
+ export declare function requireInteger(name: string, value: unknown): asserts value is number;
@@ -0,0 +1,7 @@
1
+ import { ChroneraError } from "../errors/errors.js";
2
+ export function requireInteger(name, value) {
3
+ if (typeof value !== "number" || !Number.isSafeInteger(value)) {
4
+ throw new ChroneraError("CHRONERA_INVALID_DATE", `Expected ${name} to be a safe integer; received ${String(value)}.`);
5
+ }
6
+ }
7
+ //# sourceMappingURL=integer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"integer.js","sourceRoot":"","sources":["../../src/core/integer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,MAAM,UAAU,cAAc,CAC5B,IAAY,EACZ,KAAc;IAEd,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC;QAC9D,MAAM,IAAI,aAAa,CACrB,uBAAuB,EACvB,YAAY,IAAI,mCAAmC,MAAM,CAAC,KAAK,CAAC,GAAG,CACpE,CAAC;IACJ,CAAC;AACH,CAAC","sourcesContent":["import { ChroneraError } from \"../errors/errors.js\";\n\nexport function requireInteger(\n name: string,\n value: unknown,\n): asserts value is number {\n if (typeof value !== \"number\" || !Number.isSafeInteger(value)) {\n throw new ChroneraError(\n \"CHRONERA_INVALID_DATE\",\n `Expected ${name} to be a safe integer; received ${String(value)}.`,\n );\n }\n}\n"]}
@@ -0,0 +1,19 @@
1
+ export interface IsoWeekFields {
2
+ readonly weekYear: number;
3
+ readonly weekNumber: number;
4
+ readonly dayOfWeek: number;
5
+ }
6
+ /**
7
+ * Computes ISO 8601 day of week from absolute day.
8
+ * Monday = 1, Tuesday = 2, ..., Sunday = 7.
9
+ * 1970-01-01 (absolute day 0) was Thursday (4).
10
+ */
11
+ export declare function getIsoDayOfWeek(absoluteDay: number): number;
12
+ /**
13
+ * Computes ISO 8601 week fields (weekYear, weekNumber, dayOfWeek) from Gregorian fields.
14
+ */
15
+ export declare function getIsoWeekFromAbsoluteDay(absoluteDay: number): IsoWeekFields;
16
+ /**
17
+ * Formats ISO 8601 week string: `YYYY-Www-D` or `YYYY-Www`.
18
+ */
19
+ export declare function formatIsoWeekString(fields: IsoWeekFields, includeDayOfWeek?: boolean): string;
@@ -0,0 +1,41 @@
1
+ import { absoluteDayFromGregorianFields, gregorianFieldsFromAbsoluteDay, } from "./absolute-day.js";
2
+ /**
3
+ * Computes ISO 8601 day of week from absolute day.
4
+ * Monday = 1, Tuesday = 2, ..., Sunday = 7.
5
+ * 1970-01-01 (absolute day 0) was Thursday (4).
6
+ */
7
+ export function getIsoDayOfWeek(absoluteDay) {
8
+ return ((((absoluteDay + 3) % 7) + 7) % 7) + 1;
9
+ }
10
+ /**
11
+ * Computes ISO 8601 week fields (weekYear, weekNumber, dayOfWeek) from Gregorian fields.
12
+ */
13
+ export function getIsoWeekFromAbsoluteDay(absoluteDay) {
14
+ const dayOfWeek = getIsoDayOfWeek(absoluteDay);
15
+ // Find Thursday of current week
16
+ const thursdayAbsoluteDay = absoluteDay + (4 - dayOfWeek);
17
+ const thursdayFields = gregorianFieldsFromAbsoluteDay(thursdayAbsoluteDay);
18
+ const weekYear = thursdayFields.year;
19
+ // Find first Thursday of weekYear (which is the Thursday of the week containing Jan 4)
20
+ const jan4AbsoluteDay = absoluteDayFromGregorianFields(weekYear, 1, 4);
21
+ const jan4DayOfWeek = getIsoDayOfWeek(jan4AbsoluteDay);
22
+ const firstThursdayAbsoluteDay = jan4AbsoluteDay + (4 - jan4DayOfWeek);
23
+ const weekNumber = 1 + Math.floor((thursdayAbsoluteDay - firstThursdayAbsoluteDay) / 7);
24
+ return {
25
+ weekYear,
26
+ weekNumber,
27
+ dayOfWeek,
28
+ };
29
+ }
30
+ /**
31
+ * Formats ISO 8601 week string: `YYYY-Www-D` or `YYYY-Www`.
32
+ */
33
+ export function formatIsoWeekString(fields, includeDayOfWeek = true) {
34
+ const yearStr = String(fields.weekYear).padStart(4, "0");
35
+ const weekStr = String(fields.weekNumber).padStart(2, "0");
36
+ if (!includeDayOfWeek) {
37
+ return `${yearStr}-W${weekStr}`;
38
+ }
39
+ return `${yearStr}-W${weekStr}-${fields.dayOfWeek}`;
40
+ }
41
+ //# sourceMappingURL=iso-week.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"iso-week.js","sourceRoot":"","sources":["../../src/core/iso-week.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,8BAA8B,EAC9B,8BAA8B,GAC/B,MAAM,mBAAmB,CAAC;AAQ3B;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,WAAmB;IACjD,OAAO,CAAC,CAAC,CAAC,CAAC,WAAW,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;AACjD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,yBAAyB,CAAC,WAAmB;IAC3D,MAAM,SAAS,GAAG,eAAe,CAAC,WAAW,CAAC,CAAC;IAC/C,gCAAgC;IAChC,MAAM,mBAAmB,GAAG,WAAW,GAAG,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;IAC1D,MAAM,cAAc,GAAG,8BAA8B,CAAC,mBAAmB,CAAC,CAAC;IAC3E,MAAM,QAAQ,GAAG,cAAc,CAAC,IAAI,CAAC;IAErC,uFAAuF;IACvF,MAAM,eAAe,GAAG,8BAA8B,CAAC,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IACvE,MAAM,aAAa,GAAG,eAAe,CAAC,eAAe,CAAC,CAAC;IACvD,MAAM,wBAAwB,GAAG,eAAe,GAAG,CAAC,CAAC,GAAG,aAAa,CAAC,CAAC;IAEvE,MAAM,UAAU,GACd,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,mBAAmB,GAAG,wBAAwB,CAAC,GAAG,CAAC,CAAC,CAAC;IAEvE,OAAO;QACL,QAAQ;QACR,UAAU;QACV,SAAS;KACV,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB,CACjC,MAAqB,EACrB,gBAAgB,GAAG,IAAI;IAEvB,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACzD,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAC3D,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACtB,OAAO,GAAG,OAAO,KAAK,OAAO,EAAE,CAAC;IAClC,CAAC;IACD,OAAO,GAAG,OAAO,KAAK,OAAO,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;AACtD,CAAC","sourcesContent":["import {\n absoluteDayFromGregorianFields,\n gregorianFieldsFromAbsoluteDay,\n} from \"./absolute-day.js\";\n\nexport interface IsoWeekFields {\n readonly weekYear: number;\n readonly weekNumber: number;\n readonly dayOfWeek: number; // 1 (Monday) to 7 (Sunday)\n}\n\n/**\n * Computes ISO 8601 day of week from absolute day.\n * Monday = 1, Tuesday = 2, ..., Sunday = 7.\n * 1970-01-01 (absolute day 0) was Thursday (4).\n */\nexport function getIsoDayOfWeek(absoluteDay: number): number {\n return ((((absoluteDay + 3) % 7) + 7) % 7) + 1;\n}\n\n/**\n * Computes ISO 8601 week fields (weekYear, weekNumber, dayOfWeek) from Gregorian fields.\n */\nexport function getIsoWeekFromAbsoluteDay(absoluteDay: number): IsoWeekFields {\n const dayOfWeek = getIsoDayOfWeek(absoluteDay);\n // Find Thursday of current week\n const thursdayAbsoluteDay = absoluteDay + (4 - dayOfWeek);\n const thursdayFields = gregorianFieldsFromAbsoluteDay(thursdayAbsoluteDay);\n const weekYear = thursdayFields.year;\n\n // Find first Thursday of weekYear (which is the Thursday of the week containing Jan 4)\n const jan4AbsoluteDay = absoluteDayFromGregorianFields(weekYear, 1, 4);\n const jan4DayOfWeek = getIsoDayOfWeek(jan4AbsoluteDay);\n const firstThursdayAbsoluteDay = jan4AbsoluteDay + (4 - jan4DayOfWeek);\n\n const weekNumber =\n 1 + Math.floor((thursdayAbsoluteDay - firstThursdayAbsoluteDay) / 7);\n\n return {\n weekYear,\n weekNumber,\n dayOfWeek,\n };\n}\n\n/**\n * Formats ISO 8601 week string: `YYYY-Www-D` or `YYYY-Www`.\n */\nexport function formatIsoWeekString(\n fields: IsoWeekFields,\n includeDayOfWeek = true,\n): string {\n const yearStr = String(fields.weekYear).padStart(4, \"0\");\n const weekStr = String(fields.weekNumber).padStart(2, \"0\");\n if (!includeDayOfWeek) {\n return `${yearStr}-W${weekStr}`;\n }\n return `${yearStr}-W${weekStr}-${fields.dayOfWeek}`;\n}\n"]}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * International Astronomical Union (IAU) / NASA standard conversions
3
+ * for Julian Day Number (JDN) and Modified Julian Day (MJD).
4
+ *
5
+ * Benchmark reference points:
6
+ * - 1970-01-01 (Absolute Day 0) = JDN 2440588, MJD 40587
7
+ * - 2000-01-01 (J2000.0 Epoch) = JDN 2451545, MJD 51544
8
+ */
9
+ export declare const JDN_EPOCH_OFFSET = 2440588;
10
+ export declare const MJD_EPOCH_OFFSET = 40587;
11
+ /**
12
+ * Converts a Howard Hinnant absolute civil day to an astronomical Julian Day Number (JDN).
13
+ */
14
+ export declare function toJulianDayNumber(absoluteDay: number): number;
15
+ /**
16
+ * Converts an astronomical Julian Day Number (JDN) to a Howard Hinnant absolute civil day.
17
+ */
18
+ export declare function fromJulianDayNumber(jdn: number): number;
19
+ /**
20
+ * Converts a Howard Hinnant absolute civil day to a Modified Julian Day (MJD).
21
+ */
22
+ export declare function toModifiedJulianDay(absoluteDay: number): number;
23
+ /**
24
+ * Converts a Modified Julian Day (MJD) to a Howard Hinnant absolute civil day.
25
+ */
26
+ export declare function fromModifiedJulianDay(mjd: number): number;
@@ -0,0 +1,35 @@
1
+ /**
2
+ * International Astronomical Union (IAU) / NASA standard conversions
3
+ * for Julian Day Number (JDN) and Modified Julian Day (MJD).
4
+ *
5
+ * Benchmark reference points:
6
+ * - 1970-01-01 (Absolute Day 0) = JDN 2440588, MJD 40587
7
+ * - 2000-01-01 (J2000.0 Epoch) = JDN 2451545, MJD 51544
8
+ */
9
+ export const JDN_EPOCH_OFFSET = 2440588;
10
+ export const MJD_EPOCH_OFFSET = 40587;
11
+ /**
12
+ * Converts a Howard Hinnant absolute civil day to an astronomical Julian Day Number (JDN).
13
+ */
14
+ export function toJulianDayNumber(absoluteDay) {
15
+ return absoluteDay + JDN_EPOCH_OFFSET;
16
+ }
17
+ /**
18
+ * Converts an astronomical Julian Day Number (JDN) to a Howard Hinnant absolute civil day.
19
+ */
20
+ export function fromJulianDayNumber(jdn) {
21
+ return jdn - JDN_EPOCH_OFFSET;
22
+ }
23
+ /**
24
+ * Converts a Howard Hinnant absolute civil day to a Modified Julian Day (MJD).
25
+ */
26
+ export function toModifiedJulianDay(absoluteDay) {
27
+ return absoluteDay + MJD_EPOCH_OFFSET;
28
+ }
29
+ /**
30
+ * Converts a Modified Julian Day (MJD) to a Howard Hinnant absolute civil day.
31
+ */
32
+ export function fromModifiedJulianDay(mjd) {
33
+ return mjd - MJD_EPOCH_OFFSET;
34
+ }
35
+ //# sourceMappingURL=julian-day.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"julian-day.js","sourceRoot":"","sources":["../../src/core/julian-day.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,CAAC,MAAM,gBAAgB,GAAG,OAAO,CAAC;AACxC,MAAM,CAAC,MAAM,gBAAgB,GAAG,KAAK,CAAC;AAEtC;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,WAAmB;IACnD,OAAO,WAAW,GAAG,gBAAgB,CAAC;AACxC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAAC,GAAW;IAC7C,OAAO,GAAG,GAAG,gBAAgB,CAAC;AAChC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAAC,WAAmB;IACrD,OAAO,WAAW,GAAG,gBAAgB,CAAC;AACxC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,qBAAqB,CAAC,GAAW;IAC/C,OAAO,GAAG,GAAG,gBAAgB,CAAC;AAChC,CAAC","sourcesContent":["/**\n * International Astronomical Union (IAU) / NASA standard conversions\n * for Julian Day Number (JDN) and Modified Julian Day (MJD).\n *\n * Benchmark reference points:\n * - 1970-01-01 (Absolute Day 0) = JDN 2440588, MJD 40587\n * - 2000-01-01 (J2000.0 Epoch) = JDN 2451545, MJD 51544\n */\n\nexport const JDN_EPOCH_OFFSET = 2440588;\nexport const MJD_EPOCH_OFFSET = 40587;\n\n/**\n * Converts a Howard Hinnant absolute civil day to an astronomical Julian Day Number (JDN).\n */\nexport function toJulianDayNumber(absoluteDay: number): number {\n return absoluteDay + JDN_EPOCH_OFFSET;\n}\n\n/**\n * Converts an astronomical Julian Day Number (JDN) to a Howard Hinnant absolute civil day.\n */\nexport function fromJulianDayNumber(jdn: number): number {\n return jdn - JDN_EPOCH_OFFSET;\n}\n\n/**\n * Converts a Howard Hinnant absolute civil day to a Modified Julian Day (MJD).\n */\nexport function toModifiedJulianDay(absoluteDay: number): number {\n return absoluteDay + MJD_EPOCH_OFFSET;\n}\n\n/**\n * Converts a Modified Julian Day (MJD) to a Howard Hinnant absolute civil day.\n */\nexport function fromModifiedJulianDay(mjd: number): number {\n return mjd - MJD_EPOCH_OFFSET;\n}\n"]}
@@ -0,0 +1,2 @@
1
+ import type { LocalDate, LocalDateTime, LocalTime } from "../public-types.js";
2
+ export declare function localDateTime(date: LocalDate, time: LocalTime): LocalDateTime;
@@ -0,0 +1,15 @@
1
+ import { ChroneraError } from "../errors/errors.js";
2
+ export function localDateTime(date, time) {
3
+ if (!date || date.kind !== "local-date") {
4
+ throw new ChroneraError("CHRONERA_INVALID_DATE", "Expected a valid LocalDate.");
5
+ }
6
+ if (!time || time.kind !== "local-time") {
7
+ throw new ChroneraError("CHRONERA_INVALID_TIME", "Expected a valid LocalTime.");
8
+ }
9
+ return {
10
+ kind: "local-date-time",
11
+ date,
12
+ time,
13
+ };
14
+ }
15
+ //# sourceMappingURL=local-date-time.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-date-time.js","sourceRoot":"","sources":["../../src/core/local-date-time.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAIpD,MAAM,UAAU,aAAa,CAAC,IAAe,EAAE,IAAe;IAC5D,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;QACxC,MAAM,IAAI,aAAa,CACrB,uBAAuB,EACvB,6BAA6B,CAC9B,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;QACxC,MAAM,IAAI,aAAa,CACrB,uBAAuB,EACvB,6BAA6B,CAC9B,CAAC;IACJ,CAAC;IAED,OAAO;QACL,IAAI,EAAE,iBAAiB;QACvB,IAAI;QACJ,IAAI;KACL,CAAC;AACJ,CAAC","sourcesContent":["import { ChroneraError } from \"../errors/errors.js\";\n\nimport type { LocalDate, LocalDateTime, LocalTime } from \"../public-types.js\";\n\nexport function localDateTime(date: LocalDate, time: LocalTime): LocalDateTime {\n if (!date || date.kind !== \"local-date\") {\n throw new ChroneraError(\n \"CHRONERA_INVALID_DATE\",\n \"Expected a valid LocalDate.\",\n );\n }\n\n if (!time || time.kind !== \"local-time\") {\n throw new ChroneraError(\n \"CHRONERA_INVALID_TIME\",\n \"Expected a valid LocalTime.\",\n );\n }\n\n return {\n kind: \"local-date-time\",\n date,\n time,\n };\n}\n"]}
@@ -0,0 +1,2 @@
1
+ import type { LocalDate } from "../public-types.js";
2
+ export declare function localDate(year: number, month: number, day: number): LocalDate;
@@ -0,0 +1,22 @@
1
+ import { ChroneraError } from "../errors/errors.js";
2
+ import { daysInGregorianMonth } from "./gregorian-math.js";
3
+ import { requireInteger } from "./integer.js";
4
+ export function localDate(year, month, day) {
5
+ requireInteger("year", year);
6
+ requireInteger("month", month);
7
+ requireInteger("day", day);
8
+ if (year < 1 || year > 9999) {
9
+ throw new ChroneraError("CHRONERA_OUT_OF_RANGE", `Gregorian year must be between 1 and 9999; received ${year}.`);
10
+ }
11
+ const maximumDay = daysInGregorianMonth(year, month);
12
+ if (day < 1 || day > maximumDay) {
13
+ throw new ChroneraError("CHRONERA_INVALID_DATE", `Invalid day ${day} for Gregorian month ${month} in year ${year}.`);
14
+ }
15
+ return {
16
+ kind: "local-date",
17
+ year,
18
+ month,
19
+ day,
20
+ };
21
+ }
22
+ //# sourceMappingURL=local-date.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-date.js","sourceRoot":"","sources":["../../src/core/local-date.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAI9C,MAAM,UAAU,SAAS,CAAC,IAAY,EAAE,KAAa,EAAE,GAAW;IAChE,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAC7B,cAAc,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAC/B,cAAc,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAE3B,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,IAAI,EAAE,CAAC;QAC5B,MAAM,IAAI,aAAa,CACrB,uBAAuB,EACvB,uDAAuD,IAAI,GAAG,CAC/D,CAAC;IACJ,CAAC;IAED,MAAM,UAAU,GAAG,oBAAoB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAErD,IAAI,GAAG,GAAG,CAAC,IAAI,GAAG,GAAG,UAAU,EAAE,CAAC;QAChC,MAAM,IAAI,aAAa,CACrB,uBAAuB,EACvB,eAAe,GAAG,wBAAwB,KAAK,YAAY,IAAI,GAAG,CACnE,CAAC;IACJ,CAAC;IAED,OAAO;QACL,IAAI,EAAE,YAAY;QAClB,IAAI;QACJ,KAAK;QACL,GAAG;KACJ,CAAC;AACJ,CAAC","sourcesContent":["import { ChroneraError } from \"../errors/errors.js\";\nimport { daysInGregorianMonth } from \"./gregorian-math.js\";\nimport { requireInteger } from \"./integer.js\";\n\nimport type { LocalDate } from \"../public-types.js\";\n\nexport function localDate(year: number, month: number, day: number): LocalDate {\n requireInteger(\"year\", year);\n requireInteger(\"month\", month);\n requireInteger(\"day\", day);\n\n if (year < 1 || year > 9999) {\n throw new ChroneraError(\n \"CHRONERA_OUT_OF_RANGE\",\n `Gregorian year must be between 1 and 9999; received ${year}.`,\n );\n }\n\n const maximumDay = daysInGregorianMonth(year, month);\n\n if (day < 1 || day > maximumDay) {\n throw new ChroneraError(\n \"CHRONERA_INVALID_DATE\",\n `Invalid day ${day} for Gregorian month ${month} in year ${year}.`,\n );\n }\n\n return {\n kind: \"local-date\",\n year,\n month,\n day,\n };\n}\n"]}
@@ -0,0 +1,2 @@
1
+ import type { LocalTime } from "../public-types.js";
2
+ export declare function localTime(hour: number, minute: number, second?: number, millisecond?: number): LocalTime;
@@ -0,0 +1,28 @@
1
+ import { ChroneraError } from "../errors/errors.js";
2
+ import { requireInteger } from "./integer.js";
3
+ export function localTime(hour, minute, second = 0, millisecond = 0) {
4
+ requireInteger("hour", hour);
5
+ requireInteger("minute", minute);
6
+ requireInteger("second", second);
7
+ requireInteger("millisecond", millisecond);
8
+ if (hour < 0 || hour > 23) {
9
+ throw new ChroneraError("CHRONERA_INVALID_TIME", `Hour must be between 0 and 23; received ${hour}.`);
10
+ }
11
+ if (minute < 0 || minute > 59) {
12
+ throw new ChroneraError("CHRONERA_INVALID_TIME", `Minute must be between 0 and 59; received ${minute}.`);
13
+ }
14
+ if (second < 0 || second > 59) {
15
+ throw new ChroneraError("CHRONERA_INVALID_TIME", `Second must be between 0 and 59; received ${second}.`);
16
+ }
17
+ if (millisecond < 0 || millisecond > 999) {
18
+ throw new ChroneraError("CHRONERA_INVALID_TIME", `Millisecond must be between 0 and 999; received ${millisecond}.`);
19
+ }
20
+ return {
21
+ kind: "local-time",
22
+ hour,
23
+ minute,
24
+ second,
25
+ millisecond,
26
+ };
27
+ }
28
+ //# sourceMappingURL=local-time.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-time.js","sourceRoot":"","sources":["../../src/core/local-time.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAI9C,MAAM,UAAU,SAAS,CACvB,IAAY,EACZ,MAAc,EACd,SAAiB,CAAC,EAClB,cAAsB,CAAC;IAEvB,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAC7B,cAAc,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACjC,cAAc,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACjC,cAAc,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC;IAE3C,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,EAAE,EAAE,CAAC;QAC1B,MAAM,IAAI,aAAa,CACrB,uBAAuB,EACvB,2CAA2C,IAAI,GAAG,CACnD,CAAC;IACJ,CAAC;IAED,IAAI,MAAM,GAAG,CAAC,IAAI,MAAM,GAAG,EAAE,EAAE,CAAC;QAC9B,MAAM,IAAI,aAAa,CACrB,uBAAuB,EACvB,6CAA6C,MAAM,GAAG,CACvD,CAAC;IACJ,CAAC;IAED,IAAI,MAAM,GAAG,CAAC,IAAI,MAAM,GAAG,EAAE,EAAE,CAAC;QAC9B,MAAM,IAAI,aAAa,CACrB,uBAAuB,EACvB,6CAA6C,MAAM,GAAG,CACvD,CAAC;IACJ,CAAC;IAED,IAAI,WAAW,GAAG,CAAC,IAAI,WAAW,GAAG,GAAG,EAAE,CAAC;QACzC,MAAM,IAAI,aAAa,CACrB,uBAAuB,EACvB,mDAAmD,WAAW,GAAG,CAClE,CAAC;IACJ,CAAC;IAED,OAAO;QACL,IAAI,EAAE,YAAY;QAClB,IAAI;QACJ,MAAM;QACN,MAAM;QACN,WAAW;KACZ,CAAC;AACJ,CAAC","sourcesContent":["import { ChroneraError } from \"../errors/errors.js\";\nimport { requireInteger } from \"./integer.js\";\n\nimport type { LocalTime } from \"../public-types.js\";\n\nexport function localTime(\n hour: number,\n minute: number,\n second: number = 0,\n millisecond: number = 0,\n): LocalTime {\n requireInteger(\"hour\", hour);\n requireInteger(\"minute\", minute);\n requireInteger(\"second\", second);\n requireInteger(\"millisecond\", millisecond);\n\n if (hour < 0 || hour > 23) {\n throw new ChroneraError(\n \"CHRONERA_INVALID_TIME\",\n `Hour must be between 0 and 23; received ${hour}.`,\n );\n }\n\n if (minute < 0 || minute > 59) {\n throw new ChroneraError(\n \"CHRONERA_INVALID_TIME\",\n `Minute must be between 0 and 59; received ${minute}.`,\n );\n }\n\n if (second < 0 || second > 59) {\n throw new ChroneraError(\n \"CHRONERA_INVALID_TIME\",\n `Second must be between 0 and 59; received ${second}.`,\n );\n }\n\n if (millisecond < 0 || millisecond > 999) {\n throw new ChroneraError(\n \"CHRONERA_INVALID_TIME\",\n `Millisecond must be between 0 and 999; received ${millisecond}.`,\n );\n }\n\n return {\n kind: \"local-time\",\n hour,\n minute,\n second,\n millisecond,\n };\n}\n"]}
@@ -0,0 +1,2 @@
1
+ import type { DateRange } from "../public-types.js";
2
+ export declare function dateRange<TDate>(start: TDate, end: TDate, startInclusive?: boolean, endInclusive?: boolean): DateRange<TDate>;
@@ -0,0 +1,9 @@
1
+ export function dateRange(start, end, startInclusive = true, endInclusive = true) {
2
+ return {
3
+ start,
4
+ end,
5
+ startInclusive,
6
+ endInclusive,
7
+ };
8
+ }
9
+ //# sourceMappingURL=range.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"range.js","sourceRoot":"","sources":["../../src/core/range.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,SAAS,CACvB,KAAY,EACZ,GAAU,EACV,iBAA0B,IAAI,EAC9B,eAAwB,IAAI;IAE5B,OAAO;QACL,KAAK;QACL,GAAG;QACH,cAAc;QACd,YAAY;KACb,CAAC;AACJ,CAAC","sourcesContent":["import type { DateRange } from \"../public-types.js\";\n\nexport function dateRange<TDate>(\n start: TDate,\n end: TDate,\n startInclusive: boolean = true,\n endInclusive: boolean = true,\n): DateRange<TDate> {\n return {\n start,\n end,\n startInclusive,\n endInclusive,\n };\n}\n"]}
@@ -0,0 +1,2 @@
1
+ import type { ChroneraConfig, ChroneraInstance } from "./public-types.js";
2
+ export declare function createChronera(config?: Readonly<ChroneraConfig>): ChroneraInstance;
@@ -0,0 +1,59 @@
1
+ import { ChroneraEngine } from "./internal/engine.js";
2
+ import { formatDateWithRegistry } from "./format/format-date.js";
3
+ import { parseLocalDate } from "./parse/parse-local-date.js";
4
+ import { convertCalendarDateWithRegistry } from "./operations/convert-calendar-date.js";
5
+ export function createChronera(config) {
6
+ const engine = new ChroneraEngine(config);
7
+ const defaultLocale = config?.locale ?? "en-US";
8
+ const defaultCalendar = config?.calendar ?? "gregory";
9
+ const defaultTimeZone = config?.timeZone ?? "UTC";
10
+ const defaultNumberingSystem = config?.numberingSystem;
11
+ const formatterCacheSize = config?.formatterCacheSize ?? 64;
12
+ return {
13
+ formatDate(input, options) {
14
+ const isDateOnly = "kind" in input &&
15
+ (input.kind === "local-date" || input.kind === "calendar-date");
16
+ const base = {
17
+ locale: options?.locale ?? defaultLocale,
18
+ calendar: options?.calendar ?? defaultCalendar,
19
+ ...(options?.numberingSystem !== undefined
20
+ ? { numberingSystem: options.numberingSystem }
21
+ : defaultNumberingSystem !== undefined
22
+ ? { numberingSystem: defaultNumberingSystem }
23
+ : {}),
24
+ ...(options?.timeZone !== undefined
25
+ ? { timeZone: options.timeZone }
26
+ : !isDateOnly
27
+ ? { timeZone: defaultTimeZone }
28
+ : {}),
29
+ };
30
+ const mergedOptions = options && "preset" in options && options.preset !== undefined
31
+ ? { ...base, preset: options.preset }
32
+ : {
33
+ ...base,
34
+ ...(options && "style" in options && options.style !== undefined
35
+ ? { style: options.style }
36
+ : {}),
37
+ };
38
+ return formatDateWithRegistry(engine.registry, input, mergedOptions);
39
+ },
40
+ parseLocalDate(input, options) {
41
+ return parseLocalDate(input, options);
42
+ },
43
+ convertCalendarDate(source, targetCalendar, options) {
44
+ return convertCalendarDateWithRegistry(engine.registry, source, targetCalendar, options);
45
+ },
46
+ resolvedOptions() {
47
+ return {
48
+ locale: defaultLocale,
49
+ calendar: defaultCalendar,
50
+ ...(defaultNumberingSystem !== undefined
51
+ ? { numberingSystem: defaultNumberingSystem }
52
+ : {}),
53
+ timeZone: defaultTimeZone,
54
+ formatterCacheSize,
55
+ };
56
+ },
57
+ };
58
+ }
59
+ //# sourceMappingURL=create-chronera.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-chronera.js","sourceRoot":"","sources":["../src/create-chronera.ts"],"names":[],"mappings":"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","sourcesContent":["import { ChroneraEngine } from \"./internal/engine.js\";\nimport { formatDateWithRegistry } from \"./format/format-date.js\";\nimport { parseLocalDate } from \"./parse/parse-local-date.js\";\nimport { convertCalendarDateWithRegistry } from \"./operations/convert-calendar-date.js\";\n\nimport type {\n CalendarDate,\n CalendarId,\n ChroneraConfig,\n ChroneraInstance,\n ConvertCalendarOptions,\n FormatDateInput,\n FormatDateOptions,\n LocalDate,\n ParseLocalDateOptions,\n ResolvedChroneraOptions,\n} from \"./public-types.js\";\n\nexport function createChronera(\n config?: Readonly<ChroneraConfig>,\n): ChroneraInstance {\n const engine = new ChroneraEngine(config);\n\n const defaultLocale = config?.locale ?? \"en-US\";\n const defaultCalendar = config?.calendar ?? \"gregory\";\n const defaultTimeZone = config?.timeZone ?? \"UTC\";\n const defaultNumberingSystem = config?.numberingSystem;\n const formatterCacheSize = config?.formatterCacheSize ?? 64;\n\n return {\n formatDate(\n input: FormatDateInput,\n options?: Readonly<FormatDateOptions>,\n ): string {\n const isDateOnly =\n \"kind\" in input &&\n (input.kind === \"local-date\" || input.kind === \"calendar-date\");\n\n const base = {\n locale: options?.locale ?? defaultLocale,\n calendar: options?.calendar ?? defaultCalendar,\n ...(options?.numberingSystem !== undefined\n ? { numberingSystem: options.numberingSystem }\n : defaultNumberingSystem !== undefined\n ? { numberingSystem: defaultNumberingSystem }\n : {}),\n ...(options?.timeZone !== undefined\n ? { timeZone: options.timeZone }\n : !isDateOnly\n ? { timeZone: defaultTimeZone }\n : {}),\n };\n\n const mergedOptions: FormatDateOptions =\n options && \"preset\" in options && options.preset !== undefined\n ? { ...base, preset: options.preset }\n : {\n ...base,\n ...(options && \"style\" in options && options.style !== undefined\n ? { style: options.style }\n : {}),\n };\n\n return formatDateWithRegistry(engine.registry, input, mergedOptions);\n },\n\n parseLocalDate(\n input: string,\n options?: Readonly<ParseLocalDateOptions>,\n ): LocalDate {\n return parseLocalDate(input, options);\n },\n\n convertCalendarDate(\n source: CalendarDate,\n targetCalendar: CalendarId,\n options?: Readonly<ConvertCalendarOptions>,\n ): ReturnType<typeof convertCalendarDateWithRegistry> {\n return convertCalendarDateWithRegistry(\n engine.registry,\n source,\n targetCalendar,\n options,\n );\n },\n\n resolvedOptions(): ResolvedChroneraOptions {\n return {\n locale: defaultLocale,\n calendar: defaultCalendar,\n ...(defaultNumberingSystem !== undefined\n ? { numberingSystem: defaultNumberingSystem }\n : {}),\n timeZone: defaultTimeZone,\n formatterCacheSize,\n };\n },\n };\n}\n"]}
@@ -0,0 +1 @@
1
+ export type ChroneraErrorCode = "CHRONERA_INVALID_DATE" | "CHRONERA_INVALID_TIME" | "CHRONERA_INVALID_INSTANT" | "CHRONERA_INVALID_CALENDAR" | "CHRONERA_UNSUPPORTED_CALENDAR" | "CHRONERA_INVALID_TIME_ZONE" | "CHRONERA_UNSUPPORTED_TIME_ZONE" | "CHRONERA_INVALID_LOCALE" | "CHRONERA_PARSE_FAILED" | "CHRONERA_AMBIGUOUS_DATE" | "CHRONERA_OUT_OF_RANGE" | "CHRONERA_UNSUPPORTED_OPERATION" | "CHRONERA_INCOMPATIBLE_OPTION" | "CHRONERA_INPUT_TOO_LONG" | "CHRONERA_INPUT_TOO_LARGE" | "CHRONERA_PATTERN_TOO_LONG" | "CHRONERA_PATTERN_TOO_COMPLEX";
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=error-codes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-codes.js","sourceRoot":"","sources":["../../src/errors/error-codes.ts"],"names":[],"mappings":"","sourcesContent":["export type ChroneraErrorCode =\n | \"CHRONERA_INVALID_DATE\"\n | \"CHRONERA_INVALID_TIME\"\n | \"CHRONERA_INVALID_INSTANT\"\n | \"CHRONERA_INVALID_CALENDAR\"\n | \"CHRONERA_UNSUPPORTED_CALENDAR\"\n | \"CHRONERA_INVALID_TIME_ZONE\"\n | \"CHRONERA_UNSUPPORTED_TIME_ZONE\"\n | \"CHRONERA_INVALID_LOCALE\"\n | \"CHRONERA_PARSE_FAILED\"\n | \"CHRONERA_AMBIGUOUS_DATE\"\n | \"CHRONERA_OUT_OF_RANGE\"\n | \"CHRONERA_UNSUPPORTED_OPERATION\"\n | \"CHRONERA_INCOMPATIBLE_OPTION\"\n | \"CHRONERA_INPUT_TOO_LONG\"\n | \"CHRONERA_INPUT_TOO_LARGE\"\n | \"CHRONERA_PATTERN_TOO_LONG\"\n | \"CHRONERA_PATTERN_TOO_COMPLEX\";\n"]}
@@ -0,0 +1,16 @@
1
+ import type { ChroneraErrorCode } from "./error-codes.js";
2
+ export declare class ChroneraError extends Error {
3
+ readonly name: string;
4
+ readonly code: ChroneraErrorCode;
5
+ readonly details?: Readonly<Record<string, unknown>>;
6
+ constructor(code: ChroneraErrorCode, message: string, details?: Readonly<Record<string, unknown>>, options?: ErrorOptions);
7
+ }
8
+ export declare class ChroneraParseError extends ChroneraError {
9
+ readonly name = "ChroneraParseError";
10
+ }
11
+ export declare class ChroneraRangeError extends ChroneraError {
12
+ readonly name = "ChroneraRangeError";
13
+ }
14
+ export declare class ChroneraUnsupportedError extends ChroneraError {
15
+ readonly name = "ChroneraUnsupportedError";
16
+ }
@@ -0,0 +1,22 @@
1
+ export class ChroneraError extends Error {
2
+ name = "ChroneraError";
3
+ code;
4
+ details;
5
+ constructor(code, message, details, options) {
6
+ super(message, options);
7
+ this.code = code;
8
+ if (details !== undefined) {
9
+ this.details = { ...details };
10
+ }
11
+ }
12
+ }
13
+ export class ChroneraParseError extends ChroneraError {
14
+ name = "ChroneraParseError";
15
+ }
16
+ export class ChroneraRangeError extends ChroneraError {
17
+ name = "ChroneraRangeError";
18
+ }
19
+ export class ChroneraUnsupportedError extends ChroneraError {
20
+ name = "ChroneraUnsupportedError";
21
+ }
22
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/errors/errors.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,aAAc,SAAQ,KAAK;IACpB,IAAI,GAAW,eAAe,CAAC;IACxC,IAAI,CAAoB;IACxB,OAAO,CAAqC;IAErD,YACE,IAAuB,EACvB,OAAe,EACf,OAA2C,EAC3C,OAAsB;QAEtB,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC1B,IAAI,CAAC,OAAO,GAAG,EAAE,GAAG,OAAO,EAAE,CAAC;QAChC,CAAC;IACH,CAAC;CACF;AAED,MAAM,OAAO,kBAAmB,SAAQ,aAAa;IACjC,IAAI,GAAG,oBAAoB,CAAC;CAC/C;AAED,MAAM,OAAO,kBAAmB,SAAQ,aAAa;IACjC,IAAI,GAAG,oBAAoB,CAAC;CAC/C;AAED,MAAM,OAAO,wBAAyB,SAAQ,aAAa;IACvC,IAAI,GAAG,0BAA0B,CAAC;CACrD","sourcesContent":["import type { ChroneraErrorCode } from \"./error-codes.js\";\n\nexport class ChroneraError extends Error {\n override readonly name: string = \"ChroneraError\";\n readonly code: ChroneraErrorCode;\n readonly details?: Readonly<Record<string, unknown>>;\n\n constructor(\n code: ChroneraErrorCode,\n message: string,\n details?: Readonly<Record<string, unknown>>,\n options?: ErrorOptions,\n ) {\n super(message, options);\n this.code = code;\n if (details !== undefined) {\n this.details = { ...details };\n }\n }\n}\n\nexport class ChroneraParseError extends ChroneraError {\n override readonly name = \"ChroneraParseError\";\n}\n\nexport class ChroneraRangeError extends ChroneraError {\n override readonly name = \"ChroneraRangeError\";\n}\n\nexport class ChroneraUnsupportedError extends ChroneraError {\n override readonly name = \"ChroneraUnsupportedError\";\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export { ChroneraError, ChroneraParseError, ChroneraRangeError, ChroneraUnsupportedError, } from "./errors.js";
2
+ export type { ChroneraErrorCode } from "./error-codes.js";
@@ -0,0 +1,2 @@
1
+ export { ChroneraError, ChroneraParseError, ChroneraRangeError, ChroneraUnsupportedError, } from "./errors.js";
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/errors/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,kBAAkB,EAClB,wBAAwB,GACzB,MAAM,aAAa,CAAC","sourcesContent":["export {\n ChroneraError,\n ChroneraParseError,\n ChroneraRangeError,\n ChroneraUnsupportedError,\n} from \"./errors.js\";\n\nexport type { ChroneraErrorCode } from \"./error-codes.js\";\n"]}
@@ -0,0 +1,2 @@
1
+ import type { CalendarDate, DateRange, FormatDateRangeOptions, Instant, LocalDate } from "../public-types.js";
2
+ export declare function formatDateRange(range: DateRange<LocalDate | CalendarDate | Instant>, options?: Readonly<FormatDateRangeOptions>): string;
@@ -0,0 +1,89 @@
1
+ import { ChroneraError } from "../errors/errors.js";
2
+ import { compareInstants, compareLocalDates } from "../operations/compare.js";
3
+ import { formatDate } from "./format-date.js";
4
+ import { validateAndResolveLocale } from "../locale/resolve-locale.js";
5
+ export function formatDateRange(range, options = {}) {
6
+ const { start, end } = range;
7
+ // Validate mixed input kinds
8
+ if (start.kind !== end.kind) {
9
+ throw new ChroneraError("CHRONERA_INVALID_DATE", `Cannot format date range with mixed input kinds: "${start.kind}" and "${end.kind}".`);
10
+ }
11
+ // Validate ordering and timezone rules
12
+ if (start.kind === "local-date") {
13
+ if (options.timeZone !== undefined) {
14
+ throw new ChroneraError("CHRONERA_INCOMPATIBLE_OPTION", "Timezone option is forbidden for date-only ranges.");
15
+ }
16
+ const cmp = compareLocalDates(start, end);
17
+ if (cmp > 0) {
18
+ throw new ChroneraError("CHRONERA_OUT_OF_RANGE", "Range start must be earlier than or equal to range end.");
19
+ }
20
+ }
21
+ else if (start.kind === "calendar-date") {
22
+ if (options.timeZone !== undefined) {
23
+ throw new ChroneraError("CHRONERA_INCOMPATIBLE_OPTION", "Timezone option is forbidden for calendar date ranges.");
24
+ }
25
+ const endCal = end;
26
+ if (start.calendar !== endCal.calendar) {
27
+ throw new ChroneraError("CHRONERA_INVALID_CALENDAR", `Cannot format range with mixed calendars "${start.calendar}" and "${endCal.calendar}".`);
28
+ }
29
+ if (start.year > endCal.year ||
30
+ (start.year === endCal.year && start.monthCode > endCal.monthCode) ||
31
+ (start.year === endCal.year &&
32
+ start.monthCode === endCal.monthCode &&
33
+ start.day > endCal.day)) {
34
+ throw new ChroneraError("CHRONERA_OUT_OF_RANGE", "Range start must be earlier than or equal to range end.");
35
+ }
36
+ }
37
+ else if (start.kind === "instant") {
38
+ const cmp = compareInstants(start, end);
39
+ if (cmp > 0) {
40
+ throw new ChroneraError("CHRONERA_OUT_OF_RANGE", "Range start must be earlier than or equal to range end.");
41
+ }
42
+ }
43
+ const collapse = options.collapse ?? "auto";
44
+ if (collapse === "auto" &&
45
+ typeof Intl !== "undefined" &&
46
+ typeof Intl.DateTimeFormat.prototype
47
+ .formatRange === "function" &&
48
+ options.preset === undefined) {
49
+ try {
50
+ const localeInfo = validateAndResolveLocale(options.locale);
51
+ const locale = localeInfo.baseLocale;
52
+ const cal = options.calendar ??
53
+ (start.kind === "calendar-date" ? start.calendar : "gregory");
54
+ const style = options.style ?? "medium";
55
+ let startDate;
56
+ let endDate;
57
+ if (start.kind === "local-date") {
58
+ const endLd = end;
59
+ startDate = new Date(Date.UTC(start.year, start.month - 1, start.day));
60
+ endDate = new Date(Date.UTC(endLd.year, endLd.month - 1, endLd.day));
61
+ }
62
+ else if (start.kind === "calendar-date") {
63
+ const endCd = end;
64
+ const startM = start.month ?? Number.parseInt(start.monthCode.slice(1), 10);
65
+ const endM = endCd.month ?? Number.parseInt(endCd.monthCode.slice(1), 10);
66
+ startDate = new Date(Date.UTC(start.year, startM - 1, start.day));
67
+ endDate = new Date(Date.UTC(endCd.year, endM - 1, endCd.day));
68
+ }
69
+ else {
70
+ startDate = new Date(start.epochMilliseconds);
71
+ endDate = new Date(end.epochMilliseconds);
72
+ }
73
+ const dtf = new Intl.DateTimeFormat(locale, {
74
+ dateStyle: style,
75
+ timeZone: options.timeZone ?? "UTC",
76
+ ...(cal !== "iso8601" ? { calendar: cal } : { calendar: "gregory" }),
77
+ });
78
+ return dtf.formatRange(startDate, endDate);
79
+ }
80
+ catch {
81
+ // Fall through to fallback formatting
82
+ }
83
+ }
84
+ // Fallback formatting: start – end
85
+ const startFormatted = formatDate(start, options);
86
+ const endFormatted = formatDate(end, options);
87
+ return `${startFormatted} – ${endFormatted}`;
88
+ }
89
+ //# sourceMappingURL=format-date-range.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format-date-range.js","sourceRoot":"","sources":["../../src/format/format-date-range.ts"],"names":[],"mappings":"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","sourcesContent":["import { ChroneraError } from \"../errors/errors.js\";\nimport { compareInstants, compareLocalDates } from \"../operations/compare.js\";\nimport { formatDate } from \"./format-date.js\";\nimport { validateAndResolveLocale } from \"../locale/resolve-locale.js\";\n\nimport type {\n CalendarDate,\n DateRange,\n FormatDateRangeOptions,\n Instant,\n LocalDate,\n} from \"../public-types.js\";\n\nexport function formatDateRange(\n range: DateRange<LocalDate | CalendarDate | Instant>,\n options: Readonly<FormatDateRangeOptions> = {},\n): string {\n const { start, end } = range;\n\n // Validate mixed input kinds\n if (start.kind !== end.kind) {\n throw new ChroneraError(\n \"CHRONERA_INVALID_DATE\",\n `Cannot format date range with mixed input kinds: \"${start.kind}\" and \"${end.kind}\".`,\n );\n }\n\n // Validate ordering and timezone rules\n if (start.kind === \"local-date\") {\n if (options.timeZone !== undefined) {\n throw new ChroneraError(\n \"CHRONERA_INCOMPATIBLE_OPTION\",\n \"Timezone option is forbidden for date-only ranges.\",\n );\n }\n const cmp = compareLocalDates(start, end as LocalDate);\n if (cmp > 0) {\n throw new ChroneraError(\n \"CHRONERA_OUT_OF_RANGE\",\n \"Range start must be earlier than or equal to range end.\",\n );\n }\n } else if (start.kind === \"calendar-date\") {\n if (options.timeZone !== undefined) {\n throw new ChroneraError(\n \"CHRONERA_INCOMPATIBLE_OPTION\",\n \"Timezone option is forbidden for calendar date ranges.\",\n );\n }\n const endCal = end as CalendarDate;\n if (start.calendar !== endCal.calendar) {\n throw new ChroneraError(\n \"CHRONERA_INVALID_CALENDAR\",\n `Cannot format range with mixed calendars \"${start.calendar}\" and \"${endCal.calendar}\".`,\n );\n }\n if (\n start.year > endCal.year ||\n (start.year === endCal.year && start.monthCode > endCal.monthCode) ||\n (start.year === endCal.year &&\n start.monthCode === endCal.monthCode &&\n start.day > endCal.day)\n ) {\n throw new ChroneraError(\n \"CHRONERA_OUT_OF_RANGE\",\n \"Range start must be earlier than or equal to range end.\",\n );\n }\n } else if (start.kind === \"instant\") {\n const cmp = compareInstants(start, end as Instant);\n if (cmp > 0) {\n throw new ChroneraError(\n \"CHRONERA_OUT_OF_RANGE\",\n \"Range start must be earlier than or equal to range end.\",\n );\n }\n }\n\n const collapse = options.collapse ?? \"auto\";\n\n if (\n collapse === \"auto\" &&\n typeof Intl !== \"undefined\" &&\n typeof (Intl.DateTimeFormat.prototype as { formatRange?: unknown })\n .formatRange === \"function\" &&\n options.preset === undefined\n ) {\n try {\n const localeInfo = validateAndResolveLocale(options.locale);\n const locale = localeInfo.baseLocale;\n const cal =\n options.calendar ??\n (start.kind === \"calendar-date\" ? start.calendar : \"gregory\");\n const style = options.style ?? \"medium\";\n\n let startDate: Date;\n let endDate: Date;\n\n if (start.kind === \"local-date\") {\n const endLd = end as LocalDate;\n startDate = new Date(Date.UTC(start.year, start.month - 1, start.day));\n endDate = new Date(Date.UTC(endLd.year, endLd.month - 1, endLd.day));\n } else if (start.kind === \"calendar-date\") {\n const endCd = end as CalendarDate;\n const startM =\n start.month ?? Number.parseInt(start.monthCode.slice(1), 10);\n const endM =\n endCd.month ?? Number.parseInt(endCd.monthCode.slice(1), 10);\n startDate = new Date(Date.UTC(start.year, startM - 1, start.day));\n endDate = new Date(Date.UTC(endCd.year, endM - 1, endCd.day));\n } else {\n startDate = new Date(start.epochMilliseconds);\n endDate = new Date((end as Instant).epochMilliseconds);\n }\n\n const dtf = new Intl.DateTimeFormat(locale, {\n dateStyle: style as Intl.DateTimeFormatOptions[\"dateStyle\"],\n timeZone: options.timeZone ?? \"UTC\",\n ...(cal !== \"iso8601\" ? { calendar: cal } : { calendar: \"gregory\" }),\n });\n\n return (\n dtf as unknown as { formatRange(a: Date, b: Date): string }\n ).formatRange(startDate, endDate);\n } catch {\n // Fall through to fallback formatting\n }\n }\n\n // Fallback formatting: start – end\n const startFormatted = formatDate(start, options);\n const endFormatted = formatDate(end, options);\n return `${startFormatted} – ${endFormatted}`;\n}\n"]}
@@ -0,0 +1,2 @@
1
+ import type { FormatDateTimeOptions, Instant, LocalDateTime } from "../public-types.js";
2
+ export declare function formatDateTime(input: LocalDateTime | Instant | Date, options?: Readonly<FormatDateTimeOptions>): string;