@northguild/gmt 1.15.0 → 1.16.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 (1113) hide show
  1. package/README.md +852 -272
  2. package/dist/calendar/business/businessDaysBetween.d.ts +37 -0
  3. package/dist/calendar/business/businessDaysBetween.js +89 -0
  4. package/dist/calendar/business/index.d.ts +7 -0
  5. package/dist/calendar/business/index.js +10 -0
  6. package/dist/calendar/business/mergeCalendars.d.ts +33 -0
  7. package/dist/calendar/business/mergeCalendars.js +68 -0
  8. package/dist/calendar/business/nextBusinessDay.d.ts +30 -0
  9. package/dist/calendar/business/nextBusinessDay.js +39 -0
  10. package/dist/calendar/business/previousBusinessDay.d.ts +30 -0
  11. package/dist/calendar/business/previousBusinessDay.js +39 -0
  12. package/dist/calendar/business/rollDate.d.ts +59 -0
  13. package/dist/calendar/business/rollDate.js +116 -0
  14. package/dist/calendar/calculate/bucketRange.d.ts +49 -0
  15. package/dist/calendar/calculate/bucketRange.js +169 -0
  16. package/dist/calendar/calculate/floorToZone.d.ts +42 -0
  17. package/dist/calendar/calculate/floorToZone.js +62 -0
  18. package/dist/calendar/calculate/getFiscalPeriod.d.ts +64 -0
  19. package/dist/calendar/calculate/getFiscalPeriod.js +96 -0
  20. package/dist/calendar/calculate/getIsoWeekDate.d.ts +35 -0
  21. package/dist/calendar/calculate/getIsoWeekDate.js +41 -0
  22. package/dist/calendar/calculate/getOrdinalDate.d.ts +25 -0
  23. package/dist/calendar/calculate/getOrdinalDate.js +28 -0
  24. package/dist/calendar/calculate/getQuarter.d.ts +36 -0
  25. package/dist/calendar/calculate/getQuarter.js +64 -0
  26. package/dist/calendar/calculate/index.d.ts +6 -0
  27. package/dist/calendar/calculate/index.js +6 -0
  28. package/dist/calendar/index.d.ts +4 -0
  29. package/dist/calendar/index.js +5 -0
  30. package/dist/calendar/validate/index.d.ts +4 -0
  31. package/dist/calendar/validate/index.js +4 -0
  32. package/dist/calendar/validate/isValidBusinessCalendar.d.ts +31 -0
  33. package/dist/calendar/validate/isValidBusinessCalendar.js +40 -0
  34. package/dist/calendar/validate/isValidFiscalPattern.d.ts +25 -0
  35. package/dist/calendar/validate/isValidFiscalPattern.js +29 -0
  36. package/dist/calendar/validate/isValidRollConvention.d.ts +28 -0
  37. package/dist/calendar/validate/isValidRollConvention.js +38 -0
  38. package/dist/calendar/validate/isValidZoneBucketUnit.d.ts +31 -0
  39. package/dist/calendar/validate/isValidZoneBucketUnit.js +39 -0
  40. package/dist/duration/calculate/durationAs.d.ts +27 -3
  41. package/dist/duration/calculate/durationAs.js +34 -8
  42. package/dist/duration/calculate/getDurationUnit.d.ts +5 -2
  43. package/dist/duration/calculate/getDurationUnit.js +7 -3
  44. package/dist/duration/compare/compareDurations.d.ts +25 -2
  45. package/dist/duration/compare/compareDurations.js +31 -7
  46. package/dist/duration/format/formatDuration.d.ts +14 -5
  47. package/dist/duration/format/formatDuration.js +47 -11
  48. package/dist/duration/index.d.ts +1 -0
  49. package/dist/duration/index.js +2 -0
  50. package/dist/duration/normalize/normalizeDuration.d.ts +33 -6
  51. package/dist/duration/normalize/normalizeDuration.js +41 -12
  52. package/dist/duration/parse/parseDuration.js +4 -0
  53. package/dist/index.d.ts +5 -0
  54. package/dist/index.js +5 -0
  55. package/dist/instant/convert/classifyLocal.d.ts +50 -0
  56. package/dist/instant/convert/classifyLocal.js +60 -0
  57. package/dist/instant/convert/fromOffsetInstant.d.ts +47 -0
  58. package/dist/instant/convert/fromOffsetInstant.js +99 -0
  59. package/dist/instant/convert/index.d.ts +4 -0
  60. package/dist/instant/convert/index.js +4 -0
  61. package/dist/instant/convert/resolveLocal.d.ts +40 -0
  62. package/dist/instant/convert/resolveLocal.js +76 -0
  63. package/dist/instant/convert/toOffsetInstant.d.ts +73 -0
  64. package/dist/instant/convert/toOffsetInstant.js +185 -0
  65. package/dist/instant/index.d.ts +2 -0
  66. package/dist/instant/index.js +3 -0
  67. package/dist/internal/adjustZonedBusinessDays.js +9 -7
  68. package/dist/internal/businessCalendar.d.ts +46 -0
  69. package/dist/internal/businessCalendar.js +230 -0
  70. package/dist/internal/businessDayValues.d.ts +20 -0
  71. package/dist/internal/businessDayValues.js +54 -0
  72. package/dist/internal/calendarDatePairPolicy.d.ts +10 -12
  73. package/dist/internal/calendarDatePairPolicy.js +13 -19
  74. package/dist/internal/calendarDateString.d.ts +32 -58
  75. package/dist/internal/calendarDateString.js +51 -93
  76. package/dist/internal/calendarSystemIds.d.ts +26 -2
  77. package/dist/internal/calendarSystemIds.js +57 -51
  78. package/dist/internal/calendarValueOfDate.d.ts +10 -12
  79. package/dist/internal/calendarValueOfDate.js +22 -20
  80. package/dist/internal/calendarValueOfZoned.d.ts +14 -17
  81. package/dist/internal/calendarValueOfZoned.js +25 -25
  82. package/dist/internal/calendarZonedPairPolicy.d.ts +11 -18
  83. package/dist/internal/calendarZonedPairPolicy.js +14 -25
  84. package/dist/internal/calendarZonedString.d.ts +41 -65
  85. package/dist/internal/calendarZonedString.js +52 -101
  86. package/dist/internal/compareUnixEpochs.d.ts +14 -0
  87. package/dist/internal/compareUnixEpochs.js +25 -0
  88. package/dist/internal/dateTimeUnitHelpers.d.ts +18 -0
  89. package/dist/internal/dateTimeUnitHelpers.js +27 -0
  90. package/dist/internal/dateUnitHelpers.d.ts +39 -1
  91. package/dist/internal/dateUnitHelpers.js +73 -11
  92. package/dist/internal/defaultFractionalDigits.d.ts +14 -0
  93. package/dist/internal/defaultFractionalDigits.js +23 -0
  94. package/dist/internal/differenceRecord.d.ts +32 -0
  95. package/dist/internal/differenceRecord.js +79 -0
  96. package/dist/internal/divisionBoundary.d.ts +19 -0
  97. package/dist/internal/divisionBoundary.js +23 -0
  98. package/dist/internal/durationUntilString.d.ts +1 -1
  99. package/dist/internal/durationUntilString.js +10 -2
  100. package/dist/internal/englishCalendarNames.d.ts +11 -0
  101. package/dist/internal/englishCalendarNames.js +21 -1
  102. package/dist/internal/epochNanoseconds.d.ts +27 -0
  103. package/dist/internal/epochNanoseconds.js +31 -0
  104. package/dist/internal/fiscalCalendar.d.ts +36 -0
  105. package/dist/internal/fiscalCalendar.js +86 -0
  106. package/dist/internal/floorDivide.d.ts +15 -0
  107. package/dist/internal/floorDivide.js +18 -0
  108. package/dist/internal/foreignEpochs.d.ts +134 -0
  109. package/dist/internal/foreignEpochs.js +139 -0
  110. package/dist/internal/formatCalendarDays.d.ts +28 -0
  111. package/dist/internal/formatCalendarDays.js +49 -0
  112. package/dist/internal/formatDateInCalendar.d.ts +14 -39
  113. package/dist/internal/formatDateInCalendar.js +16 -47
  114. package/dist/internal/formatRelativeDuration.d.ts +27 -0
  115. package/dist/internal/formatRelativeDuration.js +45 -0
  116. package/dist/internal/getLocaleFirstDayOfWeek.d.ts +9 -6
  117. package/dist/internal/getLocaleFirstDayOfWeek.js +9 -10
  118. package/dist/internal/getLocaleWeekYearBounds.d.ts +17 -9
  119. package/dist/internal/getLocaleWeekYearBounds.js +45 -26
  120. package/dist/internal/getLocaleWeekendDays.d.ts +9 -18
  121. package/dist/internal/getLocaleWeekendDays.js +9 -5
  122. package/dist/internal/halfOpenIntervals.d.ts +102 -0
  123. package/dist/internal/halfOpenIntervals.js +180 -0
  124. package/dist/internal/hasCalendarAnnotation.d.ts +20 -20
  125. package/dist/internal/hasCalendarAnnotation.js +23 -21
  126. package/dist/internal/hourDurationString.d.ts +16 -0
  127. package/dist/internal/hourDurationString.js +47 -0
  128. package/dist/internal/httpDateFields.d.ts +24 -0
  129. package/dist/internal/httpDateFields.js +86 -0
  130. package/dist/internal/index.d.ts +28 -9
  131. package/dist/internal/index.js +28 -9
  132. package/dist/internal/instantFormatOptions.d.ts +43 -0
  133. package/dist/internal/instantFormatOptions.js +99 -0
  134. package/dist/internal/instantIntervalText.d.ts +20 -0
  135. package/dist/internal/instantIntervalText.js +25 -0
  136. package/dist/internal/instantNanoseconds.d.ts +25 -0
  137. package/dist/internal/instantNanoseconds.js +41 -0
  138. package/dist/internal/intervalCountHelpers.d.ts +16 -10
  139. package/dist/internal/intervalCountHelpers.js +1 -31
  140. package/dist/internal/intervalNanoseconds.d.ts +47 -0
  141. package/dist/internal/intervalNanoseconds.js +86 -0
  142. package/dist/internal/isObject.d.ts +26 -0
  143. package/dist/internal/isObject.js +30 -0
  144. package/dist/internal/isoStringBody.d.ts +40 -0
  145. package/dist/internal/isoStringBody.js +85 -0
  146. package/dist/internal/joinDateTimeConnector.d.ts +1 -1
  147. package/dist/internal/localeWeekInfo.d.ts +34 -0
  148. package/dist/internal/localeWeekInfo.js +27 -0
  149. package/dist/internal/maxPieces.d.ts +41 -0
  150. package/dist/internal/maxPieces.js +53 -0
  151. package/dist/internal/measureNearRangeEnd.d.ts +26 -0
  152. package/dist/internal/measureNearRangeEnd.js +47 -0
  153. package/dist/internal/monthGridWeekRow.d.ts +4 -1
  154. package/dist/internal/monthGridWeekRow.js +3 -0
  155. package/dist/internal/normalizeTimeZone.d.ts +17 -10
  156. package/dist/internal/normalizeTimeZone.js +25 -15
  157. package/dist/internal/patternToken.d.ts +2 -1
  158. package/dist/internal/patternToken.js +10 -4
  159. package/dist/internal/plainDateAdd.d.ts +20 -0
  160. package/dist/internal/plainDateAdd.js +42 -0
  161. package/dist/internal/plainDateUntil.d.ts +21 -0
  162. package/dist/internal/plainDateUntil.js +48 -0
  163. package/dist/internal/plainFormatOptions.d.ts +59 -0
  164. package/dist/internal/plainFormatOptions.js +165 -0
  165. package/dist/internal/resolveDateTimeUnit.d.ts +4 -1
  166. package/dist/internal/resolveDateTimeUnit.js +2 -12
  167. package/dist/internal/resolveDurationRelativeTo.d.ts +28 -22
  168. package/dist/internal/resolveDurationRelativeTo.js +69 -25
  169. package/dist/internal/resolveDurationUnit.d.ts +4 -1
  170. package/dist/internal/resolveDurationUnit.js +2 -11
  171. package/dist/internal/resolveLocale.d.ts +37 -0
  172. package/dist/internal/resolveLocale.js +59 -0
  173. package/dist/internal/resolveManualRoundingOptions.d.ts +23 -0
  174. package/dist/internal/resolveManualRoundingOptions.js +39 -0
  175. package/dist/internal/resolveMinimalDaysInFirstWeek.d.ts +19 -0
  176. package/dist/internal/resolveMinimalDaysInFirstWeek.js +28 -0
  177. package/dist/internal/resolveOverflow.d.ts +6 -0
  178. package/dist/internal/resolveOverflow.js +7 -1
  179. package/dist/internal/resolveReadingTimeZone.d.ts +11 -0
  180. package/dist/internal/resolveReadingTimeZone.js +18 -0
  181. package/dist/internal/resolveUnixIntervalPair.d.ts +30 -0
  182. package/dist/internal/resolveUnixIntervalPair.js +53 -0
  183. package/dist/internal/resolveWeekStartsOn.d.ts +12 -0
  184. package/dist/internal/resolveWeekStartsOn.js +18 -0
  185. package/dist/internal/rfc5322DateTime.d.ts +26 -0
  186. package/dist/internal/rfc5322DateTime.js +176 -0
  187. package/dist/internal/splitStep.d.ts +81 -0
  188. package/dist/internal/splitStep.js +182 -0
  189. package/dist/internal/startOrEndOfUnix.d.ts +26 -0
  190. package/dist/internal/startOrEndOfUnix.js +47 -0
  191. package/dist/{utc/calculate → internal}/startOrEndOfUtc.d.ts +8 -4
  192. package/dist/{utc/calculate → internal}/startOrEndOfUtc.js +30 -26
  193. package/dist/internal/startOrEndOfZoned.d.ts +22 -0
  194. package/dist/internal/startOrEndOfZoned.js +49 -0
  195. package/dist/internal/temporalCompat/calendarDateArithmetic.d.ts +33 -0
  196. package/dist/internal/temporalCompat/calendarDateArithmetic.js +199 -0
  197. package/dist/internal/temporalCompat/calendarDateFromFields.d.ts +36 -0
  198. package/dist/internal/temporalCompat/calendarDateFromFields.js +120 -0
  199. package/dist/internal/temporalCompat/calendarFields.d.ts +25 -0
  200. package/dist/internal/temporalCompat/calendarFields.js +131 -0
  201. package/dist/internal/temporalCompat/capabilities.d.ts +28 -0
  202. package/dist/internal/temporalCompat/capabilities.js +74 -0
  203. package/dist/internal/temporalCompat/fieldSearch.d.ts +21 -0
  204. package/dist/internal/temporalCompat/fieldSearch.js +83 -0
  205. package/dist/internal/temporalCompat/fixedDay.d.ts +25 -0
  206. package/dist/internal/temporalCompat/fixedDay.js +45 -0
  207. package/dist/internal/temporalCompat/hebrewArithmetic.d.ts +19 -0
  208. package/dist/internal/temporalCompat/hebrewArithmetic.js +150 -0
  209. package/dist/internal/temporalCompat/index.d.ts +4 -0
  210. package/dist/internal/temporalCompat/index.js +5 -0
  211. package/dist/internal/temporalCompat/indianArithmetic.d.ts +16 -0
  212. package/dist/internal/temporalCompat/indianArithmetic.js +87 -0
  213. package/dist/internal/temporalCompat/largeMonthSpan.d.ts +19 -0
  214. package/dist/internal/temporalCompat/largeMonthSpan.js +199 -0
  215. package/dist/internal/temporalCompat/nonIsoArithmetic.d.ts +59 -0
  216. package/dist/internal/temporalCompat/nonIsoArithmetic.js +220 -0
  217. package/dist/internal/temporalCompat/readArithmeticModel.d.ts +3 -0
  218. package/dist/internal/temporalCompat/readArithmeticModel.js +284 -0
  219. package/dist/internal/temporalCompat/repros.d.ts +31 -0
  220. package/dist/internal/temporalCompat/repros.js +556 -0
  221. package/dist/internal/toInstantFromUtc.d.ts +10 -0
  222. package/dist/internal/toInstantFromUtc.js +19 -0
  223. package/dist/internal/unixEpochValue.d.ts +166 -0
  224. package/dist/internal/unixEpochValue.js +245 -0
  225. package/dist/internal/unixFormatReference.d.ts +18 -0
  226. package/dist/internal/unixFormatReference.js +44 -0
  227. package/dist/internal/unixZonedDateTime.d.ts +22 -0
  228. package/dist/internal/unixZonedDateTime.js +32 -0
  229. package/dist/internal/utcOffsetString.d.ts +39 -0
  230. package/dist/internal/utcOffsetString.js +75 -0
  231. package/dist/internal/utcZonedDateTime.d.ts +16 -0
  232. package/dist/internal/utcZonedDateTime.js +28 -0
  233. package/dist/internal/zonedBucket.d.ts +91 -0
  234. package/dist/internal/zonedBucket.js +441 -0
  235. package/dist/internal/zonedFormatReference.d.ts +15 -0
  236. package/dist/internal/zonedFormatReference.js +24 -0
  237. package/dist/internal/zonedLocalDates.d.ts +15 -0
  238. package/dist/internal/zonedLocalDates.js +58 -0
  239. package/dist/internal/zonedNowUnitValue.d.ts +24 -0
  240. package/dist/internal/zonedNowUnitValue.js +58 -0
  241. package/dist/internal/zonedWallClock.d.ts +84 -0
  242. package/dist/internal/zonedWallClock.js +427 -0
  243. package/dist/internal/zonedWallClockDifference.d.ts +92 -0
  244. package/dist/internal/zonedWallClockDifference.js +1173 -0
  245. package/dist/internal/zonedWallClockOperations.d.ts +132 -0
  246. package/dist/internal/zonedWallClockOperations.js +553 -0
  247. package/dist/internal/zonelessCalendarDate.d.ts +12 -0
  248. package/dist/internal/zonelessCalendarDate.js +22 -0
  249. package/dist/interval/calculate/clampInterval.d.ts +22 -0
  250. package/dist/interval/calculate/clampInterval.js +31 -0
  251. package/dist/interval/calculate/index.d.ts +6 -0
  252. package/dist/interval/calculate/index.js +6 -0
  253. package/dist/interval/calculate/intersectIntervals.d.ts +23 -0
  254. package/dist/interval/calculate/intersectIntervals.js +43 -0
  255. package/dist/interval/calculate/mergeIntervals.d.ts +28 -0
  256. package/dist/interval/calculate/mergeIntervals.js +44 -0
  257. package/dist/interval/calculate/splitIntervalAt.d.ts +28 -0
  258. package/dist/interval/calculate/splitIntervalAt.js +63 -0
  259. package/dist/interval/calculate/subtractIntervals.d.ts +31 -0
  260. package/dist/interval/calculate/subtractIntervals.js +64 -0
  261. package/dist/interval/calculate/sumIntervals.d.ts +26 -0
  262. package/dist/interval/calculate/sumIntervals.js +40 -0
  263. package/dist/interval/compare/index.d.ts +2 -0
  264. package/dist/interval/compare/index.js +2 -0
  265. package/dist/interval/compare/intervalContains.d.ts +25 -0
  266. package/dist/interval/compare/intervalContains.js +39 -0
  267. package/dist/interval/compare/intervalsOverlap.d.ts +28 -0
  268. package/dist/interval/compare/intervalsOverlap.js +42 -0
  269. package/dist/interval/index.d.ts +4 -0
  270. package/dist/interval/index.js +5 -0
  271. package/dist/interval/validate/index.d.ts +1 -0
  272. package/dist/interval/validate/index.js +1 -0
  273. package/dist/interval/validate/isValidInterval.d.ts +29 -0
  274. package/dist/interval/validate/isValidInterval.js +38 -0
  275. package/dist/plain/calculate/addBusinessDays.d.ts +26 -9
  276. package/dist/plain/calculate/addBusinessDays.js +29 -21
  277. package/dist/plain/calculate/addDate.d.ts +9 -8
  278. package/dist/plain/calculate/addDate.js +35 -22
  279. package/dist/plain/calculate/addDateTime.js +24 -10
  280. package/dist/plain/calculate/addTime.d.ts +5 -8
  281. package/dist/plain/calculate/addTime.js +23 -16
  282. package/dist/plain/calculate/clampDate.js +3 -3
  283. package/dist/plain/calculate/closestDateTo.d.ts +11 -7
  284. package/dist/plain/calculate/closestDateTo.js +36 -24
  285. package/dist/plain/calculate/cycleDate.d.ts +1 -1
  286. package/dist/plain/calculate/cycleDate.js +10 -3
  287. package/dist/plain/calculate/cycleDateTime.d.ts +1 -1
  288. package/dist/plain/calculate/cycleDateTime.js +10 -3
  289. package/dist/plain/calculate/cycleTime.d.ts +6 -8
  290. package/dist/plain/calculate/cycleTime.js +15 -9
  291. package/dist/plain/calculate/diffDate.d.ts +31 -14
  292. package/dist/plain/calculate/diffDate.js +73 -38
  293. package/dist/plain/calculate/diffDateAsDuration.d.ts +13 -8
  294. package/dist/plain/calculate/diffDateAsDuration.js +22 -9
  295. package/dist/plain/calculate/diffDateTime.d.ts +17 -5
  296. package/dist/plain/calculate/diffDateTime.js +67 -28
  297. package/dist/plain/calculate/diffDateTimeAsDuration.d.ts +2 -2
  298. package/dist/plain/calculate/diffDateTimeAsDuration.js +10 -3
  299. package/dist/plain/calculate/diffTime.d.ts +18 -5
  300. package/dist/plain/calculate/diffTime.js +68 -27
  301. package/dist/plain/calculate/endOfDate.d.ts +10 -2
  302. package/dist/plain/calculate/endOfDate.js +52 -27
  303. package/dist/plain/calculate/endOfDateTime.d.ts +17 -2
  304. package/dist/plain/calculate/endOfDateTime.js +126 -103
  305. package/dist/plain/calculate/endOfTime.d.ts +16 -2
  306. package/dist/plain/calculate/endOfTime.js +77 -59
  307. package/dist/plain/calculate/getLargestDateDurationUnit.d.ts +13 -5
  308. package/dist/plain/calculate/getLargestDateDurationUnit.js +26 -10
  309. package/dist/plain/calculate/getLargestDateTimeDurationUnit.d.ts +13 -6
  310. package/dist/plain/calculate/getLargestDateTimeDurationUnit.js +37 -22
  311. package/dist/plain/calculate/getLargestTimeDurationUnit.d.ts +13 -6
  312. package/dist/plain/calculate/getLargestTimeDurationUnit.js +33 -18
  313. package/dist/plain/calculate/getLocaleDayOfWeek.d.ts +8 -4
  314. package/dist/plain/calculate/getLocaleDayOfWeek.js +8 -3
  315. package/dist/plain/calculate/getLocaleEndOfWeek.d.ts +8 -4
  316. package/dist/plain/calculate/getLocaleEndOfWeek.js +8 -3
  317. package/dist/plain/calculate/getLocaleStartOfWeek.d.ts +8 -4
  318. package/dist/plain/calculate/getLocaleStartOfWeek.js +8 -3
  319. package/dist/plain/calculate/getLocaleWeekYear.d.ts +29 -19
  320. package/dist/plain/calculate/getLocaleWeekYear.js +48 -28
  321. package/dist/plain/calculate/getWeekNumber.d.ts +21 -2
  322. package/dist/plain/calculate/getWeekNumber.js +33 -12
  323. package/dist/plain/calculate/getWeekOfMonth.d.ts +4 -2
  324. package/dist/plain/calculate/getWeekOfMonth.js +8 -3
  325. package/dist/plain/calculate/getWeeksInLocaleWeekYear.d.ts +25 -14
  326. package/dist/plain/calculate/getWeeksInLocaleWeekYear.js +45 -25
  327. package/dist/plain/calculate/getWeeksInMonth.d.ts +4 -2
  328. package/dist/plain/calculate/getWeeksInMonth.js +8 -3
  329. package/dist/plain/calculate/getWeeksInYear.d.ts +5 -4
  330. package/dist/plain/calculate/getWeeksInYear.js +9 -14
  331. package/dist/plain/calculate/maxDate.js +19 -12
  332. package/dist/plain/calculate/maxDateTime.js +19 -12
  333. package/dist/plain/calculate/maxTime.js +19 -12
  334. package/dist/plain/calculate/minDate.js +19 -12
  335. package/dist/plain/calculate/minDateTime.js +19 -12
  336. package/dist/plain/calculate/minTime.js +19 -12
  337. package/dist/plain/calculate/nextWeekday.js +5 -0
  338. package/dist/plain/calculate/previousWeekday.js +5 -0
  339. package/dist/plain/calculate/roundDate.d.ts +23 -5
  340. package/dist/plain/calculate/roundDate.js +88 -46
  341. package/dist/plain/calculate/roundDateTime.d.ts +27 -3
  342. package/dist/plain/calculate/roundDateTime.js +128 -69
  343. package/dist/plain/calculate/roundTime.d.ts +8 -1
  344. package/dist/plain/calculate/roundTime.js +32 -17
  345. package/dist/plain/calculate/setDate.js +4 -0
  346. package/dist/plain/calculate/setDateTime.js +4 -0
  347. package/dist/plain/calculate/setTime.d.ts +1 -1
  348. package/dist/plain/calculate/setTime.js +5 -1
  349. package/dist/plain/calculate/sortDateTimes.js +17 -10
  350. package/dist/plain/calculate/sortDates.js +17 -10
  351. package/dist/plain/calculate/sortTimes.js +17 -10
  352. package/dist/plain/calculate/startOfDate.d.ts +7 -2
  353. package/dist/plain/calculate/startOfDate.js +52 -27
  354. package/dist/plain/calculate/startOfDateTime.d.ts +5 -2
  355. package/dist/plain/calculate/startOfDateTime.js +81 -62
  356. package/dist/plain/calculate/startOfQuarterForDateTime.d.ts +2 -0
  357. package/dist/plain/calculate/startOfQuarterForDateTime.js +12 -1
  358. package/dist/plain/calculate/startOfTime.d.ts +15 -2
  359. package/dist/plain/calculate/startOfTime.js +33 -37
  360. package/dist/plain/calculate/subtractBusinessDays.d.ts +25 -10
  361. package/dist/plain/calculate/subtractBusinessDays.js +28 -22
  362. package/dist/plain/calculate/subtractDate.d.ts +8 -7
  363. package/dist/plain/calculate/subtractDate.js +35 -21
  364. package/dist/plain/calculate/subtractDateTime.js +24 -10
  365. package/dist/plain/calculate/subtractTime.d.ts +5 -8
  366. package/dist/plain/calculate/subtractTime.js +23 -16
  367. package/dist/plain/chop/index.d.ts +0 -1
  368. package/dist/plain/chop/index.js +0 -1
  369. package/dist/plain/compare/areDateTimesEqualBy.d.ts +10 -5
  370. package/dist/plain/compare/areDateTimesEqualBy.js +35 -10
  371. package/dist/plain/compare/areDatesEqualBy.d.ts +10 -3
  372. package/dist/plain/compare/areDatesEqualBy.js +41 -14
  373. package/dist/plain/compare/isBetweenDate.js +32 -16
  374. package/dist/plain/compare/isBetweenDateTime.js +34 -18
  375. package/dist/plain/compare/isBetweenTime.js +32 -16
  376. package/dist/plain/compare/isBusinessDay.d.ts +25 -11
  377. package/dist/plain/compare/isBusinessDay.js +36 -15
  378. package/dist/plain/compare/isThisUnit.d.ts +13 -4
  379. package/dist/plain/compare/isThisUnit.js +33 -13
  380. package/dist/plain/compare/isWeekend.d.ts +8 -4
  381. package/dist/plain/compare/isWeekend.js +7 -3
  382. package/dist/plain/convert/convertDateToCalendar.d.ts +34 -33
  383. package/dist/plain/convert/convertDateToCalendar.js +41 -40
  384. package/dist/plain/format/formatCalendar.d.ts +12 -6
  385. package/dist/plain/format/formatCalendar.js +47 -25
  386. package/dist/plain/format/formatDate.d.ts +21 -4
  387. package/dist/plain/format/formatDate.js +37 -5
  388. package/dist/plain/format/formatDateRange.d.ts +17 -4
  389. package/dist/plain/format/formatDateRange.js +29 -5
  390. package/dist/plain/format/formatDateTime.d.ts +22 -4
  391. package/dist/plain/format/formatDateTime.js +31 -5
  392. package/dist/plain/format/formatDateTimeRange.d.ts +20 -4
  393. package/dist/plain/format/formatDateTimeRange.js +29 -5
  394. package/dist/plain/format/formatDateTimeToParts.d.ts +32 -6
  395. package/dist/plain/format/formatDateTimeToParts.js +40 -14
  396. package/dist/plain/format/formatDateToParts.d.ts +24 -3
  397. package/dist/plain/format/formatDateToParts.js +36 -11
  398. package/dist/plain/format/formatRelativeDate.d.ts +7 -3
  399. package/dist/plain/format/formatRelativeDate.js +39 -24
  400. package/dist/plain/format/formatRelativeDateTime.d.ts +15 -6
  401. package/dist/plain/format/formatRelativeDateTime.js +35 -33
  402. package/dist/plain/format/formatRelativeTime.d.ts +8 -4
  403. package/dist/plain/format/formatRelativeTime.js +36 -21
  404. package/dist/plain/format/formatSql.d.ts +15 -10
  405. package/dist/plain/format/formatSql.js +20 -11
  406. package/dist/plain/format/formatTime.d.ts +18 -4
  407. package/dist/plain/format/formatTime.js +32 -5
  408. package/dist/plain/get/getNowUnit.d.ts +3 -0
  409. package/dist/plain/get/getNowUnit.js +14 -29
  410. package/dist/plain/index.js +1 -1
  411. package/dist/plain/interval/intervalAbutsDate.d.ts +12 -7
  412. package/dist/plain/interval/intervalAbutsDate.js +15 -19
  413. package/dist/plain/interval/intervalAbutsDateTime.d.ts +9 -7
  414. package/dist/plain/interval/intervalAbutsDateTime.js +17 -23
  415. package/dist/plain/interval/intervalAbutsTime.d.ts +11 -5
  416. package/dist/plain/interval/intervalAbutsTime.js +19 -21
  417. package/dist/plain/interval/intervalContainsDate.d.ts +17 -10
  418. package/dist/plain/interval/intervalContainsDate.js +20 -15
  419. package/dist/plain/interval/intervalContainsDateTime.d.ts +16 -11
  420. package/dist/plain/interval/intervalContainsDateTime.js +24 -20
  421. package/dist/plain/interval/intervalContainsTime.d.ts +20 -10
  422. package/dist/plain/interval/intervalContainsTime.js +28 -19
  423. package/dist/plain/interval/intervalCountDate.d.ts +13 -8
  424. package/dist/plain/interval/intervalCountDate.js +46 -14
  425. package/dist/plain/interval/intervalCountDateTime.d.ts +6 -4
  426. package/dist/plain/interval/intervalCountDateTime.js +63 -18
  427. package/dist/plain/interval/intervalCountTime.d.ts +3 -4
  428. package/dist/plain/interval/intervalCountTime.js +9 -9
  429. package/dist/plain/interval/intervalDifferenceDate.d.ts +13 -6
  430. package/dist/plain/interval/intervalDifferenceDate.js +19 -32
  431. package/dist/plain/interval/intervalDifferenceDateTime.d.ts +10 -4
  432. package/dist/plain/interval/intervalDifferenceDateTime.js +21 -27
  433. package/dist/plain/interval/intervalDifferenceTime.d.ts +11 -4
  434. package/dist/plain/interval/intervalDifferenceTime.js +22 -27
  435. package/dist/plain/interval/intervalDivideEquallyDate.d.ts +16 -4
  436. package/dist/plain/interval/intervalDivideEquallyDate.js +57 -33
  437. package/dist/plain/interval/intervalDivideEquallyDateTime.d.ts +16 -4
  438. package/dist/plain/interval/intervalDivideEquallyDateTime.js +67 -31
  439. package/dist/plain/interval/intervalDivideEquallyTime.d.ts +16 -4
  440. package/dist/plain/interval/intervalDivideEquallyTime.js +58 -31
  441. package/dist/plain/interval/intervalEngulfsDate.d.ts +16 -9
  442. package/dist/plain/interval/intervalEngulfsDate.js +19 -12
  443. package/dist/plain/interval/intervalEngulfsDateTime.d.ts +16 -11
  444. package/dist/plain/interval/intervalEngulfsDateTime.js +24 -18
  445. package/dist/plain/interval/intervalEngulfsTime.d.ts +18 -8
  446. package/dist/plain/interval/intervalEngulfsTime.js +26 -15
  447. package/dist/plain/interval/intervalFromDurationDate.d.ts +5 -4
  448. package/dist/plain/interval/intervalFromDurationDate.js +11 -8
  449. package/dist/plain/interval/intervalFromDurationDateTime.js +4 -0
  450. package/dist/plain/interval/intervalFromDurationTime.d.ts +10 -12
  451. package/dist/plain/interval/intervalFromDurationTime.js +28 -17
  452. package/dist/plain/interval/intervalIntersectionDate.d.ts +9 -4
  453. package/dist/plain/interval/intervalIntersectionDate.js +14 -9
  454. package/dist/plain/interval/intervalIntersectionDateTime.d.ts +9 -4
  455. package/dist/plain/interval/intervalIntersectionDateTime.js +19 -13
  456. package/dist/plain/interval/intervalIntersectionTime.d.ts +7 -3
  457. package/dist/plain/interval/intervalIntersectionTime.js +17 -12
  458. package/dist/plain/interval/intervalLengthDate.d.ts +9 -6
  459. package/dist/plain/interval/intervalLengthDate.js +40 -8
  460. package/dist/plain/interval/intervalLengthDateTime.js +2 -2
  461. package/dist/plain/interval/intervalOverlappingDaysDate.d.ts +16 -17
  462. package/dist/plain/interval/intervalOverlappingDaysDate.js +30 -30
  463. package/dist/plain/interval/intervalOverlappingDaysDateTime.d.ts +7 -12
  464. package/dist/plain/interval/intervalOverlappingDaysDateTime.js +24 -24
  465. package/dist/plain/interval/intervalSplitAtDate.d.ts +10 -5
  466. package/dist/plain/interval/intervalSplitAtDate.js +48 -36
  467. package/dist/plain/interval/intervalSplitAtDateTime.d.ts +9 -4
  468. package/dist/plain/interval/intervalSplitAtDateTime.js +44 -32
  469. package/dist/plain/interval/intervalSplitAtTime.d.ts +9 -4
  470. package/dist/plain/interval/intervalSplitAtTime.js +44 -32
  471. package/dist/plain/interval/intervalUnionDate.d.ts +14 -6
  472. package/dist/plain/interval/intervalUnionDate.js +19 -11
  473. package/dist/plain/interval/intervalUnionDateTime.d.ts +12 -5
  474. package/dist/plain/interval/intervalUnionDateTime.js +22 -14
  475. package/dist/plain/interval/intervalUnionTime.d.ts +10 -3
  476. package/dist/plain/interval/intervalUnionTime.js +20 -12
  477. package/dist/plain/interval/intervalXorAllDate.d.ts +11 -10
  478. package/dist/plain/interval/intervalXorAllDate.js +37 -59
  479. package/dist/plain/interval/intervalXorAllDateTime.d.ts +7 -5
  480. package/dist/plain/interval/intervalXorAllDateTime.js +28 -48
  481. package/dist/plain/interval/intervalXorAllTime.d.ts +8 -4
  482. package/dist/plain/interval/intervalXorAllTime.js +29 -47
  483. package/dist/plain/interval/intervalXorDate.d.ts +10 -9
  484. package/dist/plain/interval/intervalXorDate.js +19 -54
  485. package/dist/plain/interval/intervalXorDateTime.d.ts +9 -7
  486. package/dist/plain/interval/intervalXorDateTime.js +23 -50
  487. package/dist/plain/interval/intervalXorTime.d.ts +8 -7
  488. package/dist/plain/interval/intervalXorTime.js +22 -50
  489. package/dist/plain/interval/intervalsOverlapDate.d.ts +14 -7
  490. package/dist/plain/interval/intervalsOverlapDate.js +17 -10
  491. package/dist/plain/interval/intervalsOverlapDateTime.d.ts +12 -7
  492. package/dist/plain/interval/intervalsOverlapDateTime.js +20 -14
  493. package/dist/plain/interval/intervalsOverlapTime.d.ts +10 -5
  494. package/dist/plain/interval/intervalsOverlapTime.js +18 -12
  495. package/dist/plain/interval/mergeIntervalsDate.d.ts +9 -5
  496. package/dist/plain/interval/mergeIntervalsDate.js +37 -38
  497. package/dist/plain/interval/mergeIntervalsDateTime.d.ts +7 -3
  498. package/dist/plain/interval/mergeIntervalsDateTime.js +31 -32
  499. package/dist/plain/interval/mergeIntervalsTime.d.ts +7 -3
  500. package/dist/plain/interval/mergeIntervalsTime.js +31 -31
  501. package/dist/plain/interval/splitIntervalByUnitDate.d.ts +26 -6
  502. package/dist/plain/interval/splitIntervalByUnitDate.js +76 -43
  503. package/dist/plain/interval/splitIntervalByUnitDateTime.d.ts +22 -2
  504. package/dist/plain/interval/splitIntervalByUnitDateTime.js +65 -39
  505. package/dist/plain/interval/splitIntervalByUnitTime.d.ts +18 -2
  506. package/dist/plain/interval/splitIntervalByUnitTime.js +76 -39
  507. package/dist/plain/interval/validate/isValidDateInterval.d.ts +4 -2
  508. package/dist/plain/interval/validate/isValidDateInterval.js +4 -2
  509. package/dist/plain/interval/validate/isValidDateTimeInterval.d.ts +5 -0
  510. package/dist/plain/interval/validate/isValidDateTimeInterval.js +7 -2
  511. package/dist/plain/interval/validate/isValidTimeInterval.d.ts +5 -0
  512. package/dist/plain/interval/validate/isValidTimeInterval.js +8 -18
  513. package/dist/plain/locale/getLocaleEraNames.d.ts +14 -4
  514. package/dist/plain/locale/getLocaleEraNames.js +56 -41
  515. package/dist/plain/locale/getLocaleMeridiems.d.ts +7 -4
  516. package/dist/plain/locale/getLocaleMeridiems.js +28 -22
  517. package/dist/plain/locale/getLocaleMonthNames.d.ts +14 -4
  518. package/dist/plain/locale/getLocaleMonthNames.js +34 -19
  519. package/dist/plain/locale/getLocaleWeekdayNames.d.ts +14 -7
  520. package/dist/plain/locale/getLocaleWeekdayNames.js +40 -22
  521. package/dist/plain/map/mapDatesInRange.d.ts +18 -1
  522. package/dist/plain/map/mapDatesInRange.js +53 -17
  523. package/dist/plain/parse/parseDateTimeWithPattern.d.ts +3 -2
  524. package/dist/plain/parse/parseDateTimeWithPattern.js +30 -24
  525. package/dist/plain/parse/parseDateWithPattern.d.ts +3 -2
  526. package/dist/plain/parse/parseDateWithPattern.js +22 -16
  527. package/dist/plain/parse/parseMicrosecondFromDateTime.d.ts +2 -1
  528. package/dist/plain/parse/parseMicrosecondFromDateTime.js +2 -1
  529. package/dist/plain/parse/parseMicrosecondFromTime.d.ts +2 -1
  530. package/dist/plain/parse/parseMicrosecondFromTime.js +2 -1
  531. package/dist/plain/parse/parseNanosecondFromDateTime.d.ts +2 -1
  532. package/dist/plain/parse/parseNanosecondFromDateTime.js +2 -1
  533. package/dist/plain/parse/parseNanosecondFromTime.d.ts +2 -1
  534. package/dist/plain/parse/parseNanosecondFromTime.js +2 -1
  535. package/dist/plain/parse/parseSql.d.ts +15 -12
  536. package/dist/plain/parse/parseSql.js +16 -13
  537. package/dist/plain/parse/parseTimeWithPattern.d.ts +3 -2
  538. package/dist/plain/parse/parseTimeWithPattern.js +27 -21
  539. package/dist/plain/parse/parseUnitFromDate.d.ts +9 -2
  540. package/dist/plain/parse/parseUnitFromDate.js +39 -19
  541. package/dist/plain/parse/parseUnitFromDateTime.d.ts +11 -3
  542. package/dist/plain/parse/parseUnitFromDateTime.js +54 -28
  543. package/dist/plain/parse/parseUnitFromTime.d.ts +9 -3
  544. package/dist/plain/parse/parseUnitFromTime.js +13 -3
  545. package/dist/plain/parse/parseWeekFromDate.d.ts +5 -0
  546. package/dist/plain/parse/parseWeekFromDate.js +24 -5
  547. package/dist/plain/parse/parseWeekFromDateTime.d.ts +5 -0
  548. package/dist/plain/parse/parseWeekFromDateTime.js +26 -5
  549. package/dist/plain/validate/isLeapSecond.d.ts +27 -9
  550. package/dist/plain/validate/isLeapSecond.js +30 -9
  551. package/dist/plain/validate/isLeapYear.d.ts +7 -1
  552. package/dist/plain/validate/isLeapYear.js +10 -1
  553. package/dist/plain/validate/isValidCalendarDate.d.ts +37 -6
  554. package/dist/plain/validate/isValidCalendarDate.js +37 -6
  555. package/dist/plain/validate/isValidDate.d.ts +9 -1
  556. package/dist/plain/validate/isValidDate.js +14 -5
  557. package/dist/plain/validate/isValidDateRange.d.ts +11 -4
  558. package/dist/plain/validate/isValidDateRange.js +32 -22
  559. package/dist/plain/validate/isValidDateTime.d.ts +7 -1
  560. package/dist/plain/validate/isValidDateTime.js +12 -5
  561. package/dist/plain/validate/isValidDateTimeRange.d.ts +3 -2
  562. package/dist/plain/validate/isValidDateTimeRange.js +30 -15
  563. package/dist/plain/validate/isValidIsoDateLike.d.ts +6 -1
  564. package/dist/plain/validate/isValidIsoDateLike.js +13 -8
  565. package/dist/plain/validate/isValidTime.d.ts +6 -1
  566. package/dist/plain/validate/isValidTime.js +10 -3
  567. package/dist/plain/validate/isValidTimeRange.d.ts +4 -2
  568. package/dist/plain/validate/isValidTimeRange.js +31 -27
  569. package/dist/precision/calculate/index.d.ts +1 -0
  570. package/dist/precision/calculate/index.js +1 -0
  571. package/dist/precision/calculate/truncateNanoseconds.d.ts +37 -0
  572. package/dist/precision/calculate/truncateNanoseconds.js +41 -0
  573. package/dist/precision/convert/fromDotNetTicks.d.ts +30 -0
  574. package/dist/precision/convert/fromDotNetTicks.js +39 -0
  575. package/dist/precision/convert/fromExcelSerial.d.ts +38 -0
  576. package/dist/precision/convert/fromExcelSerial.js +81 -0
  577. package/dist/precision/convert/fromFileTime.d.ts +30 -0
  578. package/dist/precision/convert/fromFileTime.js +39 -0
  579. package/dist/precision/convert/fromNanoseconds.d.ts +29 -0
  580. package/dist/precision/convert/fromNanoseconds.js +50 -0
  581. package/dist/precision/convert/fromNtpTimestamp.d.ts +43 -0
  582. package/dist/precision/convert/fromNtpTimestamp.js +57 -0
  583. package/dist/precision/convert/fromPgMicroseconds.d.ts +26 -0
  584. package/dist/precision/convert/fromPgMicroseconds.js +33 -0
  585. package/dist/precision/convert/index.d.ts +12 -0
  586. package/dist/precision/convert/index.js +12 -0
  587. package/dist/precision/convert/toDotNetTicks.d.ts +29 -0
  588. package/dist/precision/convert/toDotNetTicks.js +40 -0
  589. package/dist/precision/convert/toExcelSerial.d.ts +56 -0
  590. package/dist/precision/convert/toExcelSerial.js +85 -0
  591. package/dist/precision/convert/toFileTime.d.ts +31 -0
  592. package/dist/precision/convert/toFileTime.js +43 -0
  593. package/dist/precision/convert/toNanoseconds.d.ts +37 -0
  594. package/dist/precision/convert/toNanoseconds.js +40 -0
  595. package/dist/precision/convert/toNtpTimestamp.d.ts +30 -0
  596. package/dist/precision/convert/toNtpTimestamp.js +38 -0
  597. package/dist/precision/convert/toPgMicroseconds.d.ts +29 -0
  598. package/dist/precision/convert/toPgMicroseconds.js +42 -0
  599. package/dist/precision/format/formatNanoseconds.d.ts +26 -0
  600. package/dist/precision/format/formatNanoseconds.js +32 -0
  601. package/dist/precision/format/index.d.ts +1 -0
  602. package/dist/precision/format/index.js +1 -0
  603. package/dist/precision/index.d.ts +6 -0
  604. package/dist/precision/index.js +7 -0
  605. package/dist/precision/parse/index.d.ts +1 -0
  606. package/dist/precision/parse/index.js +1 -0
  607. package/dist/precision/parse/parseNanoseconds.d.ts +27 -0
  608. package/dist/precision/parse/parseNanoseconds.js +32 -0
  609. package/dist/precision/validate/index.d.ts +3 -0
  610. package/dist/precision/validate/index.js +3 -0
  611. package/dist/precision/validate/isValidInstant.d.ts +37 -0
  612. package/dist/precision/validate/isValidInstant.js +40 -0
  613. package/dist/precision/validate/isValidNanoPattern.d.ts +27 -0
  614. package/dist/precision/validate/isValidNanoPattern.js +40 -0
  615. package/dist/precision/validate/isValidNanoseconds.d.ts +25 -0
  616. package/dist/precision/validate/isValidNanoseconds.js +28 -0
  617. package/dist/regex/calendar-date.d.ts +25 -14
  618. package/dist/regex/calendar-date.js +26 -15
  619. package/dist/regex/calendar-zoned-date-time.d.ts +22 -38
  620. package/dist/regex/calendar-zoned-date-time.js +23 -39
  621. package/dist/regex/date-time.d.ts +14 -4
  622. package/dist/regex/date-time.js +15 -5
  623. package/dist/regex/date.d.ts +45 -3
  624. package/dist/regex/date.js +47 -5
  625. package/dist/regex/http-date.d.ts +10 -6
  626. package/dist/regex/http-date.js +10 -6
  627. package/dist/regex/index.d.ts +3 -0
  628. package/dist/regex/index.js +4 -0
  629. package/dist/regex/leap-second.d.ts +41 -8
  630. package/dist/regex/leap-second.js +42 -9
  631. package/dist/regex/nanoseconds.d.ts +20 -0
  632. package/dist/regex/nanoseconds.js +20 -0
  633. package/dist/regex/rfc-2822.d.ts +15 -7
  634. package/dist/regex/rfc-2822.js +15 -7
  635. package/dist/regex/rfc-3339.d.ts +8 -1
  636. package/dist/regex/rfc-3339.js +9 -2
  637. package/dist/regex/sql-date-time.d.ts +27 -8
  638. package/dist/regex/sql-date-time.js +28 -9
  639. package/dist/regex/time-zone-like.d.ts +24 -15
  640. package/dist/regex/time-zone-like.js +25 -16
  641. package/dist/regex/time.d.ts +20 -6
  642. package/dist/regex/time.js +20 -6
  643. package/dist/regex/unix.d.ts +13 -5
  644. package/dist/regex/unix.js +13 -5
  645. package/dist/regex/utc-date-time.d.ts +19 -9
  646. package/dist/regex/utc-date-time.js +20 -10
  647. package/dist/regex/utc-offset.d.ts +24 -0
  648. package/dist/regex/utc-offset.js +24 -0
  649. package/dist/span/calculate/index.d.ts +3 -0
  650. package/dist/span/calculate/index.js +3 -0
  651. package/dist/span/calculate/spanMs.d.ts +52 -0
  652. package/dist/span/calculate/spanMs.js +80 -0
  653. package/dist/span/calculate/spanNs.d.ts +43 -0
  654. package/dist/span/calculate/spanNs.js +51 -0
  655. package/dist/span/calculate/spanWallClock.d.ts +60 -0
  656. package/dist/span/calculate/spanWallClock.js +80 -0
  657. package/dist/span/index.d.ts +3 -0
  658. package/dist/span/index.js +4 -0
  659. package/dist/span/validate/index.d.ts +1 -0
  660. package/dist/span/validate/index.js +1 -0
  661. package/dist/span/validate/isValidSpan.d.ts +37 -0
  662. package/dist/span/validate/isValidSpan.js +41 -0
  663. package/dist/types/business-calendar.d.ts +27 -0
  664. package/dist/types/business-calendar.js +0 -0
  665. package/dist/types/calendar-system.d.ts +9 -1
  666. package/dist/types/fiscal-calendar.d.ts +22 -0
  667. package/dist/types/fiscal-calendar.js +0 -0
  668. package/dist/types/index.d.ts +6 -0
  669. package/dist/types/index.js +5 -0
  670. package/dist/types/interval.d.ts +18 -0
  671. package/dist/types/interval.js +0 -0
  672. package/dist/types/now-unit.d.ts +1 -1
  673. package/dist/types/roll-convention.d.ts +32 -0
  674. package/dist/types/roll-convention.js +0 -0
  675. package/dist/types/utc-now-unit.d.ts +1 -1
  676. package/dist/types/zone-bucket-unit.d.ts +11 -0
  677. package/dist/types/zone-bucket-unit.js +0 -0
  678. package/dist/unix/calculate/addUnix.d.ts +10 -4
  679. package/dist/unix/calculate/addUnix.js +39 -26
  680. package/dist/unix/calculate/diffUnix.d.ts +38 -11
  681. package/dist/unix/calculate/diffUnix.js +84 -40
  682. package/dist/unix/calculate/diffUnixAsDuration.d.ts +17 -7
  683. package/dist/unix/calculate/diffUnixAsDuration.js +42 -23
  684. package/dist/unix/calculate/endOfQuarterForUnix.d.ts +15 -11
  685. package/dist/unix/calculate/endOfQuarterForUnix.js +20 -39
  686. package/dist/unix/calculate/endOfUnix.d.ts +23 -18
  687. package/dist/unix/calculate/endOfUnix.js +37 -15
  688. package/dist/unix/calculate/isBetweenUnix.d.ts +12 -6
  689. package/dist/unix/calculate/isBetweenUnix.js +34 -23
  690. package/dist/unix/calculate/maxUnix.d.ts +6 -3
  691. package/dist/unix/calculate/maxUnix.js +17 -8
  692. package/dist/unix/calculate/minUnix.d.ts +6 -3
  693. package/dist/unix/calculate/minUnix.js +17 -8
  694. package/dist/unix/calculate/roundUnix.d.ts +24 -10
  695. package/dist/unix/calculate/roundUnix.js +67 -42
  696. package/dist/unix/calculate/setUnix.d.ts +14 -5
  697. package/dist/unix/calculate/setUnix.js +48 -29
  698. package/dist/unix/calculate/sortUnix.d.ts +6 -3
  699. package/dist/unix/calculate/sortUnix.js +19 -11
  700. package/dist/unix/calculate/startOfQuarterForUnix.d.ts +17 -12
  701. package/dist/unix/calculate/startOfQuarterForUnix.js +22 -30
  702. package/dist/unix/calculate/startOfUnix.d.ts +23 -18
  703. package/dist/unix/calculate/startOfUnix.js +37 -15
  704. package/dist/unix/calculate/subtractUnix.d.ts +10 -4
  705. package/dist/unix/calculate/subtractUnix.js +39 -26
  706. package/dist/unix/compare/areUnixEqual.d.ts +9 -5
  707. package/dist/unix/compare/areUnixEqual.js +17 -13
  708. package/dist/unix/compare/areUnixEqualBy.d.ts +14 -7
  709. package/dist/unix/compare/areUnixEqualBy.js +14 -7
  710. package/dist/unix/compare/isAfterUnix.d.ts +8 -4
  711. package/dist/unix/compare/isAfterUnix.js +16 -12
  712. package/dist/unix/compare/isBeforeUnix.d.ts +7 -4
  713. package/dist/unix/compare/isBeforeUnix.js +15 -12
  714. package/dist/unix/convert/convertUnixToPlainDate.d.ts +17 -9
  715. package/dist/unix/convert/convertUnixToPlainDate.js +34 -21
  716. package/dist/unix/convert/convertUnixToPlainDateTime.d.ts +15 -9
  717. package/dist/unix/convert/convertUnixToPlainDateTime.js +32 -21
  718. package/dist/unix/convert/convertUnixToPlainTime.d.ts +15 -9
  719. package/dist/unix/convert/convertUnixToPlainTime.js +32 -21
  720. package/dist/unix/convert/convertUnixToUtc.d.ts +15 -7
  721. package/dist/unix/convert/convertUnixToUtc.js +20 -15
  722. package/dist/unix/convert/convertUnixToZoned.d.ts +17 -10
  723. package/dist/unix/convert/convertUnixToZoned.js +31 -20
  724. package/dist/unix/format/formatCalendarUnix.d.ts +22 -19
  725. package/dist/unix/format/formatCalendarUnix.js +35 -81
  726. package/dist/unix/format/formatRelativeUnix.d.ts +25 -8
  727. package/dist/unix/format/formatRelativeUnix.js +46 -93
  728. package/dist/unix/format/formatUnix.d.ts +26 -4
  729. package/dist/unix/format/formatUnix.js +48 -34
  730. package/dist/unix/get/getUnixNow.d.ts +13 -7
  731. package/dist/unix/get/getUnixNow.js +27 -17
  732. package/dist/unix/get/getUnixNowUnit.d.ts +5 -2
  733. package/dist/unix/get/getUnixNowUnit.js +9 -35
  734. package/dist/unix/index.d.ts +1 -0
  735. package/dist/unix/index.js +2 -0
  736. package/dist/unix/interval/intervalAbutsUnix.d.ts +17 -12
  737. package/dist/unix/interval/intervalAbutsUnix.js +23 -41
  738. package/dist/unix/interval/intervalContainsUnix.d.ts +17 -7
  739. package/dist/unix/interval/intervalContainsUnix.js +25 -37
  740. package/dist/unix/interval/intervalCountUnix.d.ts +30 -13
  741. package/dist/unix/interval/intervalCountUnix.js +49 -23
  742. package/dist/unix/interval/intervalDifferenceUnix.d.ts +19 -10
  743. package/dist/unix/interval/intervalDifferenceUnix.js +25 -43
  744. package/dist/unix/interval/intervalDivideEquallyUnix.d.ts +24 -10
  745. package/dist/unix/interval/intervalDivideEquallyUnix.js +57 -36
  746. package/dist/unix/interval/intervalEngulfsUnix.d.ts +13 -7
  747. package/dist/unix/interval/intervalEngulfsUnix.js +18 -30
  748. package/dist/unix/interval/intervalFromDurationUnix.d.ts +10 -6
  749. package/dist/unix/interval/intervalFromDurationUnix.js +51 -39
  750. package/dist/unix/interval/intervalIntersectionUnix.d.ts +18 -11
  751. package/dist/unix/interval/intervalIntersectionUnix.js +25 -46
  752. package/dist/unix/interval/intervalLengthUnix.d.ts +21 -9
  753. package/dist/unix/interval/intervalLengthUnix.js +41 -18
  754. package/dist/unix/interval/intervalOverlappingDaysUnix.d.ts +26 -12
  755. package/dist/unix/interval/intervalOverlappingDaysUnix.js +67 -63
  756. package/dist/unix/interval/intervalSplitAtUnix.d.ts +11 -6
  757. package/dist/unix/interval/intervalSplitAtUnix.js +41 -34
  758. package/dist/unix/interval/intervalUnionUnix.d.ts +15 -9
  759. package/dist/unix/interval/intervalUnionUnix.js +20 -42
  760. package/dist/unix/interval/intervalXorAllUnix.d.ts +8 -6
  761. package/dist/unix/interval/intervalXorAllUnix.js +21 -56
  762. package/dist/unix/interval/intervalXorUnix.d.ts +22 -11
  763. package/dist/unix/interval/intervalXorUnix.js +28 -56
  764. package/dist/unix/interval/intervalsOverlapUnix.d.ts +16 -10
  765. package/dist/unix/interval/intervalsOverlapUnix.js +21 -37
  766. package/dist/unix/interval/mergeIntervalsUnix.d.ts +10 -4
  767. package/dist/unix/interval/mergeIntervalsUnix.js +25 -36
  768. package/dist/unix/interval/splitIntervalByUnitUnix.d.ts +38 -8
  769. package/dist/unix/interval/splitIntervalByUnitUnix.js +72 -56
  770. package/dist/unix/interval/validate/isValidUnixInterval.d.ts +12 -6
  771. package/dist/unix/interval/validate/isValidUnixInterval.js +17 -16
  772. package/dist/unix/parse/index.d.ts +2 -0
  773. package/dist/unix/parse/index.js +2 -0
  774. package/dist/unix/parse/parseDateFromUnix.d.ts +10 -8
  775. package/dist/unix/parse/parseDateFromUnix.js +17 -29
  776. package/dist/unix/parse/parseDayFromUnix.d.ts +6 -4
  777. package/dist/unix/parse/parseDayFromUnix.js +18 -5
  778. package/dist/unix/parse/parseDayOfWeekFromUnix.d.ts +8 -5
  779. package/dist/unix/parse/parseDayOfWeekFromUnix.js +15 -28
  780. package/dist/unix/parse/parseHourFromUnix.d.ts +6 -4
  781. package/dist/unix/parse/parseHourFromUnix.js +18 -5
  782. package/dist/unix/parse/parseMicrosecondFromUnix.d.ts +4 -2
  783. package/dist/unix/parse/parseMicrosecondFromUnix.js +16 -3
  784. package/dist/unix/parse/parseMillisecondFromUnix.d.ts +4 -2
  785. package/dist/unix/parse/parseMillisecondFromUnix.js +16 -3
  786. package/dist/unix/parse/parseMinuteFromUnix.d.ts +6 -4
  787. package/dist/unix/parse/parseMinuteFromUnix.js +18 -5
  788. package/dist/unix/parse/parseMonthFromUnix.d.ts +6 -4
  789. package/dist/unix/parse/parseMonthFromUnix.js +18 -5
  790. package/dist/unix/parse/parseNanosecondFromUnix.d.ts +8 -5
  791. package/dist/unix/parse/parseNanosecondFromUnix.js +20 -6
  792. package/dist/unix/parse/parseSecondFromUnix.d.ts +5 -3
  793. package/dist/unix/parse/parseSecondFromUnix.js +17 -4
  794. package/dist/unix/parse/parseTimeFromUnix.d.ts +10 -8
  795. package/dist/unix/parse/parseTimeFromUnix.js +17 -29
  796. package/dist/unix/parse/parseUnitFromUnix.d.ts +18 -11
  797. package/dist/unix/parse/parseUnitFromUnix.js +57 -55
  798. package/dist/unix/parse/parseWeekFromUnix.d.ts +15 -7
  799. package/dist/unix/parse/parseWeekFromUnix.js +32 -30
  800. package/dist/unix/parse/parseYearFromUnix.d.ts +5 -3
  801. package/dist/unix/parse/parseYearFromUnix.js +17 -4
  802. package/dist/unix/validate/isValidUnixMilliseconds.d.ts +8 -5
  803. package/dist/unix/validate/isValidUnixMilliseconds.js +10 -9
  804. package/dist/unix/validate/isValidUnixRange.d.ts +13 -7
  805. package/dist/unix/validate/isValidUnixRange.js +29 -19
  806. package/dist/unix/validate/isValidUnixSeconds.d.ts +8 -5
  807. package/dist/unix/validate/isValidUnixSeconds.js +10 -9
  808. package/dist/unix/validate/isValidUnixUnit.d.ts +9 -7
  809. package/dist/unix/validate/isValidUnixUnit.js +6 -8
  810. package/dist/utc/calculate/addUtc.js +26 -12
  811. package/dist/utc/calculate/diffUtc.d.ts +22 -7
  812. package/dist/utc/calculate/diffUtc.js +75 -31
  813. package/dist/utc/calculate/diffUtcAsDuration.d.ts +2 -2
  814. package/dist/utc/calculate/diffUtcAsDuration.js +10 -3
  815. package/dist/utc/calculate/endOfQuarterForUtc.d.ts +1 -1
  816. package/dist/utc/calculate/endOfQuarterForUtc.js +1 -1
  817. package/dist/utc/calculate/endOfUtc.d.ts +11 -4
  818. package/dist/utc/calculate/endOfUtc.js +22 -5
  819. package/dist/utc/calculate/isBetweenUtc.js +40 -24
  820. package/dist/utc/calculate/maxUtc.js +19 -12
  821. package/dist/utc/calculate/minUtc.js +19 -12
  822. package/dist/utc/calculate/roundUtc.d.ts +16 -2
  823. package/dist/utc/calculate/roundUtc.js +42 -31
  824. package/dist/utc/calculate/setUtc.d.ts +4 -8
  825. package/dist/utc/calculate/setUtc.js +25 -18
  826. package/dist/utc/calculate/sortUtc.js +17 -10
  827. package/dist/utc/calculate/startOfQuarterForUtc.d.ts +2 -0
  828. package/dist/utc/calculate/startOfQuarterForUtc.js +12 -1
  829. package/dist/utc/calculate/startOfUtc.d.ts +6 -4
  830. package/dist/utc/calculate/startOfUtc.js +17 -5
  831. package/dist/utc/calculate/subtractUtc.js +26 -12
  832. package/dist/utc/chop/chopUtc.d.ts +5 -2
  833. package/dist/utc/chop/chopUtc.js +8 -4
  834. package/dist/utc/compare/areUtcEqualBy.d.ts +10 -5
  835. package/dist/utc/compare/areUtcEqualBy.js +34 -11
  836. package/dist/utc/convert/convertUtcToPlainDate.js +22 -10
  837. package/dist/utc/convert/convertUtcToPlainDateTime.js +28 -16
  838. package/dist/utc/convert/convertUtcToPlainTime.js +22 -10
  839. package/dist/utc/convert/convertUtcToUnix.d.ts +12 -5
  840. package/dist/utc/convert/convertUtcToUnix.js +22 -13
  841. package/dist/utc/format/formatCalendarUtc.d.ts +11 -6
  842. package/dist/utc/format/formatCalendarUtc.js +32 -41
  843. package/dist/utc/format/formatHttp.d.ts +9 -3
  844. package/dist/utc/format/formatHttp.js +14 -12
  845. package/dist/utc/format/formatRelativeUtc.d.ts +18 -6
  846. package/dist/utc/format/formatRelativeUtc.js +43 -51
  847. package/dist/utc/format/formatUtc.d.ts +20 -3
  848. package/dist/utc/format/formatUtc.js +41 -12
  849. package/dist/utc/get/getUtcNowUnit.d.ts +3 -0
  850. package/dist/utc/get/getUtcNowUnit.js +11 -33
  851. package/dist/utc/index.d.ts +1 -0
  852. package/dist/utc/index.js +2 -0
  853. package/dist/utc/interval/intervalAbutsUtc.d.ts +10 -7
  854. package/dist/utc/interval/intervalAbutsUtc.js +18 -30
  855. package/dist/utc/interval/intervalContainsUtc.d.ts +19 -11
  856. package/dist/utc/interval/intervalContainsUtc.js +33 -34
  857. package/dist/utc/interval/intervalCountUtc.d.ts +3 -4
  858. package/dist/utc/interval/intervalCountUtc.js +12 -18
  859. package/dist/utc/interval/intervalDifferenceUtc.d.ts +13 -5
  860. package/dist/utc/interval/intervalDifferenceUtc.js +25 -51
  861. package/dist/utc/interval/intervalDivideEquallyUtc.d.ts +16 -3
  862. package/dist/utc/interval/intervalDivideEquallyUtc.js +54 -34
  863. package/dist/utc/interval/intervalEngulfsUtc.d.ts +17 -12
  864. package/dist/utc/interval/intervalEngulfsUtc.js +25 -26
  865. package/dist/utc/interval/intervalFromDurationUtc.js +5 -0
  866. package/dist/utc/interval/intervalIntersectionUtc.d.ts +12 -6
  867. package/dist/utc/interval/intervalIntersectionUtc.js +24 -41
  868. package/dist/utc/interval/intervalLengthUtc.js +5 -7
  869. package/dist/utc/interval/intervalOverlappingDaysUtc.d.ts +7 -13
  870. package/dist/utc/interval/intervalOverlappingDaysUtc.js +25 -36
  871. package/dist/utc/interval/intervalSplitAtUtc.d.ts +7 -2
  872. package/dist/utc/interval/intervalSplitAtUtc.js +39 -33
  873. package/dist/utc/interval/intervalUnionUtc.d.ts +15 -7
  874. package/dist/utc/interval/intervalUnionUtc.js +31 -42
  875. package/dist/utc/interval/intervalXorAllUtc.d.ts +7 -4
  876. package/dist/utc/interval/intervalXorAllUtc.js +30 -52
  877. package/dist/utc/interval/intervalXorUtc.d.ts +8 -6
  878. package/dist/utc/interval/intervalXorUtc.js +22 -56
  879. package/dist/utc/interval/intervalsOverlapUtc.d.ts +15 -9
  880. package/dist/utc/interval/intervalsOverlapUtc.js +23 -39
  881. package/dist/utc/interval/mergeIntervalsUtc.d.ts +9 -2
  882. package/dist/utc/interval/mergeIntervalsUtc.js +23 -36
  883. package/dist/utc/interval/splitIntervalByUnitUtc.d.ts +23 -2
  884. package/dist/utc/interval/splitIntervalByUnitUtc.js +65 -44
  885. package/dist/utc/interval/validate/isValidUtcInterval.d.ts +5 -0
  886. package/dist/utc/interval/validate/isValidUtcInterval.js +7 -6
  887. package/dist/utc/parse/parseDateFromUtc.d.ts +7 -1
  888. package/dist/utc/parse/parseDateFromUtc.js +14 -9
  889. package/dist/utc/parse/parseDayFromUtc.d.ts +7 -1
  890. package/dist/utc/parse/parseDayFromUtc.js +14 -8
  891. package/dist/utc/parse/parseDayOfWeekFromUtc.d.ts +7 -1
  892. package/dist/utc/parse/parseDayOfWeekFromUtc.js +24 -6
  893. package/dist/utc/parse/parseHourFromUtc.d.ts +7 -1
  894. package/dist/utc/parse/parseHourFromUtc.js +14 -8
  895. package/dist/utc/parse/parseHttp.d.ts +39 -14
  896. package/dist/utc/parse/parseHttp.js +69 -28
  897. package/dist/utc/parse/parseMicrosecondFromUtc.d.ts +9 -2
  898. package/dist/utc/parse/parseMicrosecondFromUtc.js +18 -9
  899. package/dist/utc/parse/parseMillisecondFromUtc.d.ts +7 -1
  900. package/dist/utc/parse/parseMillisecondFromUtc.js +16 -8
  901. package/dist/utc/parse/parseMinuteFromUtc.d.ts +7 -1
  902. package/dist/utc/parse/parseMinuteFromUtc.js +14 -8
  903. package/dist/utc/parse/parseMonthFromUtc.d.ts +7 -1
  904. package/dist/utc/parse/parseMonthFromUtc.js +14 -8
  905. package/dist/utc/parse/parseNanosecondFromUtc.d.ts +9 -2
  906. package/dist/utc/parse/parseNanosecondFromUtc.js +18 -9
  907. package/dist/utc/parse/parseSecondFromUtc.d.ts +7 -1
  908. package/dist/utc/parse/parseSecondFromUtc.js +14 -8
  909. package/dist/utc/parse/parseTimeFromUtc.js +21 -10
  910. package/dist/utc/parse/parseUnitFromUtc.d.ts +18 -7
  911. package/dist/utc/parse/parseUnitFromUtc.js +58 -31
  912. package/dist/utc/parse/parseWeekFromUtc.d.ts +16 -3
  913. package/dist/utc/parse/parseWeekFromUtc.js +38 -10
  914. package/dist/utc/parse/parseYearFromUtc.d.ts +7 -1
  915. package/dist/utc/parse/parseYearFromUtc.js +14 -8
  916. package/dist/utc/validate/isValidUtc.d.ts +8 -1
  917. package/dist/utc/validate/isValidUtc.js +12 -3
  918. package/dist/utc/validate/isValidUtcRange.d.ts +3 -2
  919. package/dist/utc/validate/isValidUtcRange.js +30 -19
  920. package/dist/zoned/calculate/addZoned.d.ts +40 -27
  921. package/dist/zoned/calculate/addZoned.js +71 -56
  922. package/dist/zoned/calculate/addZonedBusinessDays.d.ts +2 -0
  923. package/dist/zoned/calculate/addZonedBusinessDays.js +5 -2
  924. package/dist/zoned/calculate/clampZoned.js +4 -3
  925. package/dist/zoned/calculate/closestZonedTo.d.ts +6 -6
  926. package/dist/zoned/calculate/closestZonedTo.js +35 -26
  927. package/dist/zoned/calculate/cycleZoned.d.ts +10 -7
  928. package/dist/zoned/calculate/cycleZoned.js +19 -11
  929. package/dist/zoned/calculate/diffZoned.d.ts +39 -17
  930. package/dist/zoned/calculate/diffZoned.js +90 -45
  931. package/dist/zoned/calculate/diffZonedAsDuration.d.ts +19 -9
  932. package/dist/zoned/calculate/diffZonedAsDuration.js +32 -15
  933. package/dist/zoned/calculate/endOfQuarterForZoned.d.ts +11 -11
  934. package/dist/zoned/calculate/endOfQuarterForZoned.js +32 -31
  935. package/dist/zoned/calculate/endOfZoned.d.ts +21 -14
  936. package/dist/zoned/calculate/endOfZoned.js +25 -111
  937. package/dist/zoned/calculate/getHoursInZonedDay.d.ts +8 -1
  938. package/dist/zoned/calculate/getHoursInZonedDay.js +10 -14
  939. package/dist/zoned/calculate/getLocaleZonedDayOfWeek.d.ts +8 -4
  940. package/dist/zoned/calculate/getLocaleZonedDayOfWeek.js +9 -6
  941. package/dist/zoned/calculate/getLocaleZonedEndOfWeek.d.ts +20 -26
  942. package/dist/zoned/calculate/getLocaleZonedEndOfWeek.js +40 -44
  943. package/dist/zoned/calculate/getLocaleZonedStartOfWeek.d.ts +16 -24
  944. package/dist/zoned/calculate/getLocaleZonedStartOfWeek.js +36 -42
  945. package/dist/zoned/calculate/getQuarterForZoned.js +2 -2
  946. package/dist/zoned/calculate/maxZoned.js +20 -12
  947. package/dist/zoned/calculate/minZoned.d.ts +1 -1
  948. package/dist/zoned/calculate/minZoned.js +21 -13
  949. package/dist/zoned/calculate/roundZoned.d.ts +18 -4
  950. package/dist/zoned/calculate/roundZoned.js +58 -33
  951. package/dist/zoned/calculate/setZoned.d.ts +9 -3
  952. package/dist/zoned/calculate/setZoned.js +39 -18
  953. package/dist/zoned/calculate/sortZoned.js +18 -10
  954. package/dist/zoned/calculate/startOfQuarterForZoned.d.ts +4 -7
  955. package/dist/zoned/calculate/startOfQuarterForZoned.js +23 -17
  956. package/dist/zoned/calculate/startOfZoned.d.ts +17 -13
  957. package/dist/zoned/calculate/startOfZoned.js +21 -103
  958. package/dist/zoned/calculate/subtractZoned.d.ts +36 -24
  959. package/dist/zoned/calculate/subtractZoned.js +66 -50
  960. package/dist/zoned/calculate/subtractZonedBusinessDays.d.ts +2 -0
  961. package/dist/zoned/calculate/subtractZonedBusinessDays.js +5 -2
  962. package/dist/zoned/chop/chopZonedDate.js +2 -2
  963. package/dist/zoned/chop/chopZonedDateTime.js +2 -2
  964. package/dist/zoned/chop/chopZonedMilliseconds.js +2 -2
  965. package/dist/zoned/chop/chopZonedSeconds.js +2 -2
  966. package/dist/zoned/chop/chopZonedTime.js +2 -2
  967. package/dist/zoned/chop/chopZonedTimezone.js +2 -2
  968. package/dist/zoned/compare/areZonedEqual.js +3 -2
  969. package/dist/zoned/compare/areZonedEqualBy.d.ts +15 -2
  970. package/dist/zoned/compare/areZonedEqualBy.js +45 -12
  971. package/dist/zoned/compare/isAfterZoned.js +3 -2
  972. package/dist/zoned/compare/isBeforeZoned.d.ts +1 -1
  973. package/dist/zoned/compare/isBeforeZoned.js +4 -3
  974. package/dist/zoned/compare/isBetweenZoned.js +46 -29
  975. package/dist/zoned/compare/isInDaylightSaving.js +4 -4
  976. package/dist/zoned/compare/isZonedBusinessDay.d.ts +7 -4
  977. package/dist/zoned/compare/isZonedBusinessDay.js +9 -6
  978. package/dist/zoned/compare/isZonedFuture.js +2 -1
  979. package/dist/zoned/compare/isZonedPast.js +2 -1
  980. package/dist/zoned/compare/isZonedRelativeDay.js +2 -1
  981. package/dist/zoned/compare/isZonedThisUnit.d.ts +12 -4
  982. package/dist/zoned/compare/isZonedThisUnit.js +37 -16
  983. package/dist/zoned/compare/isZonedWeekend.d.ts +8 -4
  984. package/dist/zoned/compare/isZonedWeekend.js +9 -6
  985. package/dist/zoned/convert/convertPlainDateTimeToZoned.d.ts +10 -5
  986. package/dist/zoned/convert/convertPlainDateTimeToZoned.js +34 -16
  987. package/dist/zoned/convert/convertZonedToCalendar.d.ts +26 -38
  988. package/dist/zoned/convert/convertZonedToCalendar.js +33 -48
  989. package/dist/zoned/convert/convertZonedToPlainDateTime.d.ts +6 -0
  990. package/dist/zoned/convert/convertZonedToPlainDateTime.js +8 -2
  991. package/dist/zoned/convert/convertZonedToUnix.d.ts +12 -6
  992. package/dist/zoned/convert/convertZonedToUnix.js +23 -16
  993. package/dist/zoned/convert/convertZonedToUtc.js +2 -2
  994. package/dist/zoned/convert/convertZonedToZoned.js +2 -2
  995. package/dist/zoned/format/formatCalendarZoned.d.ts +7 -3
  996. package/dist/zoned/format/formatCalendarZoned.js +37 -39
  997. package/dist/zoned/format/formatRelativeZoned.d.ts +15 -6
  998. package/dist/zoned/format/formatRelativeZoned.js +54 -54
  999. package/dist/zoned/format/formatRfc2822.d.ts +14 -1
  1000. package/dist/zoned/format/formatRfc2822.js +27 -13
  1001. package/dist/zoned/format/formatRfc3339.d.ts +14 -1
  1002. package/dist/zoned/format/formatRfc3339.js +29 -3
  1003. package/dist/zoned/format/formatTimeZoneName.d.ts +3 -2
  1004. package/dist/zoned/format/formatTimeZoneName.js +28 -18
  1005. package/dist/zoned/format/formatZonedDateTime.d.ts +25 -5
  1006. package/dist/zoned/format/formatZonedDateTime.js +40 -9
  1007. package/dist/zoned/format/formatZonedRange.d.ts +24 -6
  1008. package/dist/zoned/format/formatZonedRange.js +61 -28
  1009. package/dist/zoned/format/formatZonedToParts.d.ts +29 -6
  1010. package/dist/zoned/format/formatZonedToParts.js +42 -13
  1011. package/dist/zoned/get/getDstTransitions.d.ts +6 -1
  1012. package/dist/zoned/get/getDstTransitions.js +17 -15
  1013. package/dist/zoned/get/getTimeZoneOffset.d.ts +11 -1
  1014. package/dist/zoned/get/getTimeZoneOffset.js +19 -2
  1015. package/dist/zoned/get/getZonedNow.js +20 -9
  1016. package/dist/zoned/get/getZonedNowUnit.d.ts +8 -4
  1017. package/dist/zoned/get/getZonedNowUnit.js +15 -31
  1018. package/dist/zoned/index.js +1 -1
  1019. package/dist/zoned/interval/intervalAbutsZoned.d.ts +18 -11
  1020. package/dist/zoned/interval/intervalAbutsZoned.js +24 -25
  1021. package/dist/zoned/interval/intervalContainsZoned.d.ts +16 -7
  1022. package/dist/zoned/interval/intervalContainsZoned.js +22 -14
  1023. package/dist/zoned/interval/intervalCountZoned.d.ts +19 -11
  1024. package/dist/zoned/interval/intervalCountZoned.js +32 -27
  1025. package/dist/zoned/interval/intervalDifferenceZoned.d.ts +13 -7
  1026. package/dist/zoned/interval/intervalDifferenceZoned.js +24 -36
  1027. package/dist/zoned/interval/intervalDivideEquallyZoned.d.ts +18 -9
  1028. package/dist/zoned/interval/intervalDivideEquallyZoned.js +67 -46
  1029. package/dist/zoned/interval/intervalEngulfsZoned.d.ts +10 -5
  1030. package/dist/zoned/interval/intervalEngulfsZoned.js +16 -10
  1031. package/dist/zoned/interval/intervalFromDurationZoned.d.ts +25 -11
  1032. package/dist/zoned/interval/intervalFromDurationZoned.js +61 -44
  1033. package/dist/zoned/interval/intervalIntersectionZoned.d.ts +12 -6
  1034. package/dist/zoned/interval/intervalIntersectionZoned.js +24 -18
  1035. package/dist/zoned/interval/intervalLengthZoned.d.ts +15 -6
  1036. package/dist/zoned/interval/intervalLengthZoned.js +23 -9
  1037. package/dist/zoned/interval/intervalOverlappingDaysZoned.d.ts +28 -17
  1038. package/dist/zoned/interval/intervalOverlappingDaysZoned.js +46 -34
  1039. package/dist/zoned/interval/intervalSplitAtZoned.d.ts +6 -3
  1040. package/dist/zoned/interval/intervalSplitAtZoned.js +52 -42
  1041. package/dist/zoned/interval/intervalUnionZoned.d.ts +14 -8
  1042. package/dist/zoned/interval/intervalUnionZoned.js +25 -20
  1043. package/dist/zoned/interval/intervalXorAllZoned.d.ts +9 -7
  1044. package/dist/zoned/interval/intervalXorAllZoned.js +42 -73
  1045. package/dist/zoned/interval/intervalXorZoned.d.ts +20 -12
  1046. package/dist/zoned/interval/intervalXorZoned.js +34 -64
  1047. package/dist/zoned/interval/intervalsOverlapZoned.d.ts +15 -7
  1048. package/dist/zoned/interval/intervalsOverlapZoned.js +21 -12
  1049. package/dist/zoned/interval/mergeIntervalsZoned.d.ts +10 -3
  1050. package/dist/zoned/interval/mergeIntervalsZoned.js +44 -41
  1051. package/dist/zoned/interval/splitIntervalByUnitZoned.d.ts +28 -5
  1052. package/dist/zoned/interval/splitIntervalByUnitZoned.js +72 -39
  1053. package/dist/zoned/interval/validate/isValidCalendarZonedInterval.d.ts +13 -10
  1054. package/dist/zoned/interval/validate/isValidCalendarZonedInterval.js +13 -10
  1055. package/dist/zoned/interval/validate/isValidZonedInterval.d.ts +7 -5
  1056. package/dist/zoned/interval/validate/isValidZonedInterval.js +12 -16
  1057. package/dist/zoned/map/mapZonedDatesInRange.d.ts +17 -1
  1058. package/dist/zoned/map/mapZonedDatesInRange.js +62 -26
  1059. package/dist/zoned/map/mapZonedHoursInDay.d.ts +10 -13
  1060. package/dist/zoned/map/mapZonedHoursInDay.js +13 -21
  1061. package/dist/zoned/parse/getZonedOffset.js +2 -2
  1062. package/dist/zoned/parse/getZonedOffsetAs.d.ts +4 -2
  1063. package/dist/zoned/parse/getZonedOffsetAs.js +10 -5
  1064. package/dist/zoned/parse/parseDateFromZoned.js +2 -2
  1065. package/dist/zoned/parse/parseDateTimeFromZoned.js +2 -2
  1066. package/dist/zoned/parse/parseDayFromZoned.js +2 -2
  1067. package/dist/zoned/parse/parseDayOfWeekFromZoned.js +2 -2
  1068. package/dist/zoned/parse/parseHourFromZoned.js +2 -2
  1069. package/dist/zoned/parse/parseMicrosecondFromZoned.d.ts +2 -1
  1070. package/dist/zoned/parse/parseMicrosecondFromZoned.js +4 -3
  1071. package/dist/zoned/parse/parseMillisecondFromZoned.js +2 -2
  1072. package/dist/zoned/parse/parseMinuteFromZoned.js +2 -2
  1073. package/dist/zoned/parse/parseMonthFromZoned.js +2 -2
  1074. package/dist/zoned/parse/parseNanosecondFromZoned.d.ts +2 -1
  1075. package/dist/zoned/parse/parseNanosecondFromZoned.js +4 -3
  1076. package/dist/zoned/parse/parseRfc2822.d.ts +32 -12
  1077. package/dist/zoned/parse/parseRfc2822.js +47 -45
  1078. package/dist/zoned/parse/parseRfc3339.d.ts +6 -0
  1079. package/dist/zoned/parse/parseRfc3339.js +6 -0
  1080. package/dist/zoned/parse/parseSecondFromZoned.js +2 -2
  1081. package/dist/zoned/parse/parseTimeFromZoned.js +2 -2
  1082. package/dist/zoned/parse/parseTimeZoneFromZoned.js +2 -2
  1083. package/dist/zoned/parse/parseUnitFromZoned.d.ts +14 -5
  1084. package/dist/zoned/parse/parseUnitFromZoned.js +59 -33
  1085. package/dist/zoned/parse/parseWeekFromZoned.d.ts +13 -3
  1086. package/dist/zoned/parse/parseWeekFromZoned.js +34 -10
  1087. package/dist/zoned/parse/parseYearFromZoned.js +2 -2
  1088. package/dist/zoned/validate/hasDaylightSaving.js +3 -3
  1089. package/dist/zoned/validate/isValidCalendarZonedDateTime.d.ts +31 -16
  1090. package/dist/zoned/validate/isValidCalendarZonedDateTime.js +31 -16
  1091. package/dist/zoned/validate/isValidTimeZone.d.ts +15 -2
  1092. package/dist/zoned/validate/isValidTimeZone.js +17 -4
  1093. package/dist/zoned/validate/isValidZonedDateTime.d.ts +14 -7
  1094. package/dist/zoned/validate/isValidZonedDateTime.js +20 -12
  1095. package/dist/zoned/validate/isValidZonedRange.d.ts +9 -2
  1096. package/dist/zoned/validate/isValidZonedRange.js +44 -16
  1097. package/package.json +475 -34
  1098. package/skills/gmt-arithmetic/SKILL.md +197 -16
  1099. package/skills/gmt-basics/SKILL.md +61 -14
  1100. package/skills/gmt-integration/SKILL.md +54 -8
  1101. package/skills/gmt-timezone/SKILL.md +141 -24
  1102. package/dist/internal/advanceBusinessDays.d.ts +0 -2
  1103. package/dist/internal/advanceBusinessDays.js +0 -15
  1104. package/dist/internal/ethiopicFamilyCalendar.d.ts +0 -47
  1105. package/dist/internal/ethiopicFamilyCalendar.js +0 -136
  1106. package/dist/internal/getLocaleMinimalDaysInFirstWeek.d.ts +0 -20
  1107. package/dist/internal/getLocaleMinimalDaysInFirstWeek.js +0 -31
  1108. package/dist/internal/resolveUnixTimeZone.d.ts +0 -20
  1109. package/dist/internal/resolveUnixTimeZone.js +0 -30
  1110. package/dist/unix/calculate/startOrEndOfUnix.d.ts +0 -27
  1111. package/dist/unix/calculate/startOrEndOfUnix.js +0 -140
  1112. package/dist/unix/interval/resolveUnixIntervalPair.d.ts +0 -7
  1113. package/dist/unix/interval/resolveUnixIntervalPair.js +0 -36
