@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,51 @@
1
+ import { ChroneraError } from "../errors/errors.js";
2
+ import { instantFromDate } from "../core/instant.js";
3
+ import { validateAndResolveLocale } from "../locale/resolve-locale.js";
4
+ import { formatNumberWithSystem } from "../locale/numbering-system.js";
5
+ export function formatDateTime(input, options = {}) {
6
+ const localeInfo = validateAndResolveLocale(options.locale);
7
+ const locale = localeInfo.baseLocale;
8
+ const numberingSystem = options.numberingSystem ?? localeInfo.unicodeNumberingSystem;
9
+ const dateStyle = options.dateStyle ?? "medium";
10
+ const timeStyle = options.timeStyle ?? "short";
11
+ const calId = options.calendar ?? "gregory";
12
+ let timestamp;
13
+ let timeZone = "UTC";
14
+ if ("kind" in input && input.kind === "local-date-time") {
15
+ if (options.timeZone !== undefined) {
16
+ throw new ChroneraError("CHRONERA_INCOMPATIBLE_OPTION", "Timezone option is forbidden for local-date-time inputs.");
17
+ }
18
+ timestamp = Date.UTC(input.date.year, input.date.month - 1, input.date.day, input.time.hour, input.time.minute, input.time.second, input.time.millisecond);
19
+ }
20
+ else {
21
+ let instant;
22
+ if ("kind" in input && input.kind === "instant") {
23
+ instant = input;
24
+ }
25
+ else if (input instanceof Date) {
26
+ instant = instantFromDate(input);
27
+ }
28
+ else {
29
+ throw new ChroneraError("CHRONERA_INVALID_DATE", "Expected LocalDateTime, Instant, or Date.");
30
+ }
31
+ timestamp = instant.epochMilliseconds;
32
+ timeZone = options.timeZone ?? "UTC";
33
+ }
34
+ const intlOpts = {
35
+ dateStyle,
36
+ timeStyle,
37
+ timeZone,
38
+ ...(calId !== "iso8601" ? { calendar: calId } : { calendar: "gregory" }),
39
+ ...(options.hourCycle !== undefined
40
+ ? { hourCycle: options.hourCycle }
41
+ : {}),
42
+ ...(numberingSystem !== undefined ? { numberingSystem } : {}),
43
+ };
44
+ const dtf = new Intl.DateTimeFormat(locale, intlOpts);
45
+ let output = dtf.format(new Date(timestamp));
46
+ if (numberingSystem && numberingSystem !== "latn") {
47
+ output = formatNumberWithSystem(output, numberingSystem);
48
+ }
49
+ return output;
50
+ }
51
+ //# sourceMappingURL=format-date-time.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format-date-time.js","sourceRoot":"","sources":["../../src/format/format-date-time.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AACvE,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AAQvE,MAAM,UAAU,cAAc,CAC5B,KAAqC,EACrC,UAA2C,EAAE;IAE7C,MAAM,UAAU,GAAG,wBAAwB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAC5D,MAAM,MAAM,GAAG,UAAU,CAAC,UAAU,CAAC;IACrC,MAAM,eAAe,GACnB,OAAO,CAAC,eAAe,IAAI,UAAU,CAAC,sBAAsB,CAAC;IAC/D,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,QAAQ,CAAC;IAChD,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,OAAO,CAAC;IAC/C,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,IAAI,SAAS,CAAC;IAE5C,IAAI,SAAiB,CAAC;IACtB,IAAI,QAAQ,GAAG,KAAK,CAAC;IAErB,IAAI,MAAM,IAAI,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,iBAAiB,EAAE,CAAC;QACxD,IAAI,OAAO,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;YACnC,MAAM,IAAI,aAAa,CACrB,8BAA8B,EAC9B,0DAA0D,CAC3D,CAAC;QACJ,CAAC;QACD,SAAS,GAAG,IAAI,CAAC,GAAG,CAClB,KAAK,CAAC,IAAI,CAAC,IAAI,EACf,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,EACpB,KAAK,CAAC,IAAI,CAAC,GAAG,EACd,KAAK,CAAC,IAAI,CAAC,IAAI,EACf,KAAK,CAAC,IAAI,CAAC,MAAM,EACjB,KAAK,CAAC,IAAI,CAAC,MAAM,EACjB,KAAK,CAAC,IAAI,CAAC,WAAW,CACvB,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,IAAI,OAAgB,CAAC;QACrB,IAAI,MAAM,IAAI,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAChD,OAAO,GAAG,KAAK,CAAC;QAClB,CAAC;aAAM,IAAI,KAAK,YAAY,IAAI,EAAE,CAAC;YACjC,OAAO,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;QACnC,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,aAAa,CACrB,uBAAuB,EACvB,2CAA2C,CAC5C,CAAC;QACJ,CAAC;QACD,SAAS,GAAG,OAAO,CAAC,iBAAiB,CAAC;QACtC,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,KAAK,CAAC;IACvC,CAAC;IAED,MAAM,QAAQ,GAA+B;QAC3C,SAAS;QACT,SAAS;QACT,QAAQ;QACR,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;QACxE,GAAG,CAAC,OAAO,CAAC,SAAS,KAAK,SAAS;YACjC,CAAC,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE;YAClC,CAAC,CAAC,EAAE,CAAC;QACP,GAAG,CAAC,eAAe,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC9D,CAAC;IAEF,MAAM,GAAG,GAAG,IAAI,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACtD,IAAI,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;IAE7C,IAAI,eAAe,IAAI,eAAe,KAAK,MAAM,EAAE,CAAC;QAClD,MAAM,GAAG,sBAAsB,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAC3D,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC","sourcesContent":["import { ChroneraError } from \"../errors/errors.js\";\nimport { instantFromDate } from \"../core/instant.js\";\nimport { validateAndResolveLocale } from \"../locale/resolve-locale.js\";\nimport { formatNumberWithSystem } from \"../locale/numbering-system.js\";\n\nimport type {\n FormatDateTimeOptions,\n Instant,\n LocalDateTime,\n} from \"../public-types.js\";\n\nexport function formatDateTime(\n input: LocalDateTime | Instant | Date,\n options: Readonly<FormatDateTimeOptions> = {},\n): string {\n const localeInfo = validateAndResolveLocale(options.locale);\n const locale = localeInfo.baseLocale;\n const numberingSystem =\n options.numberingSystem ?? localeInfo.unicodeNumberingSystem;\n const dateStyle = options.dateStyle ?? \"medium\";\n const timeStyle = options.timeStyle ?? \"short\";\n const calId = options.calendar ?? \"gregory\";\n\n let timestamp: number;\n let timeZone = \"UTC\";\n\n if (\"kind\" in input && input.kind === \"local-date-time\") {\n if (options.timeZone !== undefined) {\n throw new ChroneraError(\n \"CHRONERA_INCOMPATIBLE_OPTION\",\n \"Timezone option is forbidden for local-date-time inputs.\",\n );\n }\n timestamp = Date.UTC(\n input.date.year,\n input.date.month - 1,\n input.date.day,\n input.time.hour,\n input.time.minute,\n input.time.second,\n input.time.millisecond,\n );\n } else {\n let instant: Instant;\n if (\"kind\" in input && input.kind === \"instant\") {\n instant = input;\n } else if (input instanceof Date) {\n instant = instantFromDate(input);\n } else {\n throw new ChroneraError(\n \"CHRONERA_INVALID_DATE\",\n \"Expected LocalDateTime, Instant, or Date.\",\n );\n }\n timestamp = instant.epochMilliseconds;\n timeZone = options.timeZone ?? \"UTC\";\n }\n\n const intlOpts: Intl.DateTimeFormatOptions = {\n dateStyle,\n timeStyle,\n timeZone,\n ...(calId !== \"iso8601\" ? { calendar: calId } : { calendar: \"gregory\" }),\n ...(options.hourCycle !== undefined\n ? { hourCycle: options.hourCycle }\n : {}),\n ...(numberingSystem !== undefined ? { numberingSystem } : {}),\n };\n\n const dtf = new Intl.DateTimeFormat(locale, intlOpts);\n let output = dtf.format(new Date(timestamp));\n\n if (numberingSystem && numberingSystem !== \"latn\") {\n output = formatNumberWithSystem(output, numberingSystem);\n }\n\n return output;\n}\n"]}
@@ -0,0 +1,4 @@
1
+ import type { CalendarRegistry } from "../calendar/registry.js";
2
+ import type { FormatDateInput, FormatDateOptions } from "../public-types.js";
3
+ export declare function formatDateWithRegistry(registry: CalendarRegistry, input: FormatDateInput, options?: Readonly<FormatDateOptions>): string;
4
+ export declare function formatDate(input: FormatDateInput, options?: Readonly<FormatDateOptions>): string;
@@ -0,0 +1,103 @@
1
+ import { resolveDateFormattingInput } from "./resolve-date-input.js";
2
+ import { formatThaiOfficialPreset } from "./presets/thai-official.js";
3
+ import { formatJapaneseOfficialPreset, formatJapaneseOfficialWithWeekdayPreset, } from "./presets/japanese-official.js";
4
+ import { formatTaiwanOfficialPreset } from "./presets/taiwan-official.js";
5
+ import { formatArabicGregorianPreset, formatArabicHijriPreset, formatChineseShortPreset, formatChineseStandardPreset, formatChineseWithWeekdayPreset, formatFrenchLongPreset, formatFrenchStandardPreset, formatFrenchWithWeekdayPreset, formatGermanDinStandardPreset, formatGermanLongPreset, formatGermanWithWeekdayPreset, formatJapaneseEraShortPreset, formatJapaneseSeirekiPreset, formatSpanishLongPreset, formatSpanishStandardPreset, formatSpanishWithWeekdayPreset, formatThaiShortDatePreset, formatThaiSlashDatePreset, formatUkLongPreset, formatUkStandardPreset, formatUkWithWeekdayPreset, formatUsLongPreset, formatUsStandardPreset, formatUsWithWeekdayPreset, } from "./presets/world-locales.js";
6
+ import { defaultCalendarRegistry } from "../calendar/registry.js";
7
+ import { validateAndResolveLocale } from "../locale/resolve-locale.js";
8
+ import { formatNumberWithSystem } from "../locale/numbering-system.js";
9
+ import { gregorianFieldsFromAbsoluteDay } from "../core/absolute-day.js";
10
+ export function formatDateWithRegistry(registry, input, options = {}) {
11
+ const resolved = resolveDateFormattingInput(registry, input, options);
12
+ const localeInfo = validateAndResolveLocale(options.locale);
13
+ const locale = localeInfo.baseLocale;
14
+ const numberingSystem = options.numberingSystem ?? localeInfo.unicodeNumberingSystem;
15
+ if (options.preset !== undefined) {
16
+ const presetOpt = numberingSystem !== undefined ? { numberingSystem } : {};
17
+ switch (options.preset) {
18
+ case "thai-official-date":
19
+ case "thai-official-date-with-weekday":
20
+ return formatThaiOfficialPreset(resolved.calendarDate, options.preset, resolved.absoluteDay, numberingSystem ?? "latn");
21
+ case "thai-short-date":
22
+ return formatThaiShortDatePreset(resolved.calendarDate, resolved.absoluteDay, presetOpt);
23
+ case "thai-slash-date":
24
+ return formatThaiSlashDatePreset(resolved.calendarDate, resolved.absoluteDay, presetOpt);
25
+ case "japanese-official":
26
+ return formatJapaneseOfficialPreset(resolved.calendarDate, resolved.absoluteDay, presetOpt);
27
+ case "japanese-official-with-weekday":
28
+ return formatJapaneseOfficialWithWeekdayPreset(resolved.calendarDate, resolved.absoluteDay, presetOpt);
29
+ case "japanese-seireki":
30
+ return formatJapaneseSeirekiPreset(resolved.calendarDate, resolved.absoluteDay, presetOpt);
31
+ case "japanese-era-short":
32
+ return formatJapaneseEraShortPreset(resolved.calendarDate, resolved.absoluteDay, presetOpt);
33
+ case "taiwan-official":
34
+ return formatTaiwanOfficialPreset(resolved.calendarDate, resolved.absoluteDay, presetOpt);
35
+ case "us-standard":
36
+ return formatUsStandardPreset(resolved.calendarDate, resolved.absoluteDay, presetOpt);
37
+ case "us-long":
38
+ return formatUsLongPreset(resolved.calendarDate, resolved.absoluteDay, presetOpt);
39
+ case "us-with-weekday":
40
+ return formatUsWithWeekdayPreset(resolved.calendarDate, resolved.absoluteDay, presetOpt);
41
+ case "uk-standard":
42
+ return formatUkStandardPreset(resolved.calendarDate, resolved.absoluteDay, presetOpt);
43
+ case "uk-long":
44
+ return formatUkLongPreset(resolved.calendarDate, resolved.absoluteDay, presetOpt);
45
+ case "uk-with-weekday":
46
+ return formatUkWithWeekdayPreset(resolved.calendarDate, resolved.absoluteDay, presetOpt);
47
+ case "german-din-standard":
48
+ return formatGermanDinStandardPreset(resolved.calendarDate, resolved.absoluteDay, presetOpt);
49
+ case "german-long":
50
+ return formatGermanLongPreset(resolved.calendarDate, resolved.absoluteDay, presetOpt);
51
+ case "german-with-weekday":
52
+ return formatGermanWithWeekdayPreset(resolved.calendarDate, resolved.absoluteDay, presetOpt);
53
+ case "french-standard":
54
+ return formatFrenchStandardPreset(resolved.calendarDate, resolved.absoluteDay, presetOpt);
55
+ case "french-long":
56
+ return formatFrenchLongPreset(resolved.calendarDate, resolved.absoluteDay, presetOpt);
57
+ case "french-with-weekday":
58
+ return formatFrenchWithWeekdayPreset(resolved.calendarDate, resolved.absoluteDay, presetOpt);
59
+ case "chinese-standard":
60
+ return formatChineseStandardPreset(resolved.calendarDate, resolved.absoluteDay, presetOpt);
61
+ case "chinese-with-weekday":
62
+ return formatChineseWithWeekdayPreset(resolved.calendarDate, resolved.absoluteDay, presetOpt);
63
+ case "chinese-short":
64
+ return formatChineseShortPreset(resolved.calendarDate, resolved.absoluteDay, presetOpt);
65
+ case "spanish-standard":
66
+ return formatSpanishStandardPreset(resolved.calendarDate, resolved.absoluteDay, presetOpt);
67
+ case "spanish-long":
68
+ return formatSpanishLongPreset(resolved.calendarDate, resolved.absoluteDay, presetOpt);
69
+ case "spanish-with-weekday":
70
+ return formatSpanishWithWeekdayPreset(resolved.calendarDate, resolved.absoluteDay, presetOpt);
71
+ case "arabic-gregorian":
72
+ return formatArabicGregorianPreset(resolved.calendarDate, resolved.absoluteDay, presetOpt);
73
+ case "arabic-hijri":
74
+ return formatArabicHijriPreset(resolved.calendarDate, resolved.absoluteDay, presetOpt);
75
+ }
76
+ }
77
+ const style = options.style ?? "medium";
78
+ const calId = resolved.calendarDate.calendar;
79
+ // Use UTC instant for the Gregorian equivalent day
80
+ const fields = gregorianFieldsFromAbsoluteDay(resolved.absoluteDay);
81
+ const utcDate = new Date(Date.UTC(fields.year, fields.month - 1, fields.day, 12, 0, 0));
82
+ const formatterOptions = {
83
+ timeZone: "UTC",
84
+ ...(style === "numeric"
85
+ ? { year: "numeric", month: "numeric", day: "numeric" }
86
+ : { dateStyle: style }),
87
+ };
88
+ if (calId !== "gregory" && calId !== "iso8601") {
89
+ formatterOptions.calendar = calId;
90
+ }
91
+ if (numberingSystem) {
92
+ formatterOptions.numberingSystem = numberingSystem;
93
+ }
94
+ const formatted = new Intl.DateTimeFormat(locale, formatterOptions).format(utcDate);
95
+ if (numberingSystem && numberingSystem !== "latn") {
96
+ return formatNumberWithSystem(formatted, numberingSystem);
97
+ }
98
+ return formatted;
99
+ }
100
+ export function formatDate(input, options = {}) {
101
+ return formatDateWithRegistry(defaultCalendarRegistry, input, options);
102
+ }
103
+ //# sourceMappingURL=format-date.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format-date.js","sourceRoot":"","sources":["../../src/format/format-date.ts"],"names":[],"mappings":"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","sourcesContent":["import { resolveDateFormattingInput } from \"./resolve-date-input.js\";\nimport { formatThaiOfficialPreset } from \"./presets/thai-official.js\";\nimport {\n formatJapaneseOfficialPreset,\n formatJapaneseOfficialWithWeekdayPreset,\n} from \"./presets/japanese-official.js\";\nimport { formatTaiwanOfficialPreset } from \"./presets/taiwan-official.js\";\nimport {\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 \"./presets/world-locales.js\";\nimport { defaultCalendarRegistry } from \"../calendar/registry.js\";\nimport { validateAndResolveLocale } from \"../locale/resolve-locale.js\";\nimport { formatNumberWithSystem } from \"../locale/numbering-system.js\";\nimport { gregorianFieldsFromAbsoluteDay } from \"../core/absolute-day.js\";\n\nimport type { CalendarRegistry } from \"../calendar/registry.js\";\nimport type { FormatDateInput, FormatDateOptions } from \"../public-types.js\";\n\nexport function formatDateWithRegistry(\n registry: CalendarRegistry,\n input: FormatDateInput,\n options: Readonly<FormatDateOptions> = {},\n): string {\n const resolved = resolveDateFormattingInput(registry, input, options);\n const localeInfo = validateAndResolveLocale(options.locale);\n const locale = localeInfo.baseLocale;\n const numberingSystem =\n options.numberingSystem ?? localeInfo.unicodeNumberingSystem;\n\n if (options.preset !== undefined) {\n const presetOpt = numberingSystem !== undefined ? { numberingSystem } : {};\n switch (options.preset) {\n case \"thai-official-date\":\n case \"thai-official-date-with-weekday\":\n return formatThaiOfficialPreset(\n resolved.calendarDate,\n options.preset,\n resolved.absoluteDay,\n numberingSystem ?? \"latn\",\n );\n case \"thai-short-date\":\n return formatThaiShortDatePreset(\n resolved.calendarDate,\n resolved.absoluteDay,\n presetOpt,\n );\n case \"thai-slash-date\":\n return formatThaiSlashDatePreset(\n resolved.calendarDate,\n resolved.absoluteDay,\n presetOpt,\n );\n case \"japanese-official\":\n return formatJapaneseOfficialPreset(\n resolved.calendarDate,\n resolved.absoluteDay,\n presetOpt,\n );\n case \"japanese-official-with-weekday\":\n return formatJapaneseOfficialWithWeekdayPreset(\n resolved.calendarDate,\n resolved.absoluteDay,\n presetOpt,\n );\n case \"japanese-seireki\":\n return formatJapaneseSeirekiPreset(\n resolved.calendarDate,\n resolved.absoluteDay,\n presetOpt,\n );\n case \"japanese-era-short\":\n return formatJapaneseEraShortPreset(\n resolved.calendarDate,\n resolved.absoluteDay,\n presetOpt,\n );\n case \"taiwan-official\":\n return formatTaiwanOfficialPreset(\n resolved.calendarDate,\n resolved.absoluteDay,\n presetOpt,\n );\n case \"us-standard\":\n return formatUsStandardPreset(\n resolved.calendarDate,\n resolved.absoluteDay,\n presetOpt,\n );\n case \"us-long\":\n return formatUsLongPreset(\n resolved.calendarDate,\n resolved.absoluteDay,\n presetOpt,\n );\n case \"us-with-weekday\":\n return formatUsWithWeekdayPreset(\n resolved.calendarDate,\n resolved.absoluteDay,\n presetOpt,\n );\n case \"uk-standard\":\n return formatUkStandardPreset(\n resolved.calendarDate,\n resolved.absoluteDay,\n presetOpt,\n );\n case \"uk-long\":\n return formatUkLongPreset(\n resolved.calendarDate,\n resolved.absoluteDay,\n presetOpt,\n );\n case \"uk-with-weekday\":\n return formatUkWithWeekdayPreset(\n resolved.calendarDate,\n resolved.absoluteDay,\n presetOpt,\n );\n case \"german-din-standard\":\n return formatGermanDinStandardPreset(\n resolved.calendarDate,\n resolved.absoluteDay,\n presetOpt,\n );\n case \"german-long\":\n return formatGermanLongPreset(\n resolved.calendarDate,\n resolved.absoluteDay,\n presetOpt,\n );\n case \"german-with-weekday\":\n return formatGermanWithWeekdayPreset(\n resolved.calendarDate,\n resolved.absoluteDay,\n presetOpt,\n );\n case \"french-standard\":\n return formatFrenchStandardPreset(\n resolved.calendarDate,\n resolved.absoluteDay,\n presetOpt,\n );\n case \"french-long\":\n return formatFrenchLongPreset(\n resolved.calendarDate,\n resolved.absoluteDay,\n presetOpt,\n );\n case \"french-with-weekday\":\n return formatFrenchWithWeekdayPreset(\n resolved.calendarDate,\n resolved.absoluteDay,\n presetOpt,\n );\n case \"chinese-standard\":\n return formatChineseStandardPreset(\n resolved.calendarDate,\n resolved.absoluteDay,\n presetOpt,\n );\n case \"chinese-with-weekday\":\n return formatChineseWithWeekdayPreset(\n resolved.calendarDate,\n resolved.absoluteDay,\n presetOpt,\n );\n case \"chinese-short\":\n return formatChineseShortPreset(\n resolved.calendarDate,\n resolved.absoluteDay,\n presetOpt,\n );\n case \"spanish-standard\":\n return formatSpanishStandardPreset(\n resolved.calendarDate,\n resolved.absoluteDay,\n presetOpt,\n );\n case \"spanish-long\":\n return formatSpanishLongPreset(\n resolved.calendarDate,\n resolved.absoluteDay,\n presetOpt,\n );\n case \"spanish-with-weekday\":\n return formatSpanishWithWeekdayPreset(\n resolved.calendarDate,\n resolved.absoluteDay,\n presetOpt,\n );\n case \"arabic-gregorian\":\n return formatArabicGregorianPreset(\n resolved.calendarDate,\n resolved.absoluteDay,\n presetOpt,\n );\n case \"arabic-hijri\":\n return formatArabicHijriPreset(\n resolved.calendarDate,\n resolved.absoluteDay,\n presetOpt,\n );\n }\n }\n\n const style = options.style ?? \"medium\";\n const calId = resolved.calendarDate.calendar;\n\n // Use UTC instant for the Gregorian equivalent day\n const fields = gregorianFieldsFromAbsoluteDay(resolved.absoluteDay);\n const utcDate = new Date(\n Date.UTC(fields.year, fields.month - 1, fields.day, 12, 0, 0),\n );\n\n const formatterOptions: Intl.DateTimeFormatOptions = {\n timeZone: \"UTC\",\n ...(style === \"numeric\"\n ? { year: \"numeric\", month: \"numeric\", day: \"numeric\" }\n : { dateStyle: style }),\n };\n\n if (calId !== \"gregory\" && calId !== \"iso8601\") {\n formatterOptions.calendar = calId;\n }\n\n if (numberingSystem) {\n formatterOptions.numberingSystem = numberingSystem;\n }\n\n const formatted = new Intl.DateTimeFormat(locale, formatterOptions).format(\n utcDate,\n );\n\n if (numberingSystem && numberingSystem !== \"latn\") {\n return formatNumberWithSystem(formatted, numberingSystem);\n }\n\n return formatted;\n}\n\nexport function formatDate(\n input: FormatDateInput,\n options: Readonly<FormatDateOptions> = {},\n): string {\n return formatDateWithRegistry(defaultCalendarRegistry, input, options);\n}\n"]}
@@ -0,0 +1,4 @@
1
+ import type { CalendarRegistry } from "../calendar/registry.js";
2
+ import type { FormatDateInput, LocalDateTime, PatternFormatOptions } from "../public-types.js";
3
+ export declare function formatWithPatternWithRegistry(registry: CalendarRegistry, input: FormatDateInput | LocalDateTime, pattern: string, options?: Readonly<PatternFormatOptions>): string;
4
+ export declare function formatWithPattern(input: FormatDateInput | LocalDateTime, pattern: string, options?: Readonly<PatternFormatOptions>): string;
@@ -0,0 +1,266 @@
1
+ import { scanPattern } from "./pattern-scanner.js";
2
+ import { formatNumberWithSystem } from "../locale/numbering-system.js";
3
+ import { resolveDateFormattingInput } from "./resolve-date-input.js";
4
+ import { defaultCalendarRegistry } from "../calendar/registry.js";
5
+ import { validateAndResolveLocale } from "../locale/resolve-locale.js";
6
+ import { absoluteDayFromGregorianFields } from "../core/absolute-day.js";
7
+ import { getDayOfYearFromAbsoluteDay } from "../core/day-of-year.js";
8
+ import { getIsoDayOfWeek, getIsoWeekFromAbsoluteDay, } from "../core/iso-week.js";
9
+ import { ChroneraError } from "../errors/errors.js";
10
+ export function formatWithPatternWithRegistry(registry, input, pattern, options = {}) {
11
+ const tokens = scanPattern(pattern);
12
+ const localeInfo = validateAndResolveLocale(options.locale);
13
+ const locale = localeInfo.baseLocale;
14
+ const numberingSystem = options.numberingSystem ?? "latn";
15
+ // Check if input is LocalDateTime
16
+ let isLocalDateTime = false;
17
+ let localDt;
18
+ if ("kind" in input && input.kind === "local-date-time") {
19
+ isLocalDateTime = true;
20
+ localDt = input;
21
+ }
22
+ let calDate;
23
+ let absDay;
24
+ let hour = 0;
25
+ let minute = 0;
26
+ let second = 0;
27
+ let millisecond = 0;
28
+ let offsetString = "Z";
29
+ if (isLocalDateTime && localDt) {
30
+ calDate = {
31
+ kind: "calendar-date",
32
+ calendar: "gregory",
33
+ year: localDt.date.year,
34
+ monthCode: `M${String(localDt.date.month).padStart(2, "0")}`,
35
+ month: localDt.date.month,
36
+ day: localDt.date.day,
37
+ era: "CE",
38
+ eraYear: localDt.date.year,
39
+ };
40
+ absDay = absoluteDayFromGregorianFields(localDt.date.year, localDt.date.month, localDt.date.day);
41
+ hour = localDt.time.hour;
42
+ minute = localDt.time.minute;
43
+ second = localDt.time.second;
44
+ millisecond = localDt.time.millisecond;
45
+ }
46
+ else {
47
+ const resolved = resolveDateFormattingInput(registry, input, options);
48
+ calDate = resolved.calendarDate;
49
+ absDay = resolved.absoluteDay;
50
+ if (resolved.instant) {
51
+ const date = new Date(resolved.instant.epochMilliseconds);
52
+ const tz = resolved.timeZone ?? "UTC";
53
+ // Project fields using Intl
54
+ const dtf = new Intl.DateTimeFormat("en-US", {
55
+ timeZone: tz,
56
+ hourCycle: "h23",
57
+ hour: "numeric",
58
+ minute: "numeric",
59
+ second: "numeric",
60
+ timeZoneName: "longOffset",
61
+ });
62
+ const parts = dtf.formatToParts(date);
63
+ for (const p of parts) {
64
+ if (p.type === "hour")
65
+ hour = Number.parseInt(p.value, 10);
66
+ if (p.type === "minute")
67
+ minute = Number.parseInt(p.value, 10);
68
+ if (p.type === "second")
69
+ second = Number.parseInt(p.value, 10);
70
+ if (p.type === "timeZoneName") {
71
+ // e.g. "GMT+07:00" -> "+07:00"
72
+ const m = p.value.match(/GMT([+-]\d{2}:\d{2})/);
73
+ if (m && m[1]) {
74
+ offsetString = m[1];
75
+ }
76
+ else if (p.value === "GMT") {
77
+ offsetString = "Z";
78
+ }
79
+ }
80
+ }
81
+ millisecond = ((resolved.instant.epochMilliseconds % 1000) + 1000) % 1000;
82
+ }
83
+ }
84
+ const month = calDate.month ?? Number.parseInt(calDate.monthCode.slice(1), 10);
85
+ const year = calDate.eraYear ?? calDate.year;
86
+ // Helper for localized text
87
+ const localizedDate = new Date(Date.UTC(calDate.year, month - 1, calDate.day));
88
+ let out = "";
89
+ for (const t of tokens) {
90
+ if (t.type === "literal") {
91
+ out += t.value;
92
+ continue;
93
+ }
94
+ switch (t.symbol) {
95
+ case "y":
96
+ out += formatNumberWithSystem(year, numberingSystem);
97
+ break;
98
+ case "yy":
99
+ out += formatNumberWithSystem(String(year % 100).padStart(2, "0"), numberingSystem);
100
+ break;
101
+ case "yyyy":
102
+ out += formatNumberWithSystem(String(year).padStart(4, "0"), numberingSystem);
103
+ break;
104
+ case "M":
105
+ out += formatNumberWithSystem(month, numberingSystem);
106
+ break;
107
+ case "MM":
108
+ out += formatNumberWithSystem(String(month).padStart(2, "0"), numberingSystem);
109
+ break;
110
+ case "MMM": {
111
+ const dtf = new Intl.DateTimeFormat(locale, {
112
+ calendar: calDate.calendar,
113
+ month: "short",
114
+ timeZone: "UTC",
115
+ });
116
+ out += dtf.format(localizedDate);
117
+ break;
118
+ }
119
+ case "MMMM": {
120
+ const dtf = new Intl.DateTimeFormat(locale, {
121
+ calendar: calDate.calendar,
122
+ month: "long",
123
+ timeZone: "UTC",
124
+ });
125
+ out += dtf.format(localizedDate);
126
+ break;
127
+ }
128
+ case "d":
129
+ out += formatNumberWithSystem(calDate.day, numberingSystem);
130
+ break;
131
+ case "dd":
132
+ out += formatNumberWithSystem(String(calDate.day).padStart(2, "0"), numberingSystem);
133
+ break;
134
+ case "E": {
135
+ const dtf = new Intl.DateTimeFormat(locale, {
136
+ calendar: calDate.calendar,
137
+ weekday: "short",
138
+ timeZone: "UTC",
139
+ });
140
+ out += dtf.format(localizedDate);
141
+ break;
142
+ }
143
+ case "EEEE": {
144
+ const dtf = new Intl.DateTimeFormat(locale, {
145
+ calendar: calDate.calendar,
146
+ weekday: "long",
147
+ timeZone: "UTC",
148
+ });
149
+ out += dtf.format(localizedDate);
150
+ break;
151
+ }
152
+ case "G":
153
+ out += calDate.era ?? (year >= 0 ? "AD" : "BC");
154
+ break;
155
+ case "GGGG": {
156
+ const dtf = new Intl.DateTimeFormat(locale, {
157
+ calendar: calDate.calendar,
158
+ era: "long",
159
+ timeZone: "UTC",
160
+ });
161
+ out += dtf.format(localizedDate);
162
+ break;
163
+ }
164
+ case "H":
165
+ out += formatNumberWithSystem(hour, numberingSystem);
166
+ break;
167
+ case "HH":
168
+ out += formatNumberWithSystem(String(hour).padStart(2, "0"), numberingSystem);
169
+ break;
170
+ case "h": {
171
+ const h12 = hour % 12 === 0 ? 12 : hour % 12;
172
+ out += formatNumberWithSystem(h12, numberingSystem);
173
+ break;
174
+ }
175
+ case "hh": {
176
+ const h12 = hour % 12 === 0 ? 12 : hour % 12;
177
+ out += formatNumberWithSystem(String(h12).padStart(2, "0"), numberingSystem);
178
+ break;
179
+ }
180
+ case "a":
181
+ out += hour < 12 ? "AM" : "PM";
182
+ break;
183
+ case "m":
184
+ out += formatNumberWithSystem(minute, numberingSystem);
185
+ break;
186
+ case "mm":
187
+ out += formatNumberWithSystem(String(minute).padStart(2, "0"), numberingSystem);
188
+ break;
189
+ case "s":
190
+ out += formatNumberWithSystem(second, numberingSystem);
191
+ break;
192
+ case "ss":
193
+ out += formatNumberWithSystem(String(second).padStart(2, "0"), numberingSystem);
194
+ break;
195
+ case "S": {
196
+ const frac1 = Math.floor(millisecond / 100);
197
+ out += formatNumberWithSystem(frac1, numberingSystem);
198
+ break;
199
+ }
200
+ case "SSS":
201
+ out += formatNumberWithSystem(String(millisecond).padStart(3, "0"), numberingSystem);
202
+ break;
203
+ case "XXX":
204
+ out += offsetString === "+00:00" ? "Z" : offsetString;
205
+ break;
206
+ case "Q": {
207
+ const qNum = Math.floor((month - 1) / 3) + 1;
208
+ out += formatNumberWithSystem(qNum, numberingSystem);
209
+ break;
210
+ }
211
+ case "QQQ": {
212
+ const qNum = Math.floor((month - 1) / 3) + 1;
213
+ out += `Q${formatNumberWithSystem(qNum, numberingSystem)}`;
214
+ break;
215
+ }
216
+ case "QQQQ": {
217
+ const qIndex = Math.floor((month - 1) / 3);
218
+ const qNames = [
219
+ "1st quarter",
220
+ "2nd quarter",
221
+ "3rd quarter",
222
+ "4th quarter",
223
+ ];
224
+ out += qNames[qIndex];
225
+ break;
226
+ }
227
+ case "D": {
228
+ const doy = getDayOfYearFromAbsoluteDay(absDay).dayOfYear;
229
+ out += formatNumberWithSystem(doy, numberingSystem);
230
+ break;
231
+ }
232
+ case "DDD": {
233
+ const doy = getDayOfYearFromAbsoluteDay(absDay).dayOfYear;
234
+ out += formatNumberWithSystem(String(doy).padStart(3, "0"), numberingSystem);
235
+ break;
236
+ }
237
+ case "w": {
238
+ const wn = getIsoWeekFromAbsoluteDay(absDay).weekNumber;
239
+ out += formatNumberWithSystem(wn, numberingSystem);
240
+ break;
241
+ }
242
+ case "ww": {
243
+ const wn = getIsoWeekFromAbsoluteDay(absDay).weekNumber;
244
+ out += formatNumberWithSystem(String(wn).padStart(2, "0"), numberingSystem);
245
+ break;
246
+ }
247
+ case "e": {
248
+ const dow = getIsoDayOfWeek(absDay);
249
+ out += formatNumberWithSystem(dow, numberingSystem);
250
+ break;
251
+ }
252
+ case "ee": {
253
+ const dow = getIsoDayOfWeek(absDay);
254
+ out += formatNumberWithSystem(String(dow).padStart(2, "0"), numberingSystem);
255
+ break;
256
+ }
257
+ default:
258
+ throw new ChroneraError("CHRONERA_PATTERN_TOO_COMPLEX", `Unhandled pattern symbol: ${t.symbol}`);
259
+ }
260
+ }
261
+ return out;
262
+ }
263
+ export function formatWithPattern(input, pattern, options) {
264
+ return formatWithPatternWithRegistry(defaultCalendarRegistry, input, pattern, options);
265
+ }
266
+ //# sourceMappingURL=format-pattern.js.map
@@ -0,0 +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"]}
@@ -0,0 +1,2 @@
1
+ import type { FormatRelativeOptions, Instant, LocalDate } from "../public-types.js";
2
+ export declare function formatRelative(target: Instant | LocalDate, options: Readonly<FormatRelativeOptions>): string;
@@ -0,0 +1,93 @@
1
+ import { ChroneraError } from "../errors/errors.js";
2
+ import { validateAndResolveLocale } from "../locale/resolve-locale.js";
3
+ import { absoluteDayFromGregorianFields } from "../core/absolute-day.js";
4
+ export function formatRelative(target, options) {
5
+ if (!options || !options.relativeTo) {
6
+ throw new ChroneraError("CHRONERA_INCOMPATIBLE_OPTION", "formatRelative requires an explicit 'relativeTo' reference.");
7
+ }
8
+ const { relativeTo } = options;
9
+ const localeInfo = validateAndResolveLocale(options.locale);
10
+ const locale = localeInfo.baseLocale;
11
+ const numeric = options.numeric ?? "auto";
12
+ let diffMs;
13
+ let diffDays;
14
+ if (target.kind === "local-date") {
15
+ if (relativeTo.kind !== "local-date") {
16
+ throw new ChroneraError("CHRONERA_INVALID_DATE", "Target and relativeTo must both be LocalDate or both be Instant.");
17
+ }
18
+ const targetAbs = absoluteDayFromGregorianFields(target.year, target.month, target.day);
19
+ const relAbs = absoluteDayFromGregorianFields(relativeTo.year, relativeTo.month, relativeTo.day);
20
+ diffDays = targetAbs - relAbs;
21
+ diffMs = diffDays * 86400000;
22
+ }
23
+ else if (target.kind === "instant") {
24
+ if (relativeTo.kind !== "instant") {
25
+ throw new ChroneraError("CHRONERA_INVALID_DATE", "Target and relativeTo must both be LocalDate or both be Instant.");
26
+ }
27
+ diffMs = target.epochMilliseconds - relativeTo.epochMilliseconds;
28
+ diffDays = Math.trunc(diffMs / 86400000);
29
+ }
30
+ else {
31
+ throw new ChroneraError("CHRONERA_INVALID_DATE", "Expected Instant or LocalDate.");
32
+ }
33
+ let selectedUnit;
34
+ let value;
35
+ if (options.unit !== undefined) {
36
+ selectedUnit = options.unit;
37
+ switch (selectedUnit) {
38
+ case "second":
39
+ value = Math.trunc(diffMs / 1000);
40
+ break;
41
+ case "minute":
42
+ value = Math.trunc(diffMs / 60000);
43
+ break;
44
+ case "hour":
45
+ value = Math.trunc(diffMs / 3600000);
46
+ break;
47
+ case "day":
48
+ value = diffDays;
49
+ break;
50
+ case "week":
51
+ value = Math.trunc(diffDays / 7);
52
+ break;
53
+ case "month":
54
+ value = Math.trunc(diffDays / 30);
55
+ break;
56
+ case "year":
57
+ value = Math.trunc(diffDays / 365);
58
+ break;
59
+ default:
60
+ throw new ChroneraError("CHRONERA_INCOMPATIBLE_OPTION", `Unsupported unit: "${String(selectedUnit)}".`);
61
+ }
62
+ }
63
+ else {
64
+ const absMs = Math.abs(diffMs);
65
+ const absDays = Math.abs(diffDays);
66
+ if (absMs < 60000) {
67
+ selectedUnit = "second";
68
+ value = Math.trunc(diffMs / 1000);
69
+ }
70
+ else if (absMs < 3600000) {
71
+ selectedUnit = "minute";
72
+ value = Math.trunc(diffMs / 60000);
73
+ }
74
+ else if (absMs < 86400000) {
75
+ selectedUnit = "hour";
76
+ value = Math.trunc(diffMs / 3600000);
77
+ }
78
+ else if (absDays < 7) {
79
+ selectedUnit = "day";
80
+ value = diffDays;
81
+ }
82
+ else if (absDays < 28) {
83
+ selectedUnit = "week";
84
+ value = Math.trunc(diffDays / 7);
85
+ }
86
+ else {
87
+ throw new ChroneraError("CHRONERA_INCOMPATIBLE_OPTION", "Difference exceeds 28 calendar days; caller must provide explicit 'month' or 'year' unit in v1.");
88
+ }
89
+ }
90
+ const rtf = new Intl.RelativeTimeFormat(locale, { numeric });
91
+ return rtf.format(value, selectedUnit);
92
+ }
93
+ //# sourceMappingURL=format-relative.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format-relative.js","sourceRoot":"","sources":["../../src/format/format-relative.ts"],"names":[],"mappings":"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","sourcesContent":["import { ChroneraError } from \"../errors/errors.js\";\nimport { validateAndResolveLocale } from \"../locale/resolve-locale.js\";\nimport { absoluteDayFromGregorianFields } from \"../core/absolute-day.js\";\n\nimport type {\n FormatRelativeOptions,\n Instant,\n LocalDate,\n} from \"../public-types.js\";\n\nexport function formatRelative(\n target: Instant | LocalDate,\n options: Readonly<FormatRelativeOptions>,\n): string {\n if (!options || !options.relativeTo) {\n throw new ChroneraError(\n \"CHRONERA_INCOMPATIBLE_OPTION\",\n \"formatRelative requires an explicit 'relativeTo' reference.\",\n );\n }\n\n const { relativeTo } = options;\n const localeInfo = validateAndResolveLocale(options.locale);\n const locale = localeInfo.baseLocale;\n const numeric = options.numeric ?? \"auto\";\n\n let diffMs: number;\n let diffDays: number;\n\n if (target.kind === \"local-date\") {\n if (relativeTo.kind !== \"local-date\") {\n throw new ChroneraError(\n \"CHRONERA_INVALID_DATE\",\n \"Target and relativeTo must both be LocalDate or both be Instant.\",\n );\n }\n const targetAbs = absoluteDayFromGregorianFields(\n target.year,\n target.month,\n target.day,\n );\n const relAbs = absoluteDayFromGregorianFields(\n relativeTo.year,\n relativeTo.month,\n relativeTo.day,\n );\n diffDays = targetAbs - relAbs;\n diffMs = diffDays * 86400000;\n } else if (target.kind === \"instant\") {\n if (relativeTo.kind !== \"instant\") {\n throw new ChroneraError(\n \"CHRONERA_INVALID_DATE\",\n \"Target and relativeTo must both be LocalDate or both be Instant.\",\n );\n }\n diffMs = target.epochMilliseconds - relativeTo.epochMilliseconds;\n diffDays = Math.trunc(diffMs / 86400000);\n } else {\n throw new ChroneraError(\n \"CHRONERA_INVALID_DATE\",\n \"Expected Instant or LocalDate.\",\n );\n }\n\n let selectedUnit: Intl.RelativeTimeFormatUnit;\n let value: number;\n\n if (options.unit !== undefined) {\n selectedUnit = options.unit;\n switch (selectedUnit) {\n case \"second\":\n value = Math.trunc(diffMs / 1000);\n break;\n case \"minute\":\n value = Math.trunc(diffMs / 60000);\n break;\n case \"hour\":\n value = Math.trunc(diffMs / 3600000);\n break;\n case \"day\":\n value = diffDays;\n break;\n case \"week\":\n value = Math.trunc(diffDays / 7);\n break;\n case \"month\":\n value = Math.trunc(diffDays / 30);\n break;\n case \"year\":\n value = Math.trunc(diffDays / 365);\n break;\n default:\n throw new ChroneraError(\n \"CHRONERA_INCOMPATIBLE_OPTION\",\n `Unsupported unit: \"${String(selectedUnit)}\".`,\n );\n }\n } else {\n const absMs = Math.abs(diffMs);\n const absDays = Math.abs(diffDays);\n\n if (absMs < 60000) {\n selectedUnit = \"second\";\n value = Math.trunc(diffMs / 1000);\n } else if (absMs < 3600000) {\n selectedUnit = \"minute\";\n value = Math.trunc(diffMs / 60000);\n } else if (absMs < 86400000) {\n selectedUnit = \"hour\";\n value = Math.trunc(diffMs / 3600000);\n } else if (absDays < 7) {\n selectedUnit = \"day\";\n value = diffDays;\n } else if (absDays < 28) {\n selectedUnit = \"week\";\n value = Math.trunc(diffDays / 7);\n } else {\n throw new ChroneraError(\n \"CHRONERA_INCOMPATIBLE_OPTION\",\n \"Difference exceeds 28 calendar days; caller must provide explicit 'month' or 'year' unit in v1.\",\n );\n }\n }\n\n const rtf = new Intl.RelativeTimeFormat(locale, { numeric });\n return rtf.format(value, selectedUnit);\n}\n"]}