package/README.md CHANGED
@@ -11,12 +11,14 @@ Give Me Temporal.
11
11
 
12
12
  It wraps `@js-temporal/polyfill` behind a smaller, more opinionated API aimed at the cases application code actually hits: arithmetic, comparison, parsing, formatting, unix conversions, timezone conversion, and validation.
13
13
 
14
+ Read the [docs](https://gmt-dox.northguild.workers.dev/), or ask us on [Discord](https://discord.gg/TdvQdP3t5a).
15
+
14
16
  **Why GMT:**
15
17
 
16
18
  - **100% Temporal, Temporal-first.** GMT is built directly on the TC39 `Temporal` standard (via `@js-temporal/polyfill`) — not a custom, homegrown date/time type system like `@internationalized/date`'s own `CalendarDate`/`ZonedDateTime` classes. No `Date` object anywhere, enforced by 3 dedicated lint packages.
17
19
  - **A full replacement for any and all of them.** Luxon, date-fns, Moment.js, and react-aria's `@internationalized/date` don't have parity with each other — GMT covers the combined capabilities of all four in one library, plus what none of them do alone.
18
- - **~15× more CI test executions than all four competitors combined**: 334,020 (16,701 tests × 17 locales × 10 timezones × 2 Node versions) vs. their combined 20,190.
19
- - **~40× more test cases than `@internationalized/date`**: 16,701 vs. 386 — Adobe's own library, run at its own commit.
20
+ - **~54× more CI test executions than all four competitors combined**: 1,090,440 from 36,348 tests run in all 10 timezones × 3 Node versions, vs. their combined 20,190.
21
+ - **~94× more test cases than `@internationalized/date`**: 36,348 vs. 386 — Adobe's own library, run at its own commit.
20
22
  - **The only one of the five that tests systematically across locales in CI at all.** Zero of the four comparison libraries run a locale-test matrix; GMT mandates all 17 locales on every locale-aware function.
21
23
  - **The only one that runs its entire suite under a real `TZ` env var across real-world zones.** Luxon and `@internationalized/date` have no CI timezone matrix; date-fns's zone scope is unclear; Moment.js covers 6 zones but not its full suite.
22
24
  - **Explicit DST disambiguation control on both construction _and_ arithmetic** — a control none of the others expose.
@@ -36,8 +38,8 @@ pnpm add @northguild/gmt
36
38
 
37
39
  GMT enforces a strict input/output contract to keep behavior predictable and auditable:
38
40
 
39
- - **Explicit inputs only**: Public APIs accept clearly defined shapes — ISO 8601 date/time strings, IANA timezone identifiers, or numeric Unix epoch values (explicitly seconds or milliseconds). We do not attempt to parse arbitrary or ambiguous date formats.
40
- - **Predictable outputs**: Helpers return normalized values (ISO strings, numbers, booleans, or arrays). Invalid input yields typed fallbacks (`""`, `null`, or `false`) instead of throwing.
41
+ - **Explicit inputs only**: Public APIs accept clearly defined shapes — ISO 8601 date/time strings, IANA timezone identifiers, or Unix epochs as safe integers or digit strings, in seconds or milliseconds (`{ epochUnit }`). We do not attempt to parse arbitrary or ambiguous date formats.
42
+ - **Predictable outputs**: Helpers return normalized values (ISO strings, numbers, booleans, or arrays). Invalid input yields typed fallbacks (`""`, `null`, `false` or `[]`) instead of throwing.
41
43
  - **No fuzzy parsing**: Avoid "throw everything at the wall" patterns found in permissive libraries. If you need permissive parsing, perform it outside of `@northguild/gmt` and then canonicalize to the strict shapes before calling into gmt.
42
44
  - **Developer comfort with standards**: The library's goal is to make developers comfortable and deliberate with ISO 8601, IANA timezones, UTC instants, and Unix epochs by keeping APIs small and explicit.
43
45
 
@@ -59,7 +61,7 @@ Invalid input fallbacks are consistent across the library:
59
61
 
60
62
  ## Testing
61
63
 
62
- Every function is exercised across **17 locales** and a full IANA timezone matrix. The CI pipeline runs the complete suite in **20 environments** — 2 Node versions (22, 24) × 10 timezones spanning every UTC offset band from Pacific/Niue (−11:00) to Pacific/Apia (+14:00):
64
+ Every function is exercised across **17 locales** and a full IANA timezone matrix. The CI pipeline runs the complete suite in **30 environments** — 3 Node versions (22, 24, 26) × 10 timezones spanning every UTC offset band from Pacific/Niue (−11:00) to Pacific/Apia (+14:00):
63
65
 
64
66
  | Timezone | UTC Offset |
65
67
  | ------------------- | --------------- |
@@ -92,7 +94,7 @@ GMT's test suite balances **thoroughness** against **maintenance burden** by tes
92
94
  - **Non-string input tables** — functions that guard with `typeof x !== "string"` return the same sentinel for `null`, `undefined`, `123`, `true`, `[]`, and `{}`. We test one representative non-string per argument position rather than all six types × N positions. The collapse is safe because all non-string types hit the identical early-return code path.
93
95
  - **Redundant permutations** — adjacent/disjoint/reversed interval cases that produce identical results are not duplicated across every function variant. The `plain/`, `zoned/`, `utc/`, and `unix/` families share the same mathematical behavior; each family gets the minimum set of cases needed to prove correctness.
94
96
 
95
- **Result:** 16,701 tests across 552 files that exercise real behavior differences without redundant permutations. The suite runs in CI as 334,020 executions (16,701 × 2 Node versions × 10 timezones).
97
+ **Result:** 36,348 tests across 663 files that exercise real behavior differences without redundant permutations. They run in CI as 1,090,440 executions — every one of them × 3 Node versions × 10 timezones.
96
98
 
97
99
  ## How GMT is tested, vs. the libraries it targets
98
100
 
@@ -108,11 +110,11 @@ GMT is measured directly against react-aria's **`@internationalized/date`**, **L
108
110
 
109
111
  | Metric | GMT | `@internationalized/date` | Luxon | date-fns | Moment.js |
110
112
  | ------------------------------- | -------------------------------------------------- | ------------------------------ | ------------------------------------ | ----------------------------------------- | -------------------------------- |
111
- | Test files | 552 | 6 | 58 / 60<br>(2 didn't run<br>locally) | 256 | 191<br>(52 core +<br>139 locale) |
112
- | Individual test cases | **16,701** | 386 | 1,222 | 3,213 | 3,901 |
113
- | Effective CI test<br>executions | **334,020**<br>(16,701 × 2 Node<br>× 10 timezones) | 386<br>(×1 Node) | 4,888<br>(1,222 × 4 Node) | 3,213<br>(×1 Node) | 11,703<br>(3,901 × 3 Node) |
114
- | CI Node.js matrix | 22, 24 | n/a — tests<br>React 16–canary | 20, 22, 24, 25 | not explicit<br>(`node = "latest"`) | LTS, LTS-1,<br>latest |
115
- | CI timezone matrix | **10 zones × 2**<br>**Node, full suite** | none found | none found | dedicated workflow,<br>zone scope unclear | 6 zones,<br>partial suite only |
113
+ | Test files | 663 | 6 | 58 / 60<br>(2 didn't run<br>locally) | 256 | 191<br>(52 core +<br>139 locale) |
114
+ | Individual test cases | **36,348** | 386 | 1,222 | 3,213 | 3,901 |
115
+ | Effective CI test<br>executions | **1,090,440**<br>(36,348 × 3 Node<br>× 10 timezones) | 386<br>(×1 Node) | 4,888<br>(1,222 × 4 Node) | 3,213<br>(×1 Node) | 11,703<br>(3,901 × 3 Node) |
116
+ | CI Node.js matrix | 22, 24, 26 | n/a — tests<br>React 16–canary | 20, 22, 24, 25 | not explicit<br>(`node = "latest"`) | LTS, LTS-1,<br>latest |
117
+ | CI timezone matrix | **10 zones × 3**<br>**Node, full suite** | none found | none found | dedicated workflow,<br>zone scope unclear | 6 zones,<br>partial suite only |
116
118
  | Locale test matrix | **17 locales**,<br>every locale fn | none found | none found | none found | none found |
117
119
  | Real-browser CI | not yet | yes (Playwright) | not found | yes (Playwright) | not found |
118
120
  | Maintenance | active | active | active | active | **maintenance<br>mode** |
@@ -129,7 +131,7 @@ GMT has **full functional parity** with all four comparison libraries, capabilit
129
131
  | Interval/range math<br>(contains, overlap, union,<br>intersection, split, set ops) | ✅ Done | Luxon `Interval`,<br>date-fns `areIntervalsOverlapping` |
130
132
  | DST disambiguation control<br>on construction _and_ arithmetic | ✅ Done — **differentiator** | None of the others expose<br>this on arithmetic |
131
133
  | Locale-aware calendar helpers<br>(weekend, week start/end, day-of-week) | ✅ Done | `@internationalized/date` |
132
- | Business-day arithmetic,<br>clamp/closest, time rounding | ✅ Done | `temporal-kit` |
134
+ | Business-day arithmetic with<br>holiday calendars and roll conventions,<br>clamp/closest, time rounding | ✅ Done | `temporal-kit` (arithmetic only) |
133
135
  | Interval rounding-out<br>(boundary count, from-duration) | ✅ Done | Luxon |
134
136
  | Locale calendar metadata<br>(names, `hasDST`) | ✅ Done | Luxon `Info` |
135
137
  | Overlap-day count, relative<br>rounding, DST transitions, hours-in-day | ✅ Done | date-fns, `@internationalized/date` |
@@ -142,40 +144,46 @@ Specific, sourced claims — not a repeat of the metrics above.
142
144
 
143
145
  | Claim | The others |
144
146
  | --------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
145
- | Only GMT runs its **entire** suite in CI<br>under a real `TZ` env var across 10<br>real-world zones × 2 Node versions<br>(20 full-suite runs) | Luxon/`@internationalized/date`: no<br>CI timezone matrix. date-fns: zone<br>scope unclear. Moment.js: 6 zones,<br>partial suite only |
147
+ | Only GMT runs its **entire** suite in CI<br>under a real `TZ` env var across 10<br>real-world zones × 3 Node versions<br>(30 full-suite runs) | Luxon/`@internationalized/date`: no<br>CI timezone matrix. date-fns: zone<br>scope unclear. Moment.js: 6 zones,<br>partial suite only |
146
148
  | Only GMT enforces a mandatory<br>17-locale test matrix on every<br>locale-aware function | No CI-level or systematic<br>locale-matrix testing found<br>in any of the four |
147
149
  | Only GMT exposes explicit DST<br>disambiguation control on both<br>construction _and_ arithmetic | Luxon's docs call this explicitly<br>undefined; `@internationalized/date`<br>only covers construction, not arithmetic |
148
150
  | Only GMT is Temporal-native with<br>zero `Date` usage, enforced by<br>3 dedicated lint packages | Luxon, date-fns, and Moment.js all<br>still wrap or depend on `Date` internally |
149
- | GMT's effective CI test<br>executions exceed all four<br>competitors **combined**<br>by ~15× | 334,020 vs. 386 + 4,888 + 3,213<br>+ 11,703 = 20,190 |
151
+ | GMT's effective CI test<br>executions exceed all four<br>competitors **combined**<br>by ~54× | 1,090,440 vs. 386 + 4,888 + 3,213<br>+ 11,703 = 20,190 |
150
152
 
151
153
  ## Package Layout
152
154
 
153
- The package exports seven top-level namespaces:
155
+ Every public function, type and regex is a flat named export of the package root, beside
156
+ `Temporal`, `Intl` and `toTemporalInstant` re-exported from `@js-temporal/polyfill`. There are no
157
+ namespace objects: a namespace is a subpath.
154
158
 
155
159
  ```typescript
156
- import {
157
- Temporal,
158
- duration,
159
- plain,
160
- zoned,
161
- unix,
162
- utc,
163
- regex,
164
- } from "@northguild/gmt";
160
+ import { addDate, getNow, formatRelativeZoned, Temporal } from "@northguild/gmt";
165
161
  ```
166
162
 
167
- - `Temporal`: re-exported from `@js-temporal/polyfill`
168
- - `duration`: ISO 8601 duration string parsing, validation, and arithmetic
169
- - `plain`: timezone-free helpers
170
- - `zoned`: timezone-aware helpers
171
- - `unix`: Unix epoch (seconds or milliseconds) helpers
172
- - `utc`: UTC instant helpers
173
- - `regex`: low-level regex building blocks
163
+ The twelve namespace subpaths:
164
+
165
+ - `@northguild/gmt/calendar`: ISO week and ordinal dates, quarter and fiscal periods, zone-aware bucketing, and business calendars with holiday sets and roll conventions
166
+ - `@northguild/gmt/duration`: ISO 8601 duration string parsing, validation, and arithmetic
167
+ - `@northguild/gmt/instant`: the instant-plus-offset pair, and explicit resolution of zoneless local wall times
168
+ - `@northguild/gmt/interval`: half-open `[start, end)` interval algebra over instants — overlap, intersect, clamp, merge, subtract, split, sum
169
+ - `@northguild/gmt/plain`: timezone-free helpers
170
+ - `@northguild/gmt/precision`: nanosecond (`bigint`) instants, their JSON bridge, storage truncation, and foreign epoch bridges
171
+ - `@northguild/gmt/span`: elapsed and wall-clock durations between two timestamps, as raw numbers
172
+ - `@northguild/gmt/zoned`: timezone-aware helpers
173
+ - `@northguild/gmt/unix`: Unix epoch (seconds or milliseconds) helpers
174
+ - `@northguild/gmt/utc`: UTC instant helpers
175
+ - `@northguild/gmt/regex`: low-level regex building blocks
176
+ - `@northguild/gmt/types`: the shared option and unit types
177
+
178
+ Every namespace subpath except `types` also re-exports `Temporal`, `Intl` and `toTemporalInstant`, so `import { Temporal, addZoned } from "@northguild/gmt/zoned"` needs no second import.
174
179
 
175
- You can also import subpaths directly:
180
+ Every namespace except `regex` and `types` also exposes its modules as subpaths,
181
+ `@northguild/gmt/<namespace>/<module>`:
176
182
 
177
183
  ```typescript
178
- import { addDate, getNow, formatRelativeZoned } from "@northguild/gmt";
184
+ import { getZonedNow } from "@northguild/gmt/zoned";
185
+ import { addDateTime, diffDate } from "@northguild/gmt/plain/calculate";
186
+ import type { BusinessCalendar } from "@northguild/gmt/types";
179
187
  ```
180
188
 
181
189
  ## Quick Start
@@ -192,8 +200,8 @@ import {
192
200
  isBeforeDateTime,
193
201
  } from "@northguild/gmt";
194
202
 
195
- addDate("2026-01-01", 90, "day");
196
- // "2026-03-32" is impossible, so Temporal normalizes correctly -> "2026-04-01"
203
+ addDate("2026-01-01", { days: 90 });
204
+ // "2026-04-01"
197
205
 
198
206
  addBusinessDays("2024-03-15", 1);
199
207
  // "2024-03-18" (skips weekend)
@@ -201,7 +209,7 @@ addBusinessDays("2024-03-15", 1);
201
209
  subtractBusinessDays("2024-03-18", 1);
202
210
  // "2024-03-15" (skips weekend)
203
211
 
204
- diffDateTime("2024-03-17T12:00:00", "2024-03-17T12:30:00", "minute");
212
+ diffDateTime("2024-03-17T12:00:00", "2024-03-17T12:30:00", "minutes");
205
213
  // 30
206
214
 
207
215
  areDatesEqual("2026-03-17", "2026-03-17T09:00:00");
@@ -211,7 +219,7 @@ isBeforeDateTime("2026-03-17T09:00:00", "2026-03-17T10:00:00");
211
219
  // true
212
220
  ```
213
221
 
214
- `add*`/`subtract*` accept an optional `overflow` (`"constrain"` (default) | `"reject"`) to control out-of-range results (e.g. adding a month to Jan 31), and `diff*` accept optional `smallestUnit`/`roundingIncrement`/`roundingMode` to round the computed difference:
222
+ `add*`/`subtract*` accept an optional `overflow` (`"constrain"` (default) | `"reject"`) to control out-of-range results (e.g. adding a month to Jan 31) — except `addTime`/`subtractTime`, which take no options argument because a clock time wraps (`addTime("23:00:00", { hours: 2 })` is `"01:00:00"`), as Temporal's `PlainTime#add` does — and `diff*` accept optional `smallestUnit`/`roundingIncrement`/`roundingMode` to round the computed difference:
215
223
 
216
224
  ```typescript
217
225
  import { addDate, diffDate } from "@northguild/gmt";
@@ -219,7 +227,10 @@ import { addDate, diffDate } from "@northguild/gmt";
219
227
  addDate("2024-01-31", { months: 1 }, { overflow: "reject" });
220
228
  // "" — Feb 31 doesn't exist and overflow: "reject" refuses to clamp it
221
229
 
222
- diffDate("2023-01-01", "2023-01-10", "week", {
230
+ addDate("2024-02-29", { years: 1 });
231
+ // "2025-02-28" — "constrain" (the default) clamps to the last valid day, as Temporal does
232
+
233
+ diffDate("2023-01-01", "2023-01-10", "weeks", {
223
234
  smallestUnit: "week",
224
235
  roundingMode: "halfExpand",
225
236
  });
@@ -237,14 +248,20 @@ setDate("2024-01-31", { month: 2 });
237
248
  setZoned(
238
249
  "2024-11-03T01:45:00-05:00[America/New_York]",
239
250
  { minute: 0 },
240
- {
241
- disambiguation: "reject",
242
- },
251
+ { disambiguation: "reject" },
243
252
  );
244
- // "" — offset defaults to "ignore" so disambiguation actually fires on this fall-back overlap
253
+ // "2024-11-03T01:00:00-05:00[America/New_York]" — offset defaults to "prefer", as Temporal's
254
+ // ZonedDateTime#with does: the source's -05:00 is still valid, so it is kept
255
+
256
+ setZoned(
257
+ "2024-11-03T01:45:00-05:00[America/New_York]",
258
+ { minute: 0 },
259
+ { disambiguation: "reject", offset: "ignore" },
260
+ );
261
+ // "" — offset "ignore" re-resolves the repeated 01:00, and "reject" fires on the fall-back overlap
245
262
  ```
246
263
 
247
- `setZoned`/`setUnix`/`setUtc` also accept `disambiguation` and `offset` for DST gap/overlap control — see [DST Disambiguation](../../docs/dst-disambiguation.md).
264
+ `setZoned`/`setUnix` also accept `disambiguation` and `offset` for DST gap/overlap control (`setUtc` takes only `overflow`: a UTC wall clock is never ambiguous) — see [DST Disambiguation](../../docs/dst-disambiguation.md).
248
265
 
249
266
  `cycleDate`/`cycleDateTime`/`cycleTime`/`cycleZoned` adjust a single field and **wrap** at that field's own min/max instead of carrying into the next larger field — the datepicker-segment-editing primitive `add*` can't express, since overflowing into the next field is exactly what `add*` is for:
250
267
 
@@ -262,9 +279,9 @@ cycleZoned("2024-03-10T01:30:00-06:00[America/Chicago]", "hour", 1);
262
279
  // gap; disambiguation ("compatible" by default) resolves it the same way setZoned does
263
280
  ```
264
281
 
265
- `cycleZoned` also accepts `disambiguation` and `offset` (default `offset: "ignore"`) for the same DST gap/overlap control as `setZoned` — see [DST Disambiguation](../../docs/dst-disambiguation.md). `options.round` on any of the four steps to the next multiple of `amount` rather than rounding to the nearest one, matching `@internationalized/date`'s `CycleOptions.round`.
282
+ `cycleZoned` also accepts `disambiguation` and `offset` (default `offset: "prefer"`) for the same DST gap/overlap control as `setZoned` — see [DST Disambiguation](../../docs/dst-disambiguation.md). `options.round` on any of the four steps to the next multiple of `amount` rather than rounding to the nearest one, matching `@internationalized/date`'s `CycleOptions.round`.
266
283
 
267
- `isWeekend`/`isZonedWeekend` check locale-specific weekend days (via `Intl.Locale`'s `weekInfo`) rather than assuming Saturday/Sunday:
284
+ `isWeekend`/`isZonedWeekend` check locale-specific weekend days (via `Intl.Locale#getWeekInfo()`, falling back to `weekInfo`) rather than assuming Saturday/Sunday:
268
285
 
269
286
  ```typescript
270
287
  import { isWeekend, isZonedWeekend } from "@northguild/gmt";
@@ -279,7 +296,7 @@ isZonedWeekend("2024-02-04T10:00:00+02:00[Asia/Jerusalem]", "he-IL");
279
296
  // false (Sunday isn't part of he-IL's weekend)
280
297
  ```
281
298
 
282
- `isBusinessDay` returns true for fixed ISO Monday–Friday business days (Mon=1 … Fri=5), locale-agnostic and with no holiday calendar. It's the complement to locale-aware `isWeekend` and matches the boundary that `addBusinessDays`/`subtractBusinessDays` use:
299
+ `isBusinessDay` is the complement to locale-aware `isWeekend`, and shares its weekend rule with `addBusinessDays`/`subtractBusinessDays`. Called with one argument it uses fixed ISO Monday–Friday business days (Mon=1 … Fri=5), locale-agnostic and with no holidays; pass a `BusinessCalendar` to state the weekend and holidays yourself:
283
300
 
284
301
  ```typescript
285
302
  import { isBusinessDay } from "@northguild/gmt";
@@ -289,8 +306,81 @@ isBusinessDay("2024-02-05");
289
306
 
290
307
  isBusinessDay("2024-02-10");
291
308
  // false (Saturday)
309
+
310
+ isBusinessDay("2024-07-04", {
311
+ weekend: [6, 7],
312
+ holidays: ["2024-07-04"],
313
+ timeZone: "America/New_York",
314
+ });
315
+ // false (a holiday, though it's a Thursday)
292
316
  ```
293
317
 
318
+ ### Business calendars and roll conventions
319
+
320
+ A `BusinessCalendar` is `{ weekend: number[], holidays: string[], timeZone: string }`. The weekend is explicit ISO weekday numbers because Saturday–Sunday is not universal — much of the Middle East is Friday–Saturday, and some markets keep a one-day weekend. Holidays are yours to supply: GMT bundles no holiday table on the default import path, because holiday data is jurisdictional and changes annually, sometimes with days of notice. `timeZone` records which locality the calendar describes; the business-day functions take and return local dates and never read it, so a caller holding an instant reduces it with `floorToZone` first.
321
+
322
+ `isBusinessDay`, `addBusinessDays` and `subtractBusinessDays` all take a calendar as an optional trailing argument. The rest of the family requires one — there is no default weekend to fall back on:
323
+
324
+ ```typescript
325
+ import {
326
+ businessDaysBetween,
327
+ nextBusinessDay,
328
+ previousBusinessDay,
329
+ rollDate,
330
+ mergeCalendars,
331
+ isValidBusinessCalendar,
332
+ } from "@northguild/gmt";
333
+
334
+ const nyse = {
335
+ weekend: [6, 7],
336
+ holidays: ["2024-05-31", "2024-07-04"],
337
+ timeZone: "America/New_York",
338
+ };
339
+
340
+ businessDaysBetween("2024-07-01", "2024-07-05", nyse);
341
+ // 3 — start exclusive, end inclusive, and 4 July is a holiday
342
+
343
+ nextBusinessDay("2024-07-03", nyse);
344
+ // "2024-07-05" — strictly after, skipping the holiday
345
+
346
+ previousBusinessDay("2024-07-05", nyse);
347
+ // "2024-07-03"
348
+ ```
349
+
350
+ `rollDate` moves a date onto a working day by an explicit convention — `following`, `modifiedFollowing`, `preceding`, `modifiedPreceding`, `endOfMonth` or `none`. `following` and `preceding` are on-or-after and on-or-before, so they leave a working day alone; `nextBusinessDay`/`previousBusinessDay` are the strict neighbours:
351
+
352
+ ```typescript
353
+ rollDate("2024-05-31", "following", nyse);
354
+ // "2024-06-03" — forward past the weekend
355
+
356
+ rollDate("2024-05-31", "modifiedFollowing", nyse);
357
+ // "2024-05-30" — backward instead, because forward leaves May
358
+
359
+ rollDate("2024-03-15", "endOfMonth", nyse);
360
+ // "2024-03-29" — March's last working day; March ends on a Sunday
361
+
362
+ rollDate("2024-06-01", "none", nyse);
363
+ // "2024-06-01" — unadjusted, Saturday or not
364
+ ```
365
+
366
+ `mergeCalendars` composes jurisdictions: weekend rules and holidays union, so a date survives only if it is a working day in **every** input. That is the two-currency intersection FX settlement needs, and the two-port one an intermodal move needs:
367
+
368
+ ```typescript
369
+ const london = { weekend: [6, 7], holidays: ["2024-05-06"], timeZone: "Europe/London" };
370
+
371
+ const both = mergeCalendars([nyse, london]);
372
+ // { weekend: [6, 7], holidays: ["2024-05-06", "2024-05-31", "2024-07-04"], timeZone: "America/New_York" }
373
+ // timeZone is the first calendar's; the merged set spans localities that may disagree
374
+
375
+ isBusinessDay("2024-05-06", both);
376
+ // false — a UK holiday closes the merged calendar too
377
+
378
+ mergeCalendars([]);
379
+ // null
380
+ ```
381
+
382
+ `isValidBusinessCalendar` and `isValidRollConvention` narrow a candidate, so a misconfigured calendar or contract term can be told apart from bad date input when a function returns its sentinel.
383
+
294
384
  `isRelativeDay`/`isThisUnit`/`isPast`/`isFuture` are now-relative predicates — `isRelativeDay` subsumes `isToday`/`isYesterday`/`isTomorrow`, `isThisUnit` subsumes `isThisWeek`/`isThisMonth`/`isThisYear`. They compare against `getToday()`, so they depend on the **system clock and system timeZone**; the zoned variants (`isZonedRelativeDay`, `isZonedThisUnit`, `isZonedPast`, `isZonedFuture`) resolve "today"/"now" in the value's own timeZone instead, for deterministic results regardless of the host machine's timeZone:
295
385
 
296
386
  ```typescript
@@ -375,8 +465,8 @@ getLocaleDayOfWeek("2024-02-25", "en-US");
375
465
  getLocaleDayOfWeek("2024-02-26", "fr-FR");
376
466
  // 0 (Monday = first day of fr-FR week)
377
467
 
378
- getLocaleDayOfWeek("2024-02-24", "he-IL");
379
- // 0 (Saturday = first day of he-IL week)
468
+ getLocaleDayOfWeek("2024-02-24", "ar-EG");
469
+ // 0 (Saturday = first day of ar-EG week)
380
470
 
381
471
  getLocaleZonedDayOfWeek("2024-02-25T12:00:00+00:00[UTC]", "en-US");
382
472
  // 0
@@ -447,153 +537,127 @@ Supported tokens include `yyyy`/`MM`/`dd`/`HH`/`mm`/`ss`/`SSS` for fixed-width f
447
537
 
448
538
  ### Calendar systems
449
539
 
450
- GMT's `CalendarSystem` type (`"gregorian" | "hebrew" | "islamic-civil" | "islamic-tabular" | "islamic-umalqura" | "japanese" | "buddhist" | "taiwan" | "persian" | "indian" | "ethiopic" | "ethiopic-amete-alem" | "coptic"`, extended by later stories) and `convertDateToCalendar` express a date in a non-Gregorian calendar system, built almost entirely on Temporal's native calendar support — no bundled leap-year tables or ported arithmetic, with one deliberate exception (the Ethiopic family, covered below).
540
+ `convertDateToCalendar` expresses a date in another calendar system. GMT writes the standard form, exactly what `Temporal.PlainDate.prototype.toString()` writes: the ISO 8601 date, then an RFC 9557 `[u-ca=<id>]` annotation naming the calendar. The digits stay ISO. The annotation says which calendar the date is presented and computed in (RFC 9557 §3.3), so the string means the same date to GMT, to Temporal and to any other RFC 9557 parser.
451
541
 
452
542
  ```typescript
453
543
  import { convertDateToCalendar } from "@northguild/gmt";
454
544
 
455
545
  convertDateToCalendar("2024-10-03", "hebrew");
456
- // "5785-01-01[u-ca=hebrew]" — Rosh Hashanah 5785
546
+ // "2024-10-03[u-ca=hebrew]" — Rosh Hashanah 5785, written as its ISO date
457
547
 
458
- convertDateToCalendar("5785-01-01[u-ca=hebrew]", "gregorian");
459
- // "2024-10-03" — round-trips back
548
+ convertDateToCalendar("2024-10-03[u-ca=hebrew]", "iso8601");
549
+ // "2024-10-03" — iso8601 writes no annotation
460
550
 
461
- convertDateToCalendar("2024-10-03", "islamic-umalqura");
462
- // "1446-03-30[u-ca=islamic-umalqura]" — Saudi Umm al-Qura calendar
551
+ convertDateToCalendar("2024-10-03", "gregory");
552
+ // "2024-10-03[u-ca=gregory]" — gregory is its own calendar, so it is annotated
463
553
 
464
554
  convertDateToCalendar("invalid", "hebrew");
465
555
  // ""
466
556
  ```
467
557
 
468
- The output string shape is the key design decision here, and it deliberately **diverges from Temporal's own** `[u-ca=...]` convention. Temporal's `Temporal.PlainDate.prototype.toString()` always keeps the ISO/proleptic-Gregorian year-month-day digits and only tags the calendar (`"2024-10-03[u-ca=hebrew]"` — still literally October 3rd's Gregorian digits). That hides the calendar's own fields behind calendar-aware accessors, which GMT's string-only contract has no place for. GMT's annotated string instead carries the **calendar-native** year/month/day — Hebrew year 5785, not 2024 — so the calendar-system concept is visible directly in the string, not just in an object property. A plain, unannotated ISO string is always treated as (and always produced for) the `"gregorian"` calendar, so every existing GMT function keeps working unchanged.
469
-
470
- Hebrew years can run 12 or 13 months (7 leap years per 19-year Metonic cycle insert a 13th month, Adar I, before the regular Adar); `convertDateToCalendar` resolves this the same way Temporal does internally, via ordinal month numbers (`1`-`13`) rather than fixed month names, so no month-counting logic lives in GMT itself.
558
+ `CalendarSystem` is `"iso8601" | "gregory" | "hebrew" | "islamic-civil" | "islamic-tbla" | "islamic-umalqura" | "japanese" | "buddhist" | "roc" | "persian" | "indian" | "ethiopic" | "ethioaa" | "coptic"`: the canonical BCP 47 / CLDR `calendar.xml` ids Temporal uses, in the annotation and as function arguments. An alias or another letter case is canonicalized the way Temporal's `withCalendar` does it (`"ethiopic-amete-alem"` writes `[u-ca=ethioaa]`, `[u-ca=HEBREW]` reads as `hebrew`), and the canonical id is always written. `gregorian`, `taiwan` and `islamic-tabular` are not calendar ids, so they return the sentinel. `chinese`, `dangi`, `islamic` and `islamic-rgsa` are not supported.
471
559
 
472
- Three Islamic (Hijri) calendar variants are supported, and they are **not interchangeable** — each resolves the same Gregorian date to different calendar-native digits:
560
+ Every calendar-accepting function reads annotations the way `Temporal.PlainDate.from` / `Temporal.ZonedDateTime.from` read them. The critical flag is accepted and not written back (`"2024-10-03[!u-ca=hebrew]"` converts to `"2024-10-03[u-ca=hebrew]"`), and an unknown critical annotation is rejected. `;era=` is not RFC 9557 syntax and is rejected. A year is four digits, or a sign and six (`"+275760-09-13[u-ca=hebrew]"`), across Temporal's whole range, `-271821-04-19` to `+275760-09-13`.
473
561
 
474
- - `"islamic-civil"` — a fixed 30-year leap-year cycle, Friday epoch (`1 AH = 622-07-19`).
475
- - `"islamic-tabular"` — the same style of fixed arithmetic cycle, but a Thursday epoch one day earlier (`1 AH = 622-07-18`); maps to Temporal's `"islamic-tbla"` calendar id internally, though GMT's own string annotation always reads `[u-ca=islamic-tabular]`.
476
- - `"islamic-umalqura"` — the Saudi civil calendar, based on Umm al-Qura University's own published tables rather than a fixed arithmetic rule. This is **not** approximated by the tabular variant's math — `convertDateToCalendar("2020-02-24", "islamic-umalqura")` returns `"1441-06-30[u-ca=islamic-umalqura]"` while the same input under `"islamic-tabular"` returns `"1441-07-01[u-ca=islamic-tabular]"`, a genuine one-day divergence, not a rounding difference.
562
+ **Calendar fields are read values, never string content.** The Hebrew year 5785, the Japanese era `reiwa` and year 6, and the Umm al-Qura day number are all properties of the date, so GMT never puts them in a string. No standard defines a machine-readable date string with calendar-native digits, and such a string would be ambiguous: `5785-01-01[u-ca=hebrew]` is also a valid RFC 9557 string for ISO year 5785. When you need a field for display, format the date with `Intl.DateTimeFormat` and its `calendar` option, or read it from Temporal, which every GMT entry point re-exports:
477
563
 
478
- Five era-based solar calendars round out the set. Unlike Hebrew and the Islamic variants, none of these needed new leap-year logic — each is either Gregorian-shaped with a different year numbering layered on top, or a distinct-but-simple solar calendar, so they were materially less work than Hebrew or Islamic:
564
+ ```typescript
565
+ import { Temporal } from "@northguild/gmt";
479
566
 
480
- - `"buddhist"` — Gregorian day/month structure, a fixed `+543` year offset (`convertDateToCalendar("2024-10-03", "buddhist")` → `"2567-10-03[u-ca=buddhist]"`). One continuous era, no reset.
481
- - `"taiwan"` — Gregorian day/month structure, year numbering reset at 1912 (the Republic of China's founding): `2024` → `"0113-10-03[u-ca=taiwan]"` (`2024 - 1911`). Dates before 1912 count backward through Temporal's inverse era instead of going negative in the way a plain offset would — `convertDateToCalendar("1911-12-31", "taiwan")` is `"0000-12-31[u-ca=taiwan]"`, not `"-0001-12-31"`.
482
- - `"persian"` — a genuinely distinct solar calendar (not Gregorian-derived): own month lengths (6 months of 31 days, 5 of 30, a 29/30-day 12th month) and its own 33-year leap-year cycle (a year is leap when `(25 × year + 11) mod 33 < 8`), verified against `@internationalized/date`'s `PersianCalendar.ts` rather than assumed from the offset-only calendars above.
483
- - `"indian"` — the Indian National Calendar (Saka era, epoch 78 CE). Also not offset-only: its leap-year alignment follows the Gregorian rule rather than an independent cycle — the calendar's first month is 31 days in a Gregorian leap year, 30 otherwise, which is why its Saka-year boundary (`convertDateToCalendar("2024-03-20", "indian")` → `"1945-12-30[u-ca=indian]"`, `convertDateToCalendar("2024-03-21", "indian")` → `"1946-01-01[u-ca=indian]"`) doesn't land on a fixed day-of-year every year.
484
- - `"japanese"` — era-based: the year resets to `1` at each imperial era change (Meiji, Taishō, Shōwa, Heisei, Reiwa). This is the one calendar where GMT's annotated string carries an era-relative year instead of the calendar's plain native year, and needs its own explanation below.
567
+ Temporal.PlainDate.from("2024-10-03[u-ca=hebrew]").year; // 5785
568
+ Temporal.PlainDate.from("2024-10-03[u-ca=japanese]").eraYear; // 6
569
+ ```
485
570
 
486
- **Why `"japanese"` gets a different string shape.** Every other supported calendar's plain `year` field is exactly what belongs in GMT's annotated string — Hebrew year 5785, Taiwan year 113, and so on are each already the single number that identifies the year. Japanese is the exception: Temporal's `.year` for the `"japanese"` calendar stays **proleptic** across era changes (it doesn't reset — `1912-07-30`, the first day of Taishō, still reports `.year === 1912`, not `1`), because Temporal's `.year` is designed to be a stable sort key, not a display value. Using it directly would silently contradict the calendar's entire reason for existing. So `convertDateToCalendar` uses Temporal's `.eraYear` (the field that _does_ reset) paired with the era name, tagged onto the annotation as `;era=<name>`:
571
+ The three Islamic variants are different calendars, not spellings of one. On ISO 2020-02-24, `islamic-civil` (Friday epoch) reads day 29 of month 6 of 1441, `islamic-tbla` (the same arithmetic cycle with a Thursday epoch) reads day 1 of month 7, and `islamic-umalqura` (the Saudi civil calendar, from Umm al-Qura University's published tables) reads day 30 of month 6. Month arithmetic follows each calendar's own months, so the same `+1 month` lands on different ISO dates:
487
572
 
488
573
  ```typescript
489
- convertDateToCalendar("2024-10-03", "japanese");
490
- // "0006-10-03[u-ca=japanese;era=reiwa]" — year 6 of the Reiwa era, not the proleptic 2024
574
+ import { addDate } from "@northguild/gmt";
491
575
 
492
- convertDateToCalendar("1912-07-30", "japanese");
493
- // "0001-07-30[u-ca=japanese;era=taisho]" — the first day of Taishō reads year 1
576
+ addDate("2020-02-24[u-ca=islamic-umalqura]", { months: 1 });
577
+ // "2020-03-24[u-ca=islamic-umalqura]"
494
578
 
495
- convertDateToCalendar("0001-07-30[u-ca=japanese;era=taisho]", "gregorian");
496
- // "1912-07-30" — round-trips back through the era + eraYear pair
579
+ addDate("2020-02-24[u-ca=islamic-tbla]", { months: 1 });
580
+ // "2020-03-25[u-ca=islamic-tbla]"
497
581
  ```
498
582
 
499
- `@internationalized/date` documents pre-Meiji (before 1868-10-23) dates as unsupported for its Japanese calendar. GMT does not replicate that restriction: since `convertDateToCalendar` is built entirely on Temporal's own calendar support rather than a ported implementation, and Temporal resolves those dates correctly under a synthetic `"japanese"` era (with an ISO-aligned `eraYear`), rejecting them would mean writing new validation solely to reproduce another library's gap rather than an actual GMT limitation. `convertDateToCalendar("1800-01-01", "japanese")` returns `"1800-01-01[u-ca=japanese;era=japanese]"` rather than `""`.
583
+ `ethiopic` and `coptic` compute in `ethioaa`. The three share months, days and arithmetic and differ only by a constant year offset, and `@js-temporal/polyfill` 0.5.1 throws reading `ethiopic` and `coptic` fields under ICU 78 or later (`Temporal.PlainDate.from("2024-10-03[u-ca=ethiopic]").year` throws there). GMT's results are the same either way, and only the written id differs. Where the polyfill or the runtime's ICU computes a calendar wrongly (Buddhist before 1582, Hebrew years ≤ 0, Indian dates before ISO year 1, dates near either range limit), GMT's arithmetic computes the specified answer instead. Each correction probes the runtime once and stays inactive where the runtime is already right.
500
584
 
501
- Three Ethiopic-family calendars round out the set, all sharing one 13-month structure (12 months of 30 days, plus a short Pagume/Nasie 13th month of 5 days, or 6 in a leap year) but differing in epoch:
585
+ #### Calendar-aware interval and duration arithmetic
502
586
 
503
- - `"ethiopic"` — the modern Ethiopian calendar, era-based like `"japanese"`: it resets to the Amete Mihret ("Year of Mercy"/Incarnation) era at its own epoch (~AD 8), so `convertDateToCalendar("2024-10-03", "ethiopic")` returns `"2017-01-23[u-ca=ethiopic;era=ethiopic]"` — year 2017, not a 5-digit proleptic number. Dates before that epoch resolve under the Amete Alem ("Year of the World") era instead: `convertDateToCalendar("0001-01-01", "ethiopic")` → `"5493-05-08[u-ca=ethiopic;era=ethioaa]"`.
504
- - `"ethiopic-amete-alem"` — the same calendar, but always counted continuously from the Amete Alem epoch (~5493 BCE), never resetting: `convertDateToCalendar("2024-10-03", "ethiopic-amete-alem")` → `"7517-01-23[u-ca=ethiopic-amete-alem]"`.
505
- - `"coptic"` — the Coptic Orthodox calendar: same 13-month structure, its own epoch (the Diocletian/Martyrs era, AD 284): `convertDateToCalendar("2024-10-03", "coptic")` → `"1741-01-23[u-ca=coptic]"`.
587
+ A calendar-annotated date feeds `addDate`/`subtractDate`/`diffDate`/`diffDateAsDuration` and every `Date`-suffixed `plain/interval/*` function (`intervalContainsDate`, `intervalCountDate`, `splitIntervalByUnitDate`, and the rest). Calendar units ("add 1 month") resolve in the value's own calendar:
506
588
 
507
- **Why this family isn't built on Temporal's native `"ethiopic"`/`"coptic"` calendar ids, unlike every other calendar above.** `@js-temporal/polyfill`'s implementation of these two calendars resolves year/era by formatting the date through `Intl.DateTimeFormat` and matching the result against a hardcoded era-name table — unlike calendars with a fixed year-offset from ISO (Buddhist, Taiwan, and Ethiopic Amete Alem, which the polyfill computes with pure arithmetic and never touches `Intl` for). CLDR's era-name output for these two calendars changed between ICU versions: under ICU ≥ 78 (the version Node 22 and 24 both bundle — this is an ICU-version boundary, not a Node-major one), every read _or_ write of Temporal's `"ethiopic"`/`"coptic"` calendar ids throws a `RangeError` (`Era am (ISO year …) was not matched by any era`) — confirmed directly, not a hypothetical. `"ethiopic-amete-alem"` (Temporal's `"ethioaa"` id) is unaffected, since it has no era at all and is resolved with pure arithmetic. GMT routes around the bug rather than inheriting it: month/day are identical across all three calendars (they share one annual cycle), so `convertDateToCalendar` reads/writes them via the safe `"ethioaa"` calendar and computes each calendar's own displayed year (+ era, for `"ethiopic"`) with GMT-owned arithmetic — ported from the same `EthiopicHelper`/`CopticHelper` epoch constants `@js-temporal/polyfill` itself uses internally, just evaluated in GMT's code instead of through the ICU-dependent path. See `internal/ethiopicFamilyCalendar.ts` for the implementation.
589
+ ```typescript
590
+ import { addDate, diffDate, diffDateAsDuration, durationAs, intervalCountDate } from "@northguild/gmt";
508
591
 
509
- #### Calendar-aware interval and duration arithmetic
592
+ addDate("2024-02-24[u-ca=hebrew]", { months: 1 });
593
+ // "2024-03-25[u-ca=hebrew]" — 15 Adar I 5784 to 15 Adar II; addDate("2024-02-24", { months: 1 }) is "2024-03-24"
510
594
 
511
- `convertDateToCalendar`'s output feeds directly back into `addDate`/`subtractDate`/`diffDate`/`diffDateAsDuration` and every `Date`-suffixed `plain/interval/*` function (`intervalContainsDate`, `intervalCountDate`, `splitIntervalByUnitDate`, and the rest) — calendar-unit arithmetic ("add 1 month") resolves in the value's own calendar rather than being rejected or silently treated as Gregorian:
595
+ intervalCountDate("2023-09-16[u-ca=hebrew]", "2024-10-03[u-ca=hebrew]", "month");
596
+ // 13 — Hebrew leap year 5784 has 13 months; the same ISO span touches 14 ISO months
512
597
 
513
- ```typescript
514
- addDate("5784-06-15[u-ca=hebrew]", { months: 1 });
515
- // "5784-07-15[u-ca=hebrew]" — Adar I (a leap-only 30-day month) -> Adar
598
+ diffDate("2024-03-11[u-ca=hebrew]", "2024-04-10[u-ca=hebrew]", "months");
599
+ // 1 — 1 Adar II to 2 Nisan; the bare ISO dates are 0 whole months apart
516
600
 
517
- intervalCountDate(
518
- "5784-01-01[u-ca=hebrew]",
519
- "5785-01-01[u-ca=hebrew]",
520
- "month",
521
- );
522
- // 13 — a Hebrew leap year crosses 13 month boundaries, not 12 (ISO's answer for the same span)
601
+ diffDateAsDuration("2024-08-31[u-ca=buddhist]", "2024-09-30[u-ca=buddhist]", "months");
602
+ // "P30D" — not "P1M": a month counts only once the end reaches the same day of the next month
523
603
 
524
- diffDate("5784-06-15[u-ca=hebrew]", "5784-07-15[u-ca=hebrew]", "months");
525
- // 1 — measured in the shared calendar when both endpoints carry the same tag
604
+ durationAs("P1Y", "days", { relativeTo: "2023-09-16[u-ca=hebrew]" });
605
+ // 383 — Hebrew leap year 5784; relativeTo "2023-09-16" gives 366
526
606
  ```
527
607
 
528
- `utc/` and `unix/` reject a `[u-ca=...]` calendar annotation outright, and `duration/`'s `relativeTo` option accepts GMT's calendar-annotated string (not Temporal's own differently-shaped `[u-ca=...]` convention) when a calendar-aware anchor is needed:
608
+ Month and year differences follow Temporal's `NonISODateSurpasses` in every calendar, so a span from a month's last day into a shorter month is days, not a month. This matches the ISO calendar (`diffDateAsDuration("2024-08-31", "2024-09-30", "months")` is `"P30D"`), and applies to `diffDate*`, `intervalLength*`, `intervalCount*` and `diffZoned*` alike.
529
609
 
530
- ```typescript
531
- durationAs("P1Y", "days", { relativeTo: "5784-06-15[u-ca=hebrew]" });
532
- // 385 — a Hebrew leap year, not the 366 a Gregorian P1Y would total
533
- ```
610
+ `utc/` reads a UTC string as `Temporal.Instant.from` does, so a `[u-ca=...]` annotation is ignored there: `isValidUtc("2024-01-01T00:00:00Z[u-ca=hebrew]")` is `true`. `duration/`'s `relativeTo` reads a calendar-annotated string as Temporal's `ParseTemporalRelativeToString` does: zoned when it carries a time zone annotation, otherwise a date.
611
+
612
+ Two values that name different calendars follow Temporal's `CalendarEquals`. A bare ISO string names `iso8601`.
534
613
 
535
- `zoned/` has its own calendar-annotated grammar as of E7 (issue #152) — see "Calendar-aware zoned datetimes" below.
614
+ - **Differences return the sentinel** on a mismatch, as Temporal's `until` throws: `diffDate`, `diffDateAsDuration`, `intervalCountDate`, `intervalLengthDate`, `splitIntervalByUnitDate` and `intervalOverlappingDaysDate`.
615
+ - **Ordering accepts mixed calendars**, as `Temporal.PlainDate.compare` has no calendar check: `intervalContainsDate`, `intervalsOverlapDate`, `intervalAbutsDate`, `intervalEngulfsDate` and `isValidDateInterval`.
616
+ - **Functions that return a date value** (`intervalUnionDate`, `intervalIntersectionDate`, `intervalDifferenceDate`, `intervalXorDate`, `intervalXorAllDate`, `mergeIntervalsDate`, `intervalDivideEquallyDate`, `intervalSplitAtDate`) require one shared calendar and return `null`/`[]` on a mismatch, because no calendar can be chosen for the output.
617
+
618
+ ```typescript
619
+ intervalCountDate("2023-09-16[u-ca=hebrew]", "2024-10-03", "month");
620
+ // null — hebrew and iso8601
536
621
 
537
- Interval functions that only compare or diff absolute instants (`intervalContainsDate`, `intervalsOverlapDate`, `intervalAbutsDate`, `intervalEngulfsDate`, `isValidDateInterval`, `intervalOverlappingDaysDate`) accept endpoints tagged with _different_ calendars, since ordering and day-counting don't depend on which calendar a date is expressed in. Functions that return a date _value_ (`intervalUnionDate`, `intervalIntersectionDate`, `intervalDifferenceDate`, `intervalXorDate`, `intervalXorAllDate`, `mergeIntervalsDate`, `intervalDivideEquallyDate`, `intervalSplitAtDate`) require every argument to share one calendar and return their sentinel (`null`/`[]`) on a mismatch, since there's no principled way to pick which calendar the output should be expressed in. See `context/roadmap/issues/E.md`'s "E5 outcome" section for the full per-function audit, including the negatives ("no change needed, verified why") this scope boundary implies — `*DateTime`/`*Time` variants, `unix/`, and `utc/` were all confirmed unaffected rather than assumed to be.
622
+ intervalContainsDate("2023-09-16[u-ca=hebrew]", "2024-10-03", "2024-01-01[u-ca=roc]");
623
+ // true — ordering compares the ISO dates
624
+ ```
538
625
 
539
626
  #### Calendar-aware zoned datetimes
540
627
 
541
- A calendar-annotated `ZonedDateTime` string adds a time, a UTC offset and an IANA zone to the
542
- plain grammar above:
628
+ A calendar-annotated `ZonedDateTime` string is the RFC 9557 form `Temporal.ZonedDateTime.prototype.toString()` writes: the time zone annotation first, then the calendar (RFC 9557 §4.1):
543
629
 
544
630
  ```
545
- <calendar-native-date>T<time><offset>[u-ca=<id>[;era=<era>]][<timeZone>]
631
+ <date>T<time><offset>[<timeZone>][u-ca=<id>]
546
632
 
547
- 5784-06-15T14:30:00-05:00[u-ca=hebrew][America/New_York]
548
- 0031-04-30T12:00:00+09:00[u-ca=japanese;era=heisei][Asia/Tokyo]
549
- 7517-12-30T00:30:00-04:00[u-ca=ethiopic-amete-alem][America/Santiago]
633
+ 2024-02-24T14:30:00-05:00[America/New_York][u-ca=hebrew]
634
+ 2019-04-30T12:00:00+09:00[Asia/Tokyo][u-ca=japanese]
550
635
  ```
551
636
 
552
- `convertZonedToCalendar` produces it, and `isValidCalendarZonedDateTime` validates it:
637
+ `convertZonedToCalendar` produces it, and `isValidCalendarZonedDateTime` validates it. A calendar annotation before the zone is not RFC 9557 and returns the sentinel:
553
638
 
554
639
  ```typescript
640
+ import { addZoned, convertZonedToCalendar } from "@northguild/gmt";
641
+
555
642
  convertZonedToCalendar("2024-10-03T14:30:45-04:00[America/New_York]", "hebrew");
556
- // "5785-01-01T14:30:45-04:00[u-ca=hebrew][America/New_York]"
643
+ // "2024-10-03T14:30:45-04:00[America/New_York][u-ca=hebrew]"
557
644
 
558
- addZoned("5784-06-15T14:30:00-05:00[u-ca=hebrew][America/New_York]", {
559
- months: 1,
560
- });
561
- // "5784-07-15T14:30:00-04:00[u-ca=hebrew][America/New_York]"
562
- // Adar I -> Adar AND EST -> EDT, resolved in one call. No ordering of a plain/ calendar
645
+ convertZonedToCalendar("2024-10-03T14:30:45-04:00[u-ca=hebrew][America/New_York]", "iso8601");
646
+ // "" — the calendar annotation must follow the zone
647
+
648
+ addZoned("2024-02-24T14:30:00-05:00[America/New_York][u-ca=hebrew]", { months: 1 });
649
+ // "2024-03-25T14:30:00-04:00[America/New_York][u-ca=hebrew]"
650
+ // Adar I -> Adar II AND EST -> EDT, resolved in one call. No ordering of a plain/ calendar
563
651
  // operation and a zoned/ conversion produces this: do the calendar step first and DST is
564
652
  // applied to an already-resolved wall time; do the zoned step first and there is no calendar
565
653
  // left to step in.
654
+ ```
566
655
 
567
- addZoned("0031-04-30T12:00:00+09:00[u-ca=japanese;era=heisei][Asia/Tokyo]", {
568
- days: 1,
569
- });
570
- // "0001-05-01T12:00:00+09:00[u-ca=japanese;era=reiwa][Asia/Tokyo]" — era re-derived, never copied
571
- ```
572
-
573
- > **The `[u-ca=...]` segment comes BEFORE `[timeZone]` — the reverse of RFC 9557.** This is
574
- > deliberate. GMT's digits are calendar-native (Hebrew year 5784, not ISO year 5784), so the
575
- > string is never valid RFC 9557 to begin with, and the `;era=` suffix is not valid RFC 9557 at
576
- > any ordering. Writing it in RFC order is actively dangerous:
577
- > `Temporal.ZonedDateTime.from("5784-01-01T14:30:00-05:00[America/New_York][u-ca=hebrew]")`
578
- > _succeeds_, silently reading 5784 as an ISO year — a ~3760-year misparse with no error. GMT's
579
- > ordering makes that shape uniformly rejected instead.
580
-
581
- Scope: `addZoned`, `subtractZoned`, `diffZoned`, `diffZonedAsDuration`, `convertZonedToCalendar`,
582
- and the `zoned/interval/*` family. Everything else in `zoned/` still rejects the annotation —
583
- `isValidZonedDateTime` is unchanged, so a function that has not opted in fails closed rather than
584
- silently answering in the wrong calendar. `addZonedBusinessDays`/`subtractZonedBusinessDays` stay
585
- out by design: day-of-week is ISO-fixed in every supported calendar, so a tag would change nothing
586
- while implying it might.
587
-
588
- Mixed-calendar endpoints follow the same split as `plain/`: ordering functions
589
- (`intervalContainsZoned`, `intervalsOverlapZoned`, `intervalAbutsZoned`, `intervalEngulfsZoned`,
590
- `intervalOverlappingDaysZoned`, `isValidCalendarZonedInterval`) accept them; the eight
591
- value-returning set operations require one shared calendar and return their sentinel on a
592
- mismatch. Measurement functions (`diffZoned`, `diffZonedAsDuration`, `intervalCountZoned`,
593
- `intervalLengthZoned`, `splitIntervalByUnitZoned`) measure in the endpoints' shared calendar when
594
- both tags match and fall back to Gregorian otherwise — mandatory here rather than merely
595
- convenient, because `Temporal.ZonedDateTime.prototype.until` throws across mismatched calendars
596
- for _every_ unit, including pure time units like hours.
656
+ Scope: `addZoned`, `subtractZoned`, `diffZoned`, `diffZonedAsDuration`, `convertZonedToCalendar`, and the `zoned/interval/*` family. Everything else in `zoned/`, and `isValidZonedDateTime`, accepts `[u-ca=iso8601]` and rejects any other calendar, so a function that has not opted in fails closed rather than silently answering in the wrong calendar. `addZonedBusinessDays`/`subtractZonedBusinessDays` stay out by design: day-of-week is ISO-fixed in every supported calendar, so a tag would change nothing while implying it might.
657
+
658
+ Mixed-calendar endpoints follow the same rules as `plain/`. Ordering functions (`intervalContainsZoned`, `intervalsOverlapZoned`, `intervalAbutsZoned`, `intervalEngulfsZoned`, `isValidCalendarZonedInterval`) accept them. The value-returning set operations require one shared calendar. Differences (`diffZoned`, `diffZonedAsDuration`, `intervalCountZoned`, `intervalLengthZoned`, `splitIntervalByUnitZoned`, `intervalOverlappingDaysZoned`) return their sentinel on a mismatch for every unit, including hours, as `Temporal.ZonedDateTime.prototype.until` throws across calendars.
659
+
660
+ **Migrating strings written before 1.16.0.** Earlier releases wrote the calendar's own year, month and day (`"5785-01-01[u-ca=hebrew]"` for ISO 2024-10-03), a `;era=` suffix, the zoned calendar annotation before the zone, and the ids `gregorian`, `taiwan`, `islamic-tabular` and `ethiopic-amete-alem` (now `iso8601`, `roc`, `islamic-tbla` and `ethioaa`). No converter exists: most old strings are also valid RFC 9557 strings for a different ISO date, and the two readings cannot be told apart. `convertDateToCalendar("5785-01-01[u-ca=hebrew]", "iso8601")` returns `"5785-01-01"`. Regenerate each stored value from its ISO date with `convertDateToCalendar` or `convertZonedToCalendar`.
597
661
 
598
662
  ### Durations
599
663
 
@@ -684,6 +748,8 @@ diffDateAsDuration("2024-03-10", "2024-04-05", "days");
684
748
 
685
749
  ### Intervals
686
750
 
751
+ > **One boundary model.** Every interval function in this section (`intervalsOverlapDate`, `intervalDifferenceUtc`, …) reads an interval as half-open, `[start, end)`: `start` is inside and `end` is not, as in the `interval/` namespace described under [Interval algebra](#interval-algebra) (SQL:2011 closed-open `PERIOD`, RFC 5545's non-inclusive `DTEND`, EWD831). Touching intervals share no instant, so they abut rather than overlap, and no function steps an endpoint by one unit. For a `Date` interval that means `end` is the first day **after** the period: pass `"2024-07-01"`, not `"2024-06-30"`, for the first half of 2024 (`addDate(lastDay, { days: 1 })`). Before 1.16.0 most positional families read intervals as closed `[start, end]`.
752
+
687
753
  Interval and range validators are available in two API shapes — **range validators** (matching `isValidDateRange`'s `{ value1, value2, options? }` object-param shape) and **interval validators** (`(start, end)` positional args, `start <= end` always):
688
754
 
689
755
  ```typescript
@@ -734,8 +800,8 @@ isValidZonedRange({
734
800
 
735
801
  Interval containment checks (`intervalContains*`) test whether a point or inner interval falls within an outer interval. Each supports two modes via an optional fourth argument:
736
802
 
737
- - 3-arg: `intervalContains(start, end, point)` — true when `start <= point <= end`
738
- - 4-arg: `intervalContains(start, end, innerStart, innerEnd)` — true when the inner interval is fully contained
803
+ - 3-arg: `intervalContains(start, end, point)` — true when `start <= point < end`
804
+ - 4-arg: `intervalContains(start, end, innerStart, innerEnd)` — true when the inner interval lies within the outer one and overlaps it, so an inner interval may share the outer `end`, but an empty inner interval at `end` is not contained
739
805
 
740
806
  ```typescript
741
807
  import {
@@ -751,6 +817,9 @@ import {
751
817
  intervalContainsDate("2024-01-01", "2024-12-31", "2024-06-15");
752
818
  // true
753
819
 
820
+ intervalContainsDate("2024-01-01", "2024-12-31", "2024-12-31");
821
+ // false (the end is excluded)
822
+
754
823
  intervalContainsTime("09:00:00", "17:00:00", "12:00:00");
755
824
  // true
756
825
 
@@ -779,9 +848,9 @@ intervalContainsTime("09:00:00", "17:00:00", "10:00:00", "16:00:00");
779
848
  // true
780
849
  ```
781
850
 
782
- All interval containment checks return `false` on invalid input (wrong type, malformed strings, leap seconds, inverted intervals, non-finite values for Unix).
851
+ All interval containment checks return `false` on invalid input (wrong type, malformed strings, leap seconds, inverted intervals, or an epoch outside the `unix/` grammar: not a safe integer or a digit string).
783
852
 
784
- `intervalsOverlap*` checks whether two intervals share any time. Returns `true` when intervals overlap, `false` when they are disjoint or only adjacent (touching at a single instant with no shared time):
853
+ `intervalsOverlap*` checks whether two intervals share any instant. Returns `false` when they are disjoint. Intervals that touch (one's end equals the other's start) share no instant, so they do **not** overlap, exactly as `intervalsOverlap` in `interval/`:
785
854
 
786
855
  ```typescript
787
856
  import {
@@ -797,23 +866,23 @@ intervalsOverlapDate("2024-01-01", "2024-06-30", "2024-04-01", "2024-12-31");
797
866
  // true
798
867
 
799
868
  intervalsOverlapDate("2024-01-01", "2024-06-30", "2024-06-30", "2024-12-31");
800
- // false (adjacent, no shared time)
869
+ // false (touching — 2024-06-30 is outside the first interval)
801
870
 
802
871
  intervalsOverlapUnix(0, 1700000000, 1000000, 2000000);
803
872
  // true
804
873
 
805
874
  intervalsOverlapUtc(
806
- "2024-01-01T00:00:00Z",
807
- "2024-06-30T23:59:59Z",
808
- "2024-04-01T00:00:00Z",
809
- "2024-12-31T23:59:59Z",
875
+ "2024-01-01T09:00:00Z",
876
+ "2024-01-01T17:00:00Z",
877
+ "2024-01-01T17:00:00Z",
878
+ "2024-01-01T18:00:00Z",
810
879
  );
811
- // true
880
+ // false (touching at 17:00)
812
881
  ```
813
882
 
814
- All overlap checks return `false` on invalid input (wrong type, malformed strings, leap seconds, inverted intervals, non-finite values for Unix).
883
+ All overlap checks return `false` on invalid input (wrong type, malformed strings, leap seconds, inverted intervals, or an epoch outside the `unix/` grammar: not a safe integer or a digit string).
815
884
 
816
- `intervalIntersection*` returns the overlapping span of two intervals, or `null` when they do not overlap. Adjacent intervals (sharing one instant) count as overlapping and return a single-point span:
885
+ `intervalIntersection*` returns the overlapping span of two intervals, or `null` when they do not overlap. Touching intervals share no instant, so their intersection is `null`:
817
886
 
818
887
  ```typescript
819
888
  import {
@@ -827,43 +896,35 @@ import {
827
896
 
828
897
  intervalIntersectionDate(
829
898
  "2024-01-01",
830
- "2024-06-30",
899
+ "2024-07-01",
831
900
  "2024-04-01",
832
- "2024-12-31",
833
- );
834
- // { start: "2024-04-01", end: "2024-06-30" }
835
-
836
- intervalIntersectionDate(
837
- "2024-01-01",
838
- "2024-06-30",
839
- "2024-06-30",
840
- "2024-12-31",
901
+ "2025-01-01",
841
902
  );
842
- // { start: "2024-06-30", end: "2024-06-30" } (adjacent, shares one instant)
903
+ // { start: "2024-04-01", end: "2024-07-01" }
843
904
 
844
905
  intervalIntersectionDate(
845
906
  "2024-01-01",
846
- "2024-06-30",
847
907
  "2024-07-01",
848
- "2024-12-31",
908
+ "2024-07-01",
909
+ "2025-01-01",
849
910
  );
850
- // null (disjoint)
911
+ // null (touching, no shared day)
851
912
 
852
913
  intervalIntersectionUnix(0, 1700000000, 1000000, 2000000);
853
- // { start: 1000000, end: 1700000000 }
914
+ // { start: 1000000, end: 2000000 } (B lies inside A)
854
915
 
855
916
  intervalIntersectionUtc(
856
917
  "2024-01-01T00:00:00Z",
857
- "2024-06-30T23:59:59Z",
918
+ "2024-07-01T00:00:00Z",
858
919
  "2024-04-01T00:00:00Z",
859
- "2024-12-31T23:59:59Z",
920
+ "2025-01-01T00:00:00Z",
860
921
  );
861
- // { start: "2024-04-01T00:00:00Z", end: "2024-06-30T23:59:59Z" }
922
+ // { start: "2024-04-01T00:00:00Z", end: "2024-07-01T00:00:00Z" }
862
923
  ```
863
924
 
864
- All intersection functions return `null` on invalid input (wrong type, malformed strings, leap seconds, inverted intervals, non-finite values for Unix).
925
+ All intersection functions return `null` on invalid input (wrong type, malformed strings, leap seconds, inverted intervals, or an epoch outside the `unix/` grammar: not a safe integer or a digit string).
865
926
 
866
- `intervalOverlappingDays*` returns how many distinct calendar dates two intervals share — the numeric counterpart to `intervalIntersection*`'s span. Counting is inclusive of both endpoints of the closed intersection `[max(aStart, bStart), min(aEnd, bEnd)]`, so `intervalOverlappingDaysDate("2024-01-01", "2024-01-01", "2024-01-01", "2024-01-01")` is `1`, not `0`. There is no `Time` variant — `PlainTime` has no calendar, so a day count is undefined for it:
927
+ `intervalOverlappingDays*` returns how many distinct calendar dates two intervals share — the numeric counterpart to `intervalIntersection*`'s span. It counts the calendar dates that hold at least one instant of the half-open intersection `[max(aStart, bStart), min(aEnd, bEnd))`, so an empty intersection counts `0`: `intervalOverlappingDaysDate("2024-01-01", "2024-01-02", "2024-01-01", "2024-01-02")` is `1`, and touching intervals are `0`. There is no `Time` variant — `PlainTime` has no calendar, so a day count is undefined for it:
867
928
 
868
929
  ```typescript
869
930
  import {
@@ -876,44 +937,42 @@ import {
876
937
 
877
938
  intervalOverlappingDaysDate(
878
939
  "2024-01-01",
879
- "2024-06-30",
940
+ "2024-07-01",
880
941
  "2024-04-01",
881
- "2024-12-31",
942
+ "2025-01-01",
882
943
  );
883
- // 91
944
+ // 91 (2024-04-01 through 2024-06-30)
884
945
 
885
946
  intervalOverlappingDaysDate(
886
947
  "2024-01-01",
887
- "2024-06-30",
888
- "2024-06-30",
889
- "2024-12-31",
948
+ "2024-07-01",
949
+ "2024-07-01",
950
+ "2025-01-01",
890
951
  );
891
- // 1 (adjacent, shares one date)
952
+ // 0 (touching, no shared date)
892
953
 
893
- intervalOverlappingDaysDate(
894
- "2024-01-01",
895
- "2024-06-30",
896
- "2024-07-01",
897
- "2024-12-31",
954
+ intervalOverlappingDaysUtc(
955
+ "2024-01-17T12:00:00Z",
956
+ "2024-01-19T00:00:00Z",
957
+ "2024-01-10T00:00:00Z",
958
+ "2024-01-18T06:00:00Z",
898
959
  );
899
- // 0 (disjoint)
960
+ // 2 (18 hours of overlap touch 17 and 18 January)
900
961
 
901
- intervalOverlappingDaysUnix(0, 172800000, 86400000, 259200000, {
902
- timeZone: "UTC",
903
- });
904
- // 2
962
+ intervalOverlappingDaysUnix(0, 172800000, 86400000, 259200000);
963
+ // 1 (the intersection [86400000, 172800000) is 1970-01-02 in UTC)
905
964
  ```
906
965
 
907
- Returns `0` when the intervals do not overlap (a well-defined answer, not invalid input) and `null` on invalid input, including an inverted interval (`start > end`). `intervalOverlappingDaysZoned` and `intervalOverlappingDaysUnix` count days in `aStart`'s time zone (`intervalOverlappingDaysUnix` defaults to the system time zone, overridable via `{ timeZone }`) — the same rule `intervalCountZoned`/`intervalCountUnix` use — so `intervalOverlappingDaysZoned` is **not commutative** when the two intervals carry different zones: swapping the arguments can change the answer.
966
+ Returns `0` when the intervals do not overlap (a well-defined answer, not invalid input) and `null` on invalid input, including an inverted interval (`start > end`). `intervalOverlappingDaysZoned` and `intervalOverlappingDaysUnix` count days in `aStart`'s time zone (`intervalOverlappingDaysUnix` defaults to UTC; pass `{ timeZone }`, or `"local"` for the system zone) — the same rule `intervalCountZoned`/`intervalCountUnix` use — so `intervalOverlappingDaysZoned` is **not commutative** when the two intervals carry different zones: swapping the arguments can change the answer. Both count the distinct local dates the overlap touches, so a date the zone skipped (`Pacific/Apia`, 2011-12-30) is not counted, and a fall-back that sends the clock back into the previous date counts that date too.
908
967
 
909
- This deliberately diverges from date-fns's `getOverlappingDaysInIntervals`, which rounds up elapsed 24-hour periods instead of counting calendar dates — its own doc example (`Jan 10–20` vs `Jan 17–21`) returns `3` there and `4` here. To reproduce date-fns's number, compose `intervalIntersection*` with `intervalCount*`:
968
+ It counts calendar dates, not elapsed days: the 18-hour overlap above touches two dates. For the elapsed length of the overlap, compose `intervalIntersection*` with `intervalLength*`:
910
969
 
911
970
  ```typescript
912
- const span = intervalIntersectionDate(aStart, aEnd, bStart, bEnd);
913
- span ? intervalCountDate(span.start, span.end, "day") : 0; // date-fns semantics
971
+ const span = intervalIntersectionUtc(aStart, aEnd, bStart, bEnd);
972
+ span ? intervalLengthUtc(span.start, span.end, "day") : 0; // 0.75 for the overlap above
914
973
  ```
915
974
 
916
- `intervalUnion*` returns the combined span of two overlapping or adjacent intervals, or `null` when they are disjoint with a gap. Adjacent intervals (sharing one instant) count as mergeable:
975
+ `intervalUnion*` returns the combined span of two overlapping or touching intervals, or `null` when a gap separates them. Touching intervals (one's end equals the other's start) join:
917
976
 
918
977
  ```typescript
919
978
  import {
@@ -925,28 +984,28 @@ import {
925
984
  intervalUnionZoned,
926
985
  } from "@northguild/gmt";
927
986
 
928
- intervalUnionDate("2024-01-01", "2024-06-30", "2024-04-01", "2024-12-31");
929
- // { start: "2024-01-01", end: "2024-12-31" }
987
+ intervalUnionDate("2024-01-01", "2024-07-01", "2024-04-01", "2025-01-01");
988
+ // { start: "2024-01-01", end: "2025-01-01" }
930
989
 
931
- intervalUnionDate("2024-01-01", "2024-06-30", "2024-06-30", "2024-12-31");
932
- // { start: "2024-01-01", end: "2024-12-31" } (adjacent, merged)
990
+ intervalUnionDate("2024-01-01", "2024-07-01", "2024-07-01", "2025-01-01");
991
+ // { start: "2024-01-01", end: "2025-01-01" } (touching, joined)
933
992
 
934
993
  intervalUnionDate("2024-01-01", "2024-06-30", "2024-07-01", "2024-12-31");
935
- // null (disjoint with a gap)
994
+ // null (2024-06-30 lies in neither interval)
936
995
 
937
996
  intervalUnionUnix(0, 1700000000, 1000000, 2000000);
938
997
  // { start: 0, end: 1700000000 }
939
998
 
940
999
  intervalUnionUtc(
941
1000
  "2024-01-01T00:00:00Z",
942
- "2024-06-30T23:59:59Z",
1001
+ "2024-07-01T00:00:00Z",
943
1002
  "2024-04-01T00:00:00Z",
944
- "2024-12-31T23:59:59Z",
1003
+ "2025-01-01T00:00:00Z",
945
1004
  );
946
- // { start: "2024-01-01T00:00:00Z", end: "2024-12-31T23:59:59Z" }
1005
+ // { start: "2024-01-01T00:00:00Z", end: "2025-01-01T00:00:00Z" }
947
1006
  ```
948
1007
 
949
- All union functions return `null` on invalid input (wrong type, malformed strings, leap seconds, inverted intervals, non-finite values for Unix).
1008
+ All union functions return `null` on invalid input (wrong type, malformed strings, leap seconds, inverted intervals, or an epoch outside the `unix/` grammar: not a safe integer or a digit string).
950
1009
 
951
1010
  `intervalDifference*` returns the portion(s) of interval A not covered by interval B, as an array of `{ start, end }` records:
952
1011
 
@@ -961,24 +1020,26 @@ import {
961
1020
  } from "@northguild/gmt";
962
1021
 
963
1022
  intervalDifferenceDate("2024-01-01", "2024-12-31", "2024-06-01", "2024-07-01");
964
- // [{ start: "2024-01-01", end: "2024-05-31" }, { start: "2024-07-02", end: "2024-12-31" }]
1023
+ // [{ start: "2024-01-01", end: "2024-06-01" }, { start: "2024-07-01", end: "2024-12-31" }]
965
1024
 
966
1025
  intervalDifferenceDate("2024-01-01", "2024-12-31", "2024-01-01", "2024-12-31");
967
1026
  // [] (B fully covers A)
968
1027
 
969
1028
  intervalDifferenceUnix(0, 1700000000, 1000000, 2000000);
970
- // [{ start: 0, end: 999999 }, { start: 2000001, end: 1700000000 }]
1029
+ // [{ start: 0, end: 1000000 }, { start: 2000000, end: 1700000000 }]
971
1030
 
972
1031
  intervalDifferenceUtc(
973
- "2024-01-01T00:00:00Z",
974
- "2024-12-31T23:59:59Z",
975
- "2024-06-01T00:00:00Z",
976
- "2024-07-01T00:00:00Z",
1032
+ "2024-01-01T09:00:00Z",
1033
+ "2024-01-01T17:00:00Z",
1034
+ "2024-01-01T12:00:00Z",
1035
+ "2024-01-01T13:00:00Z",
977
1036
  );
978
- // [{ start: "2024-01-01T00:00:00Z", end: "2024-05-31T23:59:59Z" }, { start: "2024-07-02T00:00:00Z", end: "2024-12-31T23:59:59Z" }]
1037
+ // [{ start: "2024-01-01T09:00:00Z", end: "2024-01-01T12:00:00Z" }, { start: "2024-01-01T13:00:00Z", end: "2024-01-01T17:00:00Z" }]
979
1038
  ```
980
1039
 
981
- All difference functions return `[]` on invalid input (wrong type, malformed strings, leap seconds, inverted intervals, non-finite values for Unix).
1040
+ Each piece ends exactly where B starts and resumes exactly where B ends, with no one-unit step, so the pieces and B together cover A once. `intervalDifferenceUtc` returns the same pieces as `subtractIntervals`.
1041
+
1042
+ All difference functions return `[]` on invalid input (wrong type, malformed strings, leap seconds, inverted intervals, or an epoch outside the `unix/` grammar: not a safe integer or a digit string).
982
1043
 
983
1044
  `intervalXor*` returns the symmetric difference of two intervals — the portions covered by exactly one of them, not both — as an array of `{ start, end }` records:
984
1045
 
@@ -992,27 +1053,27 @@ import {
992
1053
  intervalXorZoned,
993
1054
  } from "@northguild/gmt";
994
1055
 
995
- intervalXorDate("2024-01-01", "2024-06-30", "2024-04-01", "2024-12-31");
996
- // [{ start: "2024-01-01", end: "2024-03-31" }, { start: "2024-07-01", end: "2024-12-31" }]
1056
+ intervalXorDate("2024-01-01", "2024-07-01", "2024-04-01", "2025-01-01");
1057
+ // [{ start: "2024-01-01", end: "2024-04-01" }, { start: "2024-07-01", end: "2025-01-01" }]
997
1058
 
998
- intervalXorDate("2024-01-01", "2024-06-30", "2024-06-30", "2024-12-31");
999
- // [{ start: "2024-01-01", end: "2024-06-29" }, { start: "2024-07-01", end: "2024-12-31" }] (adjacent)
1059
+ intervalXorDate("2024-01-01", "2024-07-01", "2024-07-01", "2025-01-01");
1060
+ // [{ start: "2024-01-01", end: "2025-01-01" }] (touching intervals share no date, so the runs join)
1000
1061
 
1001
1062
  intervalXorUnix(0, 1700000000, 1000000, 2000000);
1002
- // [{ start: 0, end: 999999 }, { start: 2000001, end: 1700000000 }]
1063
+ // [{ start: 0, end: 1000000 }, { start: 2000000, end: 1700000000 }]
1003
1064
 
1004
1065
  intervalXorUtc(
1005
- "2024-01-01T00:00:00Z",
1006
- "2024-06-30T23:59:59Z",
1007
- "2024-04-01T00:00:00Z",
1008
- "2024-12-31T23:59:59Z",
1066
+ "2024-01-01T09:00:00Z",
1067
+ "2024-01-01T13:00:00Z",
1068
+ "2024-01-01T12:00:00Z",
1069
+ "2024-01-01T17:00:00Z",
1009
1070
  );
1010
- // [{ start: "2024-01-01T00:00:00Z", end: "2024-03-31T23:59:59Z" }, { start: "2024-07-01T00:00:00Z", end: "2024-12-31T23:59:59Z" }]
1071
+ // [{ start: "2024-01-01T09:00:00Z", end: "2024-01-01T12:00:00Z" }, { start: "2024-01-01T13:00:00Z", end: "2024-01-01T17:00:00Z" }]
1011
1072
  ```
1012
1073
 
1013
- All xor functions return `[]` on invalid input (wrong type, malformed strings, leap seconds, inverted intervals, non-finite values for Unix).
1074
+ All xor functions return `[]` on invalid input (wrong type, malformed strings, leap seconds, inverted intervals, or an epoch outside the `unix/` grammar: not a safe integer or a digit string).
1014
1075
 
1015
- `intervalAbuts*` checks whether two intervals are exactly adjacent — one's end equals the other's start with zero gap and zero overlap:
1076
+ `intervalAbuts*` checks whether two intervals are exactly adjacent, in either order: one interval's `end` equals the other's `start` (Allen's "meets"). The two then share no instant and leave no gap. Intervals separated by any gap, even one nanosecond or one epoch unit, do not abut, and an empty interval abuts nothing:
1016
1077
 
1017
1078
  ```typescript
1018
1079
  import {
@@ -1024,30 +1085,30 @@ import {
1024
1085
  intervalAbutsZoned,
1025
1086
  } from "@northguild/gmt";
1026
1087
 
1027
- intervalAbutsDate("2024-01-01", "2024-06-30", "2024-06-30", "2024-12-31");
1028
- // true
1088
+ intervalAbutsDate("2024-01-01", "2024-07-01", "2024-07-01", "2025-01-01");
1089
+ // true (the first interval ends where the second starts)
1029
1090
 
1030
- intervalAbutsDate("2024-01-01", "2024-06-29", "2024-06-30", "2024-12-31");
1031
- // false (one-day gap)
1091
+ intervalAbutsDate("2024-01-01", "2024-06-30", "2024-07-01", "2024-12-31");
1092
+ // false (2024-06-30 lies in neither interval)
1032
1093
 
1033
- intervalAbutsDate("2024-01-01", "2024-06-30", "2024-04-01", "2024-12-31");
1094
+ intervalAbutsDate("2024-01-01", "2024-07-01", "2024-04-01", "2025-01-01");
1034
1095
  // false (overlap)
1035
1096
 
1036
1097
  intervalAbutsUnix(0, 1000000, 1000000, 2000000);
1037
1098
  // true
1038
1099
 
1039
1100
  intervalAbutsUtc(
1040
- "2024-01-01T00:00:00Z",
1041
- "2024-06-30T23:59:59Z",
1042
- "2024-06-30T23:59:59Z",
1043
- "2024-12-31T23:59:59Z",
1101
+ "2024-01-01T09:00:00Z",
1102
+ "2024-01-01T12:00:00Z",
1103
+ "2024-01-01T12:00:00.000000001Z",
1104
+ "2024-01-01T17:00:00Z",
1044
1105
  );
1045
- // true
1106
+ // false (1 ns apart)
1046
1107
  ```
1047
1108
 
1048
- All abuts checks return `false` on invalid input (wrong type, malformed strings, leap seconds, inverted intervals, non-finite values for Unix).
1109
+ All abuts checks return `false` on invalid input (wrong type, malformed strings, leap seconds, inverted intervals, or an epoch outside the `unix/` grammar: not a safe integer or a digit string).
1049
1110
 
1050
- `intervalEngulfs*` checks whether interval B is fully contained within interval A — every instant of B falls within A. Equivalent to the 4-argument `intervalContains*` mode:
1111
+ `intervalEngulfs*` checks whether interval B lies within interval A and overlaps it — B may share A's `start` or `end`, but an empty B at A's `end` is not engulfed. Equivalent to the 4-argument `intervalContains*` mode:
1051
1112
 
1052
1113
  ```typescript
1053
1114
  import {
@@ -1080,7 +1141,7 @@ intervalEngulfsUtc(
1080
1141
  // true
1081
1142
  ```
1082
1143
 
1083
- All engulfs checks return `false` on invalid input (wrong type, malformed strings, leap seconds, inverted intervals, non-finite values for Unix).
1144
+ All engulfs checks return `false` on invalid input (wrong type, malformed strings, leap seconds, inverted intervals, or an epoch outside the `unix/` grammar: not a safe integer or a digit string).
1084
1145
 
1085
1146
  `splitIntervalByUnit*` splits an interval into sub-intervals of `amount × unit`, returning an array of `{ start, end }` records. The final sub-interval is trimmed so its `end` never exceeds the original `end`:
1086
1147
 
@@ -1109,7 +1170,26 @@ splitIntervalByUnitUnix(0, 86400000, "hour", 6);
1109
1170
  // [{ start: 0, end: 21600000 }, { start: 21600000, end: 43200000 }, { start: 43200000, end: 64800000 }, { start: 64800000, end: 86400000 }]
1110
1171
  ```
1111
1172
 
1112
- All split functions return `[]` on invalid input (wrong type, malformed strings, leap seconds, inverted intervals, non-positive amount, unsupported unit, or a unit that has no effect on the target type).
1173
+ All split functions return `[]` on invalid input (wrong type, malformed strings, leap seconds, inverted intervals, non-positive amount, unsupported unit, or a unit that has no effect on the target type). A zero-length interval returns itself as the one piece (`[{ start, end }]`) for a supported unit, and `[]` for an unsupported one: `splitIntervalByUnitDate("2024-01-01", "2024-01-01", "hour", 1)` is `[]`.
1174
+
1175
+ `splitIntervalByUnit*`, `intervalDivideEqually*`, `mapDatesInRange` and `mapZonedDatesInRange` build one array element per piece, so each takes an optional `{ maxPieces }` (a positive safe integer, default `1_000_000`) and returns `[]` when the result would be longer. A split stops as soon as the piece past the limit is due, so a huge range answers in bounded time instead of exhausting the heap. Pass a larger `maxPieces` when a long range legitimately needs it:
1176
+
1177
+ ```typescript
1178
+ import { mapDatesInRange, splitIntervalByUnitDate } from "@northguild/gmt";
1179
+
1180
+ splitIntervalByUnitDate("2024-01-01", "2024-01-10", "day", 2, { maxPieces: 4 });
1181
+ // [] — 5 slices exceed the limit
1182
+
1183
+ mapDatesInRange("0001-01-01", "9999-12-31", 1);
1184
+ // [] — 3,652,059 dates exceed the default
1185
+ ```
1186
+
1187
+ Each boundary is computed from `start` (`start + k × amount`, as Temporal and Luxon's `Interval.splitBy` do), never by stepping from the previous boundary, so month-end starts don't drift. A yearly split from February 29 likewise returns to February 29 in leap years:
1188
+
1189
+ ```typescript
1190
+ splitIntervalByUnitDate("2024-01-31", "2024-05-01", "month", 1);
1191
+ // [{ start: "2024-01-31", end: "2024-02-29" }, { start: "2024-02-29", end: "2024-03-31" }, { start: "2024-03-31", end: "2024-04-30" }, { start: "2024-04-30", end: "2024-05-01" }]
1192
+ ```
1113
1193
 
1114
1194
  `intervalCount*` returns how many calendar-unit boundaries an interval crosses — the number of units the half-open interval `[start, end)` touches. This is distinct from `diff*`, which measures exact elapsed duration: an interval from 23:59 to 00:01 is two minutes long but touches two days:
1115
1195
 
@@ -1146,7 +1226,9 @@ intervalCountUnix(0, 86400000, "hour");
1146
1226
  // 24
1147
1227
  ```
1148
1228
 
1149
- Zero-length intervals count `1` when they sit mid-unit and `0` when they sit exactly on a unit boundary — `intervalCountDate("2024-01-15", "2024-01-15", "month")` is `1`, while `intervalCountDate("2024-01-01", "2024-01-01", "month")` is `0`. Weeks start on Monday (ISO 8601), singular and plural units are interchangeable (`"day"` and `"days"`), and `intervalCountUnix` uses the system timeZone for calendar boundaries (consistent with `addUnix`). All count functions return `null` on invalid input (wrong type, malformed strings, leap seconds, inverted intervals, unsupported unit, or a unit that has no effect on the target type).
1229
+ A zero-length interval counts `0` in every unit — the empty `[start, start)` holds no instant, so `intervalCountDate("2024-01-15", "2024-01-15", "month")` is `0`. Weeks start on Monday (ISO 8601), singular and plural units are interchangeable (`"day"` and `"days"`), and `intervalCountUnix` counts calendar boundaries in `options.timeZone`, UTC by default (`"local"` for the system zone), like `addUnix`. All count functions return `null` on invalid input (wrong type, malformed strings, leap seconds, inverted intervals, unsupported unit, or a unit that has no effect on the target type).
1230
+
1231
+ `intervalCountZoned`, `intervalCountUnix` and `intervalCountUtc` count the same local buckets `bucketRange` returns. A bucket shorter than its unit still counts once — a 20-minute range straddling 04:00 on `Pacific/Chatham`'s spring-forward day counts 2 hours, because its 03:00 hour lasts only 15 minutes — and a day the zone deleted counts not at all (`Pacific/Apia`'s 30 December 2011).
1150
1232
 
1151
1233
  `intervalLength*` is `intervalCount*`'s exact-duration counterpart — it answers "how long is this interval" as a real, possibly fractional number, rather than "how many boundaries does it touch":
1152
1234
 
@@ -1174,7 +1256,7 @@ intervalLengthZoned(
1174
1256
  // 23 (spring-forward local day is 23 real hours)
1175
1257
  ```
1176
1258
 
1177
- `intervalLength*` uses `Temporal.Duration.prototype.total`, so calendar units (month, year) resolve against the interval's own `start` rather than truncating, and zoned/unix/utc variants are DST-aware the same way `intervalCount*` is. Returns `0` for a zero-length interval, and `null` on invalid input (wrong type, malformed strings, leap seconds, inverted intervals, unsupported unit).
1259
+ `intervalLength*` uses `Temporal.Duration.prototype.total`, so calendar units (month, year) resolve against the interval's own `start` rather than truncating, and zoned/unix/utc variants are DST-aware the same way `intervalCount*` is. Returns `0` for a zero-length interval, and `null` on invalid input (wrong type, malformed strings, leap seconds, inverted intervals, unsupported unit). `intervalLengthUnix` and `splitIntervalByUnitUnix` take `{ epochUnit, timeZone }` like `intervalCountUnix` (milliseconds and UTC by default): `intervalLengthUnix(0, 86400, "day", { epochUnit: "seconds" })` is `1`.
1178
1260
 
1179
1261
  `intervalDivideEqually*` splits an interval into `n` equal-length sub-intervals, and `intervalSplitAt*` splits an interval at arbitrary points instead of by count:
1180
1262
 
@@ -1191,7 +1273,7 @@ intervalSplitAtDate("2024-01-01", "2024-01-10", ["2024-01-07", "2024-01-03"]);
1191
1273
  // [{ start: "2024-01-01", end: "2024-01-03" }, { start: "2024-01-03", end: "2024-01-07" }, { start: "2024-01-07", end: "2024-01-10" }]
1192
1274
  ```
1193
1275
 
1194
- `n` must be a positive integer (`[]` otherwise); `n === 1` returns the original interval unchanged, and a zero-length interval returns `n` identical zero-length sub-intervals. Non-fractional types (`PlainDate`) round internal boundaries to the nearest whole unit; every other variant is exact, computed from total elapsed nanoseconds (`intervalDivideEquallyZoned` splits DST-crossing intervals by real elapsed time, not local clock time). `intervalSplitAt*` sorts its `points` internally — they need not be pre-sorted — and drops points outside `[start, end]` or exactly on a boundary, since those cannot introduce a new sub-interval; an empty or all-dropped `points` array returns `[{ start, end }]` unsplit.
1276
+ `n` must be a positive integer (`[]` otherwise), and `n` above `maxPieces` also returns `[]`; `n === 1` returns the original interval unchanged, and a zero-length interval returns `n` identical zero-length sub-intervals. Each internal boundary is `start + round((end − start) · i / n)`, an exact half rounding up — in whole days for `PlainDate`, nanoseconds for the other string variants and the arguments' own epoch unit for `intervalDivideEquallyUnix` — so the split is exact when the span divides evenly by `n`, within half a unit otherwise, and the pieces tile the range with no gap or overshoot (`intervalDivideEquallyZoned` splits DST-crossing intervals by real elapsed time, not local clock time). `intervalSplitAt*` sorts its `points` internally — they need not be pre-sorted — and drops points outside the interval or exactly on `start` or `end`, since those cannot introduce a new sub-interval. Each piece's `end` is the next piece's `start`, so under `[start, end)` the pieces partition the interval; an empty or all-dropped `points` array returns `[{ start, end }]` unsplit.
1195
1277
 
1196
1278
  `mergeIntervals*` and `intervalXorAll*` are the list-form generalizations of `intervalUnion*` and `intervalXor*`, which are pairwise only — each takes a single array of `{ start, end }` records instead of two flat intervals:
1197
1279
 
@@ -1209,10 +1291,10 @@ intervalXorAllDate([
1209
1291
  { start: "2024-01-05", end: "2024-01-15" },
1210
1292
  { start: "2024-01-08", end: "2024-01-20" },
1211
1293
  ]);
1212
- // [{ start: "2024-01-01", end: "2024-01-04" }, { start: "2024-01-08", end: "2024-01-10" }, { start: "2024-01-16", end: "2024-01-20" }]
1294
+ // [{ start: "2024-01-01", end: "2024-01-05" }, { start: "2024-01-08", end: "2024-01-10" }, { start: "2024-01-15", end: "2024-01-20" }]
1213
1295
  ```
1214
1296
 
1215
- `mergeIntervals*` collapses overlapping or adjacent intervals (shared endpoint) into the minimum non-overlapping set. `intervalXorAll*` returns the set covered by an odd number of the input intervals — for exactly two intervals the result is identical to the pairwise `intervalXor*`, and two identical intervals cancel out to `[]`. All four return `[]` for an empty list or on invalid input.
1297
+ `mergeIntervals*` collapses overlapping or touching intervals (one's end equals the next one's start) into the minimum sorted set that does not overlap. `intervalXorAll*` returns the maximal runs covered by an odd number of the input intervals, sorted by start — for exactly two intervals the result is identical to the pairwise `intervalXor*`, and two identical intervals cancel out to `[]`. All four return `[]` for an empty list or on invalid input.
1216
1298
 
1217
1299
  `intervalFromDuration*` constructs an interval from a single point plus an ISO 8601 duration, anchored at either end — Luxon's `Interval.after`/`Interval.before` as one function with an `anchor` param instead of two:
1218
1300
 
@@ -1243,16 +1325,16 @@ intervalFromDurationTime("12:00:00", "P1D", "start");
1243
1325
  // null (PlainTime has no calendar — a date-unit duration needs a relativeTo it can't supply)
1244
1326
  ```
1245
1327
 
1246
- Calendar units (years/months/weeks) resolve against `value` itself, so no separate `relativeTo` is needed — except for `intervalFromDurationTime`, which returns `null` for a `duration` with a nonzero years/months/weeks/days component, since `PlainTime` has no calendar to resolve it against. `intervalFromDurationZoned` accepts the same `disambiguation`/`offset`/`overflow` options as `addZoned`; `intervalFromDurationUnix` accepts `addUnix`'s `epochUnit`/`timeZone`/`overflow` options. A negative `duration` that inverts the computed span, or an `overflow: "reject"` result, returns `null` — same sentinel as any other invalid input.
1328
+ Calendar units (years/months/weeks) resolve against `value` itself, so no separate `relativeTo` is needed — except for `intervalFromDurationTime`, which returns `null` for a `duration` with a nonzero years/months/weeks/days component, since `PlainTime` has no calendar to resolve it against. `intervalFromDurationZoned` accepts the same `disambiguation`/`overflow` options as `addZoned`; `intervalFromDurationUnix` accepts `addUnix`'s `epochUnit`/`timeZone`/`overflow` options; `intervalFromDurationTime` takes no options argument, like `addTime`. A negative `duration` that inverts the computed span, or an `overflow: "reject"` result, returns `null` — same sentinel as any other invalid input.
1247
1329
 
1248
- All validators return `false` on invalid input (wrong type, malformed strings, leap seconds, mixed kinds for plain interval validators, non-finite values for Unix).
1330
+ All validators return `false` on invalid input (wrong type, malformed strings, leap seconds, mixed kinds for plain interval validators, or an epoch outside the `unix/` grammar: not a safe integer or a digit string).
1249
1331
 
1250
1332
  ### Zoned operations
1251
1333
 
1252
1334
  ```typescript
1253
1335
  import { addZoned, formatZonedDateTime } from "@northguild/gmt";
1254
1336
 
1255
- addZoned("2026-03-07T23:00:00-05:00[America/New_York]", 2, "hour");
1337
+ addZoned("2026-03-07T23:00:00-05:00[America/New_York]", { hours: 2 });
1256
1338
  // "2026-03-08T01:00:00-05:00[America/New_York]"
1257
1339
 
1258
1340
  formatZonedDateTime("2024-03-17T14:30:45+00:00[UTC]", "en-US", {
@@ -1274,23 +1356,31 @@ convertPlainDateTimeToZoned("2024-03-10T02:30:00", "America/New_York", {
1274
1356
  // "" — no such local time exists
1275
1357
  ```
1276
1358
 
1277
- The `startOfZoned`/`endOfZoned`/`startOfQuarterForZoned`/`endOfQuarterForZoned`/`mapZonedHoursInDay` family (and their `unix/` counterparts) also accept `disambiguation`, plus an `offset` option (`"prefer"` | `"use"` | `"ignore"` (default) | `"reject"`) that controls whether the source's existing UTC offset is kept when computing the new boundary. **`offset` must stay at its default (`"ignore"`) for `disambiguation` to take effect** — Temporal's own default (`"prefer"`) keeps the source offset whenever still valid, which silently makes `disambiguation` a no-op:
1359
+ The `startOfZoned`/`endOfZoned`/`startOfQuarterForZoned`/`endOfQuarterForZoned`/`getLocaleZonedStartOfWeek`/`getLocaleZonedEndOfWeek` family (and their `unix/` counterparts) always return the real boundary of the unit that contains the input, in its zone: a start is never after the input and an end never before it, even when the wall-clock boundary was skipped or repeated. `Pacific/Chatham`'s 03:00 hour on its spring-forward starts at 03:45, New York's repeated 1 a.m. is its own hour, and a midnight repeated on the same date (America/Havana, 2024-11-03) stays one 25-hour day:
1278
1360
 
1279
1361
  ```typescript
1280
1362
  import { startOfZoned } from "@northguild/gmt";
1281
1363
 
1282
1364
  // 2024-11-03T01:45:00-05:00 is the SECOND, repeated 1am of the fall-back overlap in America/New_York.
1283
- const source = "2024-11-03T01:45:00-05:00[America/New_York]";
1365
+ startOfZoned("2024-11-03T01:45:00-05:00[America/New_York]", "hour");
1366
+ // "2024-11-03T01:00:00-05:00[America/New_York]" — the real start of the repeated hour
1367
+ ```
1284
1368
 
1285
- startOfZoned(source, "hour", { disambiguation: "reject" });
1286
- // "" — offset defaults to "ignore", so disambiguation actually fires and "reject" throws
1369
+ These boundary functions follow TC39's `startOfDay()`, which takes no resolution options: they take no `disambiguation` or `offset` options, and neither does `mapZonedHoursInDay`. Resolution options belong on functions that set wall-clock fields. `getHoursInZonedDay` and `mapZonedHoursInDay` measure the input's calendar date exactly as TC39's `hoursInDay` does, which differs from `startOfZoned(…, "day")` only where a fall-back re-enters the previous date (America/Goose_Bay, 2010-11-07).
1287
1370
 
1288
- startOfZoned(source, "hour", { disambiguation: "reject", offset: "prefer" });
1289
- // "2024-11-03T01:00:00-05:00[America/New_York]" — offset:"prefer" keeps the source's
1290
- // still-valid -05:00 offset, so disambiguation is never consulted and "reject" never fires
1291
- ```
1371
+ `convertPlainDateTimeToZoned`, `addZoned`, `subtractZoned` and `intervalFromDurationZoned` take no `offset` option: they resolve a plain date-time that has no UTC offset for it to act on.
1372
+
1373
+ `addZoned`, `subtractZoned` and `intervalFromDurationZoned` follow TC39's AddZonedDateTime: the date part of the duration (years to days) moves the wall clock, and the time part (hours and smaller) is added in exact time. `disambiguation` resolves the wall clock the date part lands on — in a spring-forward gap `"compatible"` and `"later"` move it forward, `"earlier"` back, and `"reject"` returns the sentinel; in a fall-back overlap it picks the occurrence — and never re-resolves the time part, so adding 10 minutes is always 10 real minutes. Before 1.16.0 a gap landing always moved forward. `diffZoned`, `diffZonedAsDuration` and `intervalLengthZoned` follow DifferenceZonedDateTime: days, weeks, months and years are counted on the zone's wall clock, and hours and smaller in exact time. Two values in different zones share no wall clock, so a calendar unit returns the sentinel; convert one end with `convertZonedToZoned` first:
1374
+
1375
+ ```typescript
1376
+ import { diffZoned } from "@northguild/gmt";
1377
+
1378
+ diffZoned("2024-03-09T12:00:00-05:00[America/New_York]", "2024-03-10T12:00:00-04:00[America/New_York]", "days");
1379
+ // 1 — noon to noon across a 23-hour day
1292
1380
 
1293
- `convertPlainDateTimeToZoned` and `addZoned`/`subtractZoned` also accept `offset` for API consistency, but it's permanently inert on both — their construction path never has a stored offset for it to act on.
1381
+ diffZoned("2024-01-01T00:00:00-05:00[America/New_York]", "2024-01-03T00:00:00+01:00[Europe/Paris]", "days");
1382
+ // null — calendar unit across two time zones
1383
+ ```
1294
1384
 
1295
1385
  `hasDaylightSaving` reports whether an IANA timezone observes daylight saving time at all:
1296
1386
 
@@ -1431,7 +1521,7 @@ closestZonedTo("2024-03-15T12:00:00[America/New_York]", [
1431
1521
  // "2024-03-18T00:00:00-04:00[America/New_York]"
1432
1522
  ```
1433
1523
 
1434
- See [`docs/dst-disambiguation.md`](../../docs/dst-disambiguation.md) for the full explanation, including why `overflow` was deliberately left off the public API.
1524
+ See [`docs/dst-disambiguation.md`](../../docs/dst-disambiguation.md) for the full explanation, including where `overflow` is and is not exposed.
1435
1525
 
1436
1526
  ### Formatting
1437
1527
 
@@ -1466,24 +1556,36 @@ formatRelativeDate("2026-01-15");
1466
1556
  // e.g. "3 months ago"
1467
1557
 
1468
1558
  formatRelativeTime("14:30:00", "en-US", { style: "short" });
1469
- // e.g. "2 hours ago"
1559
+ // e.g. "2 hr. ago"
1470
1560
 
1471
1561
  formatRelativeDateTime("2026-03-17T09:00:00", "en-GB", {
1472
1562
  style: "long",
1473
1563
  numeric: "always",
1474
1564
  });
1475
- // e.g. "17 March, 2026 at 09:00"
1565
+ // e.g. "in 3 hours"
1476
1566
 
1477
1567
  // Zoned relative formatting — reference can be a ZonedDateTime, UTC string, or unix epoch.
1478
1568
  formatRelativeZoned("2026-03-08T01:00:00-05:00[America/New_York]", "en-US");
1479
1569
  // e.g. "tomorrow"
1480
1570
 
1481
- formatRelativeUtc("2024-03-17T14:30:45+00:00[UTC]", "en-US");
1482
- // e.g. "2 years ago"
1571
+ // Auto-picked units run from second through year, with formatRelativeDate's thresholds;
1572
+ // pass largestUnit to cap them.
1573
+ formatRelativeUtc("2024-03-17T14:30:45Z", "en-US", {
1574
+ reference: "2026-03-17T14:30:45Z",
1575
+ });
1576
+ // "2 years ago"
1577
+ formatRelativeUtc("2024-03-17T14:30:45Z", "en-US", {
1578
+ reference: "2026-03-17T14:30:45Z",
1579
+ largestUnit: "day",
1580
+ });
1581
+ // "730 days ago"
1483
1582
 
1484
1583
  // Unix epoch relative formatting.
1485
- formatRelativeUnix(1710685845000, "en-US", { epochUnit: "milliseconds" });
1486
- // e.g. "3 years ago"
1584
+ formatRelativeUnix(1710685845000, "en-US", {
1585
+ epochUnit: "milliseconds",
1586
+ reference: 1805358645000,
1587
+ });
1588
+ // "3 years ago"
1487
1589
 
1488
1590
  // roundingMethod ("floor" | "ceil" | "round", default "round") controls how the
1489
1591
  // computed distance rounds to the display unit — every formatRelative* function accepts it.
@@ -1514,13 +1616,13 @@ formatCalendarZoned("2026-03-16T14:30:00-04:00[America/New_York]", "de-DE", {
1514
1616
  // formatZonedRange (same parameter order and option shape), for a
1515
1617
  // locale-elided range between two timezone-free values.
1516
1618
  formatDateRange("2024-02-03", "2024-02-05", "en-US", { dateStyle: "long" });
1517
- // "February 3 – 5, 2024"
1619
+ // "February 3 - 5, 2024"
1518
1620
 
1519
1621
  formatDateTimeRange("2024-02-03T09:00:00", "2024-02-03T17:00:00", "en-US", {
1520
1622
  dateStyle: "long",
1521
1623
  timeStyle: "short",
1522
1624
  });
1523
- // "February 3, 2024, 9:00 AM – 5:00 PM"
1625
+ // "February 3, 2024, 9:00 AM - 5:00 PM"
1524
1626
 
1525
1627
  // formatDateToParts / formatDateTimeToParts / formatZonedToParts return the
1526
1628
  // locale-ordered Array<{ type, value }> parts behind the strings above,
@@ -1541,7 +1643,7 @@ formatDateToParts("2024-03-15", "fr-FR");
1541
1643
  formatZonedToParts("2024-03-15T14:30:00-04:00[America/New_York]", "en-US", {
1542
1644
  timeZoneName: "longOffset",
1543
1645
  });
1544
- // includes { type: "timeZoneName", value: "GMT-4" }
1646
+ // includes { type: "timeZoneName", value: "GMT-04:00" }
1545
1647
  ```
1546
1648
 
1547
1649
  ### Named machine formats
@@ -1569,17 +1671,29 @@ formatRfc2822("2024-03-15T14:30:00-04:00[America/New_York]");
1569
1671
  parseRfc2822("Fri, 15 Mar 2024 14:30:00 -0400");
1570
1672
  // "2024-03-15T14:30:00-04:00[-04:00]"
1571
1673
 
1572
- // HTTP headers (RFC 7231 IMF-fixdate) — Last-Modified, Date, Expires.
1674
+ // A receiver reads RFC 5322's full and obsolete syntax: comments, any case,
1675
+ // two-digit years and zone names. A day name that contradicts the date is "".
1676
+ parseRfc2822("fri,15 Mar 24 14:30 -0400 (EDT)");
1677
+ // "2024-03-15T14:30:00-04:00[-04:00]"
1678
+ parseRfc2822("Sat, 15 Mar 2024 14:30:00 -0400");
1679
+ // "" — 15 March 2024 was a Friday
1680
+
1681
+ // HTTP headers (RFC 9110 IMF-fixdate) — Last-Modified, Date, Expires.
1573
1682
  formatHttp("2024-03-15T14:30:00Z");
1574
1683
  // "Fri, 15 Mar 2024 14:30:00 GMT"
1575
1684
  parseHttp("Fri, 15 Mar 2024 14:30:00 GMT");
1576
1685
  // "2024-03-15T14:30:00Z"
1686
+ // parseHttp also reads the obsolete rfc850-date and asctime-date forms.
1687
+ parseHttp("Sun Nov 6 08:49:37 1994");
1688
+ // "1994-11-06T08:49:37Z"
1577
1689
 
1578
1690
  // ANSI SQL / ODBC datetime literals (DATETIME/TIMESTAMP columns, no tz).
1579
1691
  formatSql("2024-03-15T14:30:00");
1580
1692
  // "2024-03-15 14:30:00"
1581
1693
  parseSql("2024-03-15 14:30:00");
1582
1694
  // "2024-03-15T14:30:00"
1695
+ parseSql("2024-03-15 14:30");
1696
+ // "" — the SQL literal grammar requires seconds, and a year of 0001–9999
1583
1697
 
1584
1698
  // Strict RFC 3339 — strips the bracketed IANA zone GMT's own zoned strings
1585
1699
  // carry, which RFC 3339 does not permit.
@@ -1589,21 +1703,482 @@ parseRfc3339("2024-03-15T14:30:00-04:00");
1589
1703
  // "2024-03-15T14:30:00-04:00[-04:00]"
1590
1704
  ```
1591
1705
 
1706
+ The formatters return `""` for a value their grammar cannot express, such as a year outside `0000`–`9999` for RFC 3339 and HTTP-date or outside `0001`–`9999` for SQL, rather than writing a string no conforming parser accepts. Use Temporal's own `toString()` when you need any year.
1707
+
1592
1708
  ### Unix and UTC helpers
1593
1709
 
1594
1710
  ```typescript
1595
1711
  import { getUnixNow, getUtcNow, convertUnixToPlainDate } from "@northguild/gmt";
1596
1712
 
1597
- getUnixNow("milliseconds");
1598
- // 1710685845000
1713
+ getUnixNow();
1714
+ // 1710685845000 (milliseconds; getUnixNow({ epochUnit: "seconds" }) is 1710685845)
1599
1715
 
1600
1716
  getUtcNow();
1601
1717
  // "2026-03-18T11:42:33.123Z"
1602
1718
 
1603
- convertUnixToPlainDate(1710685845);
1719
+ convertUnixToPlainDate(1710685845000, { timeZone: "UTC" });
1604
1720
  // "2024-03-17"
1605
1721
  ```
1606
1722
 
1723
+ ### Nanosecond precision
1724
+
1725
+ `convertZonedToUnix` and friends return `number` milliseconds. Systems that record
1726
+ telemetry, trades or sensor readings need nanoseconds, and a `number` cannot hold them:
1727
+ integers are exact only to `2^53 − 1` ≈ 9.0 × 10^15, and nanoseconds since the epoch
1728
+ passed that in April 1970. (`Date.now() * 1e6` is not a nanosecond timestamp — it is a
1729
+ millisecond timestamp with three zeroes appended.) The `precision/` namespace works in
1730
+ `bigint`:
1731
+
1732
+ ```typescript
1733
+ import {
1734
+ toNanoseconds,
1735
+ fromNanoseconds,
1736
+ formatNanoseconds,
1737
+ parseNanoseconds,
1738
+ truncateNanoseconds,
1739
+ } from "@northguild/gmt";
1740
+
1741
+ toNanoseconds("2024-03-10T12:00:00.123456789Z");
1742
+ // 1710072000123456789n
1743
+
1744
+ fromNanoseconds(1710072000123456789n);
1745
+ // "2024-03-10T12:00:00.123456789Z"
1746
+
1747
+ fromNanoseconds(1710072000123456789n, "America/New_York");
1748
+ // "2024-03-10T08:00:00.123456789-04:00[America/New_York]"
1749
+ ```
1750
+
1751
+ `JSON.stringify` throws a `TypeError` on a `bigint`, so the value crosses a wire as a
1752
+ canonical decimal string:
1753
+
1754
+ ```typescript
1755
+ JSON.stringify({ observedAt: formatNanoseconds(1710072000123456789n) });
1756
+ // '{"observedAt":"1710072000123456789"}'
1757
+
1758
+ parseNanoseconds("1710072000123456789");
1759
+ // 1710072000123456789n
1760
+ ```
1761
+
1762
+ Most storage engines cannot hold nanoseconds — PostgreSQL `timestamptz` and MySQL
1763
+ `DATETIME(6)` hold microseconds — so a naive write-then-read loses the last digits
1764
+ silently. Truncate to the target precision first, and the round-trip is exact:
1765
+
1766
+ ```typescript
1767
+ truncateNanoseconds(1710072000123456789n, "us");
1768
+ // 1710072000123456000n — safe to write to a microsecond column
1769
+
1770
+ truncateNanoseconds(1710072000123456789n, "ms");
1771
+ // 1710072000123000000n
1772
+ ```
1773
+
1774
+ Truncation floors toward negative infinity, so pre-1970 values truncate the same way
1775
+ post-1970 ones do — `truncateNanoseconds(-1500n, "us")` is `-2000n`, not `-1000n`.
1776
+ Rounding toward zero would make the result jump direction either side of the epoch.
1777
+
1778
+ `0n` is both the epoch and the invalid-input sentinel, so `precision/validate` exists to
1779
+ tell them apart. Each predicate accepts exactly what its partner parses:
1780
+
1781
+ ```typescript
1782
+ import {
1783
+ isValidInstant,
1784
+ isValidNanoseconds,
1785
+ isValidNanoPattern,
1786
+ } from "@northguild/gmt";
1787
+
1788
+ isValidInstant("1970-01-01T00:00:00Z"); // true — toNanoseconds returns 0n, the epoch
1789
+ isValidInstant("garbage"); // false — toNanoseconds returns 0n, the sentinel
1790
+
1791
+ isValidNanoPattern("0"); // true — parseNanoseconds returns 0n, the epoch
1792
+ isValidNanoPattern("1e18"); // false
1793
+
1794
+ isValidNanoseconds(0n); // true — in range for truncateNanoseconds / fromNanoseconds
1795
+ isValidNanoseconds(0); // false — a number cannot carry a nanosecond timestamp
1796
+ ```
1797
+
1798
+ Reach for `isValidInstant` rather than `isValidUtc`: the latter gates on GMT's stricter
1799
+ `<date>T<time>Z` shape and rejects the offsets and bracketed zones `toNanoseconds`
1800
+ accepts, so validating with it discards valid input.
1801
+
1802
+ Every `precision/` function returns a sentinel (`""` for strings, `0n` for bigints) on
1803
+ invalid input, and accepts only values inside the range `Temporal.Instant` can represent
1804
+ (±8_640_000_000_000_000_000_000n). `0n` is also the epoch itself, so validate the input
1805
+ first when the two must be told apart. Leap-second-aware time scales (TAI, GPS) are not
1806
+ part of this namespace — these are plain instant conversions.
1807
+
1808
+ ### Foreign epoch bridges
1809
+
1810
+ Other systems do not count from 1970. NTP counts from 1900 and rolls over in 2036, Windows
1811
+ `FILETIME` counts 100-nanosecond intervals from 1601, .NET ticks count the same interval
1812
+ from year 1, Excel uses a day serial with a deliberate 1900 leap-year bug, and PostgreSQL
1813
+ stores microseconds from 2000-01-01. Every integration re-derives these constants, usually
1814
+ wrongly:
1815
+
1816
+ ```typescript
1817
+ import {
1818
+ toNtpTimestamp,
1819
+ fromNtpTimestamp,
1820
+ toFileTime,
1821
+ fromFileTime,
1822
+ toDotNetTicks,
1823
+ fromDotNetTicks,
1824
+ toExcelSerial,
1825
+ fromExcelSerial,
1826
+ toPgMicroseconds,
1827
+ fromPgMicroseconds,
1828
+ } from "@northguild/gmt";
1829
+
1830
+ toFileTime("1970-01-01T00:00:00Z");
1831
+ // 116444736000000000n — 100 ns intervals since 1601-01-01
1832
+
1833
+ toDotNetTicks("1970-01-01T00:00:00Z");
1834
+ // 621355968000000000n — same unit, counted from 0001-01-01
1835
+
1836
+ toPgMicroseconds("2024-03-10T12:00:00Z");
1837
+ // 763387200000000n — microseconds since 2000-01-01
1838
+ ```
1839
+
1840
+ **NTP timestamps are era-ambiguous by design.** The seconds field is unsigned 32-bit, so it
1841
+ wraps every ~136.19 years and the era is not part of the value. `fromNtpTimestamp` takes it
1842
+ as an explicit argument:
1843
+
1844
+ ```typescript
1845
+ toNtpTimestamp("2036-02-07T06:28:15Z");
1846
+ // 18446744069414584320n — the last second of era 0
1847
+
1848
+ toNtpTimestamp("2036-02-07T06:28:16Z");
1849
+ // 0n — era 1 begins, and the seconds field wraps
1850
+
1851
+ fromNtpTimestamp(0n);
1852
+ // "1900-01-01T00:00:00Z"
1853
+
1854
+ fromNtpTimestamp(0n, 1);
1855
+ // "2036-02-07T06:28:16Z" — the same value, one era on
1856
+ ```
1857
+
1858
+ **Excel's serial 60 is the phantom 29 February 1900**, a date that never existed — 1900 was
1859
+ not a leap year. Lotus 1-2-3 got it wrong and Excel keeps the bug for compatibility, so the
1860
+ serial day `[60, 61)` is a hole rather than a date. "Fixing" it would put GMT one day out
1861
+ from Excel for every date before March 1900:
1862
+
1863
+ ```typescript
1864
+ fromExcelSerial(59);
1865
+ // "1900-02-28T00:00:00Z"
1866
+
1867
+ fromExcelSerial(60);
1868
+ // "" — the phantom 1900-02-29
1869
+
1870
+ fromExcelSerial(61);
1871
+ // "1900-03-01T00:00:00Z"
1872
+
1873
+ toExcelSerial("2024-03-10T12:00:00Z");
1874
+ // 45361.5 — days, with the time of day as the fraction
1875
+
1876
+ toExcelSerial("2024-03-10T12:00:00Z", { system: "1904" });
1877
+ // 43899.5 — the legacy Mac system, exactly 1462 days lower
1878
+ ```
1879
+
1880
+ Each bridge accepts only what its target format can actually hold, and returns the
1881
+ namespace's sentinel otherwise — `toFileTime` on a pre-1601 instant is `0n`, not a negative
1882
+ tick count, and `toExcelSerial` past 9999-12-31 is `null`, not an out-of-range serial.
1883
+ PostgreSQL's range is the one that surprises: its timestamp domain starts at 4713 BC, which
1884
+ is 40× later than the earliest instant Temporal can represent, so an in-range Temporal
1885
+ instant is not automatically an in-range PostgreSQL one. Where
1886
+ the target unit is coarser than a nanosecond the conversion floors toward negative infinity,
1887
+ so a round trip is exact to that unit: 100 ns for `FILETIME` and .NET ticks, 1 µs for
1888
+ PostgreSQL, 1 ms for Excel. NTP is the exception in the other direction — its 2^-32 s unit is
1889
+ finer than a nanosecond, so `fromNtpTimestamp` rounds to the nearest nanosecond and the round
1890
+ trip is exact.
1891
+ ### Spans
1892
+
1893
+ `diffZoned` measures in calendar units and returns a `Duration`. Profiling, tracing and
1894
+ telemetry want a raw number, and the `span/` namespace gives one:
1895
+
1896
+ ```typescript
1897
+ import { spanMs, spanNs, spanWallClock } from "@northguild/gmt";
1898
+
1899
+ spanMs("2024-03-10T12:00:00Z", "2024-03-10T12:00:01Z");
1900
+ // 1000
1901
+
1902
+ spanMs("2024-03-10T12:00:00Z", "2024-03-10T12:00:00.123456789Z");
1903
+ // 123.456789 — fractional, like performance.now()
1904
+
1905
+ spanNs("2024-03-10T12:00:00.123456789Z", "2024-03-10T12:00:00.123456790Z");
1906
+ // 1n
1907
+ ```
1908
+
1909
+ Both are signed — `spanMs(b, a)` is exactly `-spanMs(a, b)` — and both measure **exact
1910
+ elapsed time**. That is not the same question as calendar distance, and conflating the two
1911
+ is the most common span bug there is. A wall-clock day containing a DST transition is 23 or
1912
+ 25 hours long (24.5 in `Australia/Lord_Howe`), so:
1913
+
1914
+ ```typescript
1915
+ const start = "2024-03-09T12:00:00-05:00[America/New_York]";
1916
+ const end = "2024-03-10T12:00:00-04:00[America/New_York]";
1917
+
1918
+ spanMs(start, end);
1919
+ // 82800000 — 23 hours actually elapsed
1920
+
1921
+ spanWallClock(start, end, "hours");
1922
+ // 24 — the clock face advanced a full day
1923
+
1924
+ spanWallClock(start, end, "days");
1925
+ // 1
1926
+ ```
1927
+
1928
+ `spanWallClock` reads each endpoint's own local wall clock — straight off the string, never
1929
+ via an instant, so DST disambiguation cannot distort it and a local time that never occurred
1930
+ is measured as written. The two endpoints need not share a zone: a flight leaving New York at 23:00 and landing in Berlin at 11:00 the next local day
1931
+ is 12 wall-clock hours and 7 elapsed hours. It truncates toward zero, and it is not a count
1932
+ of midnights crossed.
1933
+
1934
+ `isValidSpan(start, end)` answers "will these two produce a span?" — true exactly when
1935
+ `spanMs` and `spanNs` will return a value. It is symmetric, since a reversed pair is a
1936
+ negative span rather than an invalid one. `spanWallClock` has a different input grammar and
1937
+ is covered by `isValidZonedDateTime`.
1938
+
1939
+ Three limits, all deliberate:
1940
+
1941
+ - **`0` and `0n` are valid spans**, so invalid input returns `null` from all three rather
1942
+ than the zero the rest of the library uses for numbers. `null` and not `NaN`: it is the
1943
+ sentinel every other number-returning function in GMT uses, and the only one
1944
+ `strictNullChecks` forces a caller to handle — a `NaN` types as plain `number` and
1945
+ propagates silently through arithmetic.
1946
+ - **`spanMs` returns `null` past `Number.MAX_SAFE_INTEGER` milliseconds** (±285,000 years,
1947
+ which two instants at opposite ends of `Temporal.Instant`'s range exceed). A
1948
+ sub-millisecond fraction counts toward that ceiling, so what comes back is always a safe
1949
+ integer or below. Use `spanNs` there; its result is a duration, not an instant, and can be
1950
+ twice the epoch-nanosecond range.
1951
+ - **Leap seconds are not counted.** UTC repeats a second rather than numbering a 61st one,
1952
+ so a span across one is a second short of the physical elapsed time; against a smeared
1953
+ clock (Google, AWS, Meta) the error is up to a second spread over the smear window.
1954
+
1955
+ ### Offset-preserving instants and local resolution
1956
+
1957
+ An instant orders events globally; the UTC offset in force where the event happened renders
1958
+ it as the human on the ground saw it. Neither derives from the other, which is why GS1 EPCIS
1959
+ 2.0 requires both fields (`eventTime` plus `eventTimeZoneOffset`), UN/EDIFACT DTM has
1960
+ qualifiers `303`/`304` for the pair, and DICOM appends `&ZZXX` to a `DT` value. The `instant/`
1961
+ namespace is that pair:
1962
+
1963
+ ```typescript
1964
+ import { fromOffsetInstant, toOffsetInstant } from "@northguild/gmt";
1965
+
1966
+ toOffsetInstant("2024-07-15T12:00:00-04:00[America/New_York]");
1967
+ // { instant: "2024-07-15T16:00:00Z", offset: "-04:00", timeZone: "America/New_York" }
1968
+
1969
+ // Most feeds send no zone at all — the offset alone is what happened.
1970
+ toOffsetInstant("2024-07-15T12:00:00-04:00");
1971
+ // { instant: "2024-07-15T16:00:00Z", offset: "-04:00" }
1972
+
1973
+ // A UTC-only feed plus a zone you know from somewhere else.
1974
+ toOffsetInstant("2024-07-15T16:00:00Z", "America/New_York");
1975
+ // { instant: "2024-07-15T16:00:00Z", offset: "-04:00", timeZone: "America/New_York" }
1976
+
1977
+ fromOffsetInstant({ instant: "2024-07-15T16:00:00Z", offset: "-04:00" });
1978
+ // "2024-07-15T12:00:00-04:00"
1979
+ ```
1980
+
1981
+ **An offset is not a zone.** `-05:00` does not identify `America/New_York` — it is every zone
1982
+ sitting at `-05:00` that day, and it says nothing about what that zone will do next spring.
1983
+ Store the zone for anything still to be scheduled; store the offset for anything that already
1984
+ happened. `timeZone` is optional because most feeds do not send one, and a string whose
1985
+ offset contradicts its own bracketed zone returns `null` rather than a guess.
1986
+
1987
+ The other half of the namespace is the reverse problem: a wall time that arrives with no
1988
+ offset at all ("gate-out 08:00"). Resolving one needs a zone the sender did not send, plus a
1989
+ policy for the two days a year the mapping is not one-to-one:
1990
+
1991
+ ```typescript
1992
+ import { classifyLocal, resolveLocal } from "@northguild/gmt";
1993
+
1994
+ classifyLocal("2024-11-03T01:30:00", "America/New_York"); // "ambiguous"
1995
+ classifyLocal("2024-03-10T02:30:00", "America/New_York"); // "nonexistent"
1996
+ classifyLocal("2024-07-15T12:00:00", "America/New_York"); // "unique"
1997
+
1998
+ resolveLocal("2024-11-03T01:30:00", "America/New_York");
1999
+ // "2024-11-03T05:30:00Z" — the default "compatible" takes the first 01:30
2000
+
2001
+ resolveLocal("2024-11-03T01:30:00", "America/New_York", { disambiguation: "later" });
2002
+ // "2024-11-03T06:30:00Z" — the same wall clock, an hour of real time later
2003
+
2004
+ resolveLocal("2024-11-03T01:30:00", "America/New_York", { disambiguation: "reject" });
2005
+ // "" — ambiguous, and not guessed
2006
+ ```
2007
+
2008
+ `classifyLocal` exists so code can branch **before** a policy is applied. A demurrage clock, a
2009
+ medication window or a duty limit should refuse an ambiguous wall time, or route it to a
2010
+ human — not silently accept whichever of two instants an hour apart a default handed it. See
2011
+ [DST Disambiguation](../../docs/dst-disambiguation.md) for the four strategies in full.
2012
+
2013
+ Two notes on the boundaries of this namespace:
2014
+
2015
+ - **`resolveLocal` returns an instant; `convertPlainDateTimeToZoned` returns a zoned string.**
2016
+ Same underlying resolution, different output and different precision — `resolveLocal` is
2017
+ exact to the nanosecond, while `convertPlainDateTimeToZoned` defaults to milliseconds.
2018
+ Neither takes an `offset` option. Reach for whichever shape you need next.
2019
+ - **`offset` is `±HH:MM`, except where it is not.** A handful of zones did not run on a whole
2020
+ minute before 1972 — `Africa/Monrovia` really was `-00:44:30` — and those report
2021
+ `±HH:MM:SS`. Rounding them would put the pair thirty seconds from the event it describes.
2022
+
2023
+ ### Calendar boundaries and zone-aware buckets
2024
+
2025
+ Two absences with outsized consequences, and they turn out to be the same absence twice: a
2026
+ calendar boundary is not a fixed number of hours, and it is not in UTC.
2027
+
2028
+ **Week and period identifiers.** Vessel schedules are published by week number and retail runs
2029
+ on 52/53-week fiscal calendars. Both come back as whole identifiers, not as fields to combine
2030
+ by hand — a week number without its week-numbering year is ambiguous at both ends of a year:
2031
+
2032
+ ```typescript
2033
+ import { getFiscalPeriod, getIsoWeekDate, getOrdinalDate, getQuarter } from "@northguild/gmt";
2034
+
2035
+ getIsoWeekDate("2027-01-01"); // { year: 2026, week: 53, weekday: 5 } — week-year 2026, not 2027
2036
+ getOrdinalDate("2024-12-31"); // { year: 2024, dayOfYear: 366 }
2037
+ getQuarter("2024-03-31", { fiscalYearStartMonth: 4 }); // { year: 2023, quarter: 4 }
2038
+
2039
+ // The NRF retail calendar, stated as its published rule: "the Saturday nearest to January 31".
2040
+ const nrf = { pattern: "4-5-4", yearEndsOn: "2026-01-31" } as const;
2041
+
2042
+ getFiscalPeriod("2024-06-15", nrf); // { year: 2024, period: 5, week: 19 }
2043
+ getFiscalPeriod("2024-01-28", nrf); // { year: 2023, period: 12, week: 53 } — a 53-week year
2044
+ ```
2045
+
2046
+ 52 × 7 is 364 days, so a 53rd week is inserted every five or six years and lands in the final
2047
+ period. `yearEndsOn` states the *rule*, by example — years end on that date's weekday, nearest
2048
+ that date's month and day — not one year's end, because GMT bundles no fiscal calendar. There
2049
+ is no single correct retail calendar to bundle.
2050
+
2051
+ **Zone-aware bucketing.** "Group by day in `America/New_York`" over UTC timestamps is the most
2052
+ common observability bug there is, and the same operation decides how many chargeable days a
2053
+ container accrued, because free time is counted in terminal-local calendar days:
2054
+
2055
+ ```typescript
2056
+ import { bucketRange, floorToZone } from "@northguild/gmt";
2057
+
2058
+ floorToZone("2024-06-15T03:00:00Z", "day", "America/New_York"); // "2024-06-14T04:00:00Z"
2059
+ floorToZone("2024-06-15T03:00:00Z", "day", "UTC"); // "2024-06-15T00:00:00Z"
2060
+ ```
2061
+
2062
+ Same instant, different calendar day — 03:00 UTC on 15 June is still 14 June in New York, and
2063
+ flooring it to the UTC day is wrong for most of the world for most of the day. The zone is an
2064
+ argument because GMT has no ambient one and must not acquire one.
2065
+
2066
+ `bucketRange` returns the boundaries spanning a range, and **the buckets are deliberately not
2067
+ uniform in length**:
2068
+
2069
+ ```typescript
2070
+ bucketRange("2024-03-09T05:00:00Z", "2024-03-12T04:00:00Z", "day", "America/New_York");
2071
+ // ["2024-03-09T05:00:00Z", "2024-03-10T05:00:00Z", "2024-03-11T04:00:00Z"]
2072
+ // 24h, then 23h — the middle day springs forward
2073
+
2074
+ bucketRange("2024-11-02T04:00:00Z", "2024-11-05T05:00:00Z", "day", "America/New_York");
2075
+ // ["2024-11-02T04:00:00Z", "2024-11-03T04:00:00Z", "2024-11-04T05:00:00Z"]
2076
+ // 24h, then 25h — the middle day falls back
2077
+ ```
2078
+
2079
+ Forcing 24 hours here is what makes a daily aggregate drift an hour twice a year. The same
2080
+ honesty applies to boundaries that do not exist: the calendar day Samoa deleted crossing the
2081
+ date line is absent from the list, a local day whose midnight is skipped by a spring-forward
2082
+ starts at 01:00, and in a zone that falls back by half an hour (`Australia/Lord_Howe`) the
2083
+ local 01:00 hour bucket is genuinely 90 minutes long.
2084
+
2085
+ For a zoned or epoch value, `startOfZoned`/`startOfUnix` with no options return the same real
2086
+ boundary. Do not floor with `roundZoned`/`roundUnix` and `roundingMode: "trunc"`: they follow
2087
+ TC39 `ZonedDateTime.round`, which rounds the wall clock and re-resolves it in the zone, so
2088
+ `"2024-09-29T03:50:00+13:45[Pacific/Chatham]"` truncated to the hour gives 04:00 — after the
2089
+ input.
2090
+
2091
+ A pattern or a bucket unit the namespace does not recognise returns the same sentinel an
2092
+ unusable date or instant does, so both unions have a type guard to narrow one that arrived as
2093
+ a bare string — from config, an env var, a form:
2094
+
2095
+ ```typescript
2096
+ import { isValidFiscalPattern, isValidZoneBucketUnit } from "@northguild/gmt";
2097
+
2098
+ isValidFiscalPattern("4-5-4"); // true — the NRF retail calendar
2099
+ isValidFiscalPattern("4-5-5"); // false — the shape a 53-week year's last quarter takes
2100
+ isValidZoneBucketUnit("day"); // true
2101
+ isValidZoneBucketUnit("days"); // true — singular or plural, as floorToZone accepts
2102
+ isValidZoneBucketUnit("year"); // false — the year question is getQuarter's
2103
+ ```
2104
+
2105
+ ### Interval algebra
2106
+
2107
+ Four realms need the same operation and none of them could express it: sum the parts of an
2108
+ interval that fall inside a set of allowed windows. Laytime counts only the hours a charter
2109
+ clause allows, driver hours split a duty period around mandatory rest, demurrage free time
2110
+ counts only working days, and a trading window counts only continuous-session time. The
2111
+ `interval/` namespace is that one shared primitive, with one boundary rule:
2112
+
2113
+ **Half-open `[start, end)`.** An instant `t` is inside when `start ≤ t < end`. That is SQL:2011's
2114
+ closed-open `PERIOD`, RFC 5545's non-inclusive `DTEND` and Dijkstra's EWD831. A container gated
2115
+ out at exactly 17:00 has not used another day, and two consecutive shifts never double-count the
2116
+ instant they meet.
2117
+
2118
+ ```typescript
2119
+ import {
2120
+ clampInterval,
2121
+ intersectIntervals,
2122
+ intervalContains,
2123
+ intervalsOverlap,
2124
+ isValidInterval,
2125
+ mergeIntervals,
2126
+ splitIntervalAt,
2127
+ subtractIntervals,
2128
+ sumIntervals,
2129
+ } from "@northguild/gmt";
2130
+
2131
+ const shift = { start: "2024-01-01T09:00:00Z", end: "2024-01-01T17:00:00Z" };
2132
+
2133
+ intervalContains(shift, "2024-01-01T09:00:00Z"); // true — start is inside
2134
+ intervalContains(shift, "2024-01-01T17:00:00Z"); // false — end is not
2135
+
2136
+ intervalsOverlap(shift, { start: "2024-01-01T17:00:00Z", end: "2024-01-01T18:00:00Z" });
2137
+ // false — touching intervals share no instant
2138
+ intersectIntervals(shift, { start: "2024-01-01T12:00:00Z", end: "2024-01-01T18:00:00Z" });
2139
+ // { start: "2024-01-01T12:00:00Z", end: "2024-01-01T17:00:00Z" }
2140
+ clampInterval({ start: "2024-01-01T08:00:00Z", end: "2024-01-01T12:00:00Z" }, shift);
2141
+ // { start: "2024-01-01T09:00:00Z", end: "2024-01-01T12:00:00Z" }
2142
+
2143
+ mergeIntervals([
2144
+ { start: "2024-01-01T13:00:00Z", end: "2024-01-01T17:00:00Z" },
2145
+ { start: "2024-01-01T09:00:00Z", end: "2024-01-01T12:00:00Z" },
2146
+ { start: "2024-01-01T12:00:00Z", end: "2024-01-01T13:00:00Z" },
2147
+ ]);
2148
+ // [{ start: "2024-01-01T09:00:00Z", end: "2024-01-01T17:00:00Z" }] — sorted, touching runs joined
2149
+
2150
+ const worked = subtractIntervals(shift, [{ start: "2024-01-01T12:00:00Z", end: "2024-01-01T13:00:00Z" }]);
2151
+ // [{ start: "2024-01-01T09:00:00Z", end: "2024-01-01T12:00:00Z" },
2152
+ // { start: "2024-01-01T13:00:00Z", end: "2024-01-01T17:00:00Z" }]
2153
+ sumIntervals(worked); // "PT7H"
2154
+
2155
+ splitIntervalAt(shift, ["2024-01-01T15:00:00Z", "2024-01-01T11:00:00Z"]);
2156
+ // [{ start: "2024-01-01T09:00:00Z", end: "2024-01-01T11:00:00Z" },
2157
+ // { start: "2024-01-01T11:00:00Z", end: "2024-01-01T15:00:00Z" },
2158
+ // { start: "2024-01-01T15:00:00Z", end: "2024-01-01T17:00:00Z" }] — pieces share no instant
2159
+
2160
+ isValidInterval({ start: "2024-01-01T17:00:00Z", end: "2024-01-01T09:00:00Z" }); // false — inverted
2161
+ ```
2162
+
2163
+ - **Endpoints are instants.** An offset (`Z` or `±HH:MM`) is required and a `[Zone]` annotation is
2164
+ optional. As with a TC39 `Temporal.Instant`, endpoints compare by epoch nanoseconds, so two of
2165
+ them may name different zones. Leap seconds are rejected, and a `[u-ca=…]` annotation is ignored, as `Temporal.Instant.from` ignores it. For local-calendar
2166
+ edges, build them with `floorToZone` or `bucketRange` first.
2167
+ - **Outputs are the caller's own strings**, never re-serialised. When two strings spell the same
2168
+ instant, the first argument's spelling wins. No spec covers the tie, so this is a GMT rule.
2169
+ - **`start === end` is a valid empty interval.** It contains no instant, overlaps only an interval
2170
+ it lies strictly inside, and adds nothing to a sum. An inverted interval returns the sentinel:
2171
+ `false`, `null`, `[]` or `""`.
2172
+ - **`sumIntervals` is covered time.** It returns the length of the union, with overlaps counted
2173
+ once, as an exact duration with hours as the largest unit. That is exactly what TC39
2174
+ `Instant.prototype.until(…, { largestUnit: "hour" })` produces, because an instant has no
2175
+ calendar that says how long a day is. So `PT49H30M` is never written `P2DT1H30M`, a New York
2176
+ spring-forward day is `PT23H`, and `sumIntervals([])` is `"PT0S"`. The sum is exact past
2177
+ 2^53 nanoseconds.
2178
+ - **`[]` means two things.** From `mergeIntervals`, `subtractIntervals` and `splitIntervalAt` it
2179
+ is both a legitimate result (a fully covered subtraction) and the invalid-input sentinel.
2180
+ `isValidInterval` tells them apart.
2181
+
1607
2182
  ## API Surface
1608
2183
 
1609
2184
  For the complete API listing, see the namespace documentation on GitHub:
@@ -1612,6 +2187,11 @@ For the complete API listing, see the namespace documentation on GitHub:
1612
2187
  - [Plain API](https://github.com/northguild/gmt/tree/main/packages/gmt/src/plain) — timezone-free operations
1613
2188
  - [Zoned API](https://github.com/northguild/gmt/tree/main/packages/gmt/src/zoned) — IANA timezone-aware operations
1614
2189
  - [Unix API](https://github.com/northguild/gmt/tree/main/packages/gmt/src/unix) — Unix epoch utilities
2190
+ - [Precision API](https://github.com/northguild/gmt/tree/main/packages/gmt/src/precision) — nanosecond instants, JSON transport, storage truncation, NTP / FILETIME / .NET ticks / Excel / PostgreSQL epoch bridges
2191
+ - [Span API](https://github.com/northguild/gmt/tree/main/packages/gmt/src/span) — elapsed and wall-clock durations as raw numbers
2192
+ - [Calendar API](https://github.com/northguild/gmt/tree/main/packages/gmt/src/calendar) — ISO week and ordinal dates, quarter and fiscal periods, zone-aware bucketing, and business calendars with holiday sets and roll conventions
2193
+ - [Interval API](https://github.com/northguild/gmt/tree/main/packages/gmt/src/interval) — half-open interval algebra over instants: overlap, intersect, clamp, merge, subtract, split, sum
2194
+ - [Instant API](https://github.com/northguild/gmt/tree/main/packages/gmt/src/instant) — the instant-plus-offset pair, and explicit local-time resolution
1615
2195
  - [UTC API](https://github.com/northguild/gmt/tree/main/packages/gmt/src/utc) — UTC instant utilities
1616
2196
  - [Regex API](https://github.com/northguild/gmt/tree/main/packages/gmt/src/regex) — composable regex patterns
1617
2197
 
@@ -1647,7 +2227,7 @@ When working with `@northguild/gmt`, follow these rules:
1647
2227
  3. **Invalid input returns a sentinel, never throws.** `""` for strings, `null` for numbers, `false` for booleans, `[]` for arrays.
1648
2228
  4. **Wrap all Temporal calls in `try-catch`.** `.from()`, `.add()`, `.since()`, etc. throw `RangeError` on bad input.
1649
2229
  5. **Keep `plain/` and `zoned/` strictly separate.** Never mix `PlainDateTime` and `ZonedDateTime`.
1650
- 6. **Full locale matrix for any locale-aware function.** 17 locales, explicit rows, `hasFullIcu` ternaries where output differs.
2230
+ 6. **Full locale matrix for any locale-aware function.** 17 locales, explicit rows, `expectOneOfIcu`/`expectDateTimeEqual` (from `src/test/icuVariants.ts`) where CLDR wording differs.
1651
2231
  7. **Use pre-built mocks for error-path tests.** See `packages/gmt/src/test/mocks`.
1652
2232
  8. **JSDoc with `@example` on every public function.** Cover valid, invalid, and edge-case inputs.
1653
2233