@northguild/gmt 1.18.0 → 1.19.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 (593) hide show
  1. package/README.md +55 -2920
  2. package/dist/calendar/calculate/bucketRange.d.ts +10 -2
  3. package/dist/calendar/calculate/bucketRange.js +18 -61
  4. package/dist/calendar/calculate/floorToZone.d.ts +10 -2
  5. package/dist/calendar/calculate/floorToZone.js +15 -7
  6. package/dist/calendar/hours/addOperatingTime.d.ts +6 -0
  7. package/dist/calendar/hours/addOperatingTime.js +7 -1
  8. package/dist/calendar/hours/isOpenAt.d.ts +6 -0
  9. package/dist/calendar/hours/isOpenAt.js +6 -0
  10. package/dist/calendar/hours/nextCloseAt.d.ts +6 -0
  11. package/dist/calendar/hours/nextCloseAt.js +7 -1
  12. package/dist/calendar/hours/nextOpenAt.d.ts +6 -0
  13. package/dist/calendar/hours/nextOpenAt.js +7 -1
  14. package/dist/calendar/hours/operatingIntervals.d.ts +5 -0
  15. package/dist/calendar/hours/operatingIntervals.js +5 -0
  16. package/dist/calendar/hours/operatingTimeBetween.d.ts +5 -0
  17. package/dist/calendar/hours/operatingTimeBetween.js +5 -0
  18. package/dist/calendar/hours/recurringWindows.d.ts +8 -1
  19. package/dist/calendar/hours/recurringWindows.js +12 -4
  20. package/dist/duration/calculate/durationFromUnits.d.ts +47 -0
  21. package/dist/duration/calculate/durationFromUnits.js +67 -0
  22. package/dist/duration/calculate/getDurationUnit.d.ts +2 -2
  23. package/dist/duration/calculate/getDurationUnit.js +2 -2
  24. package/dist/duration/calculate/index.d.ts +3 -1
  25. package/dist/duration/calculate/index.js +3 -1
  26. package/dist/duration/calculate/negateDuration.d.ts +1 -1
  27. package/dist/duration/calculate/negateDuration.js +1 -1
  28. package/dist/duration/calculate/{durationAs.d.ts → totalDuration.d.ts} +25 -19
  29. package/dist/duration/calculate/{durationAs.js → totalDuration.js} +25 -19
  30. package/dist/duration/calculate/totalUnits.d.ts +49 -0
  31. package/dist/duration/calculate/totalUnits.js +73 -0
  32. package/dist/duration/compare/compareDurations.d.ts +1 -1
  33. package/dist/duration/compare/compareDurations.js +1 -1
  34. package/dist/duty/calculate/dutyDayFor.d.ts +38 -0
  35. package/dist/duty/calculate/dutyDayFor.js +71 -0
  36. package/dist/duty/calculate/dutyTotals.d.ts +24 -0
  37. package/dist/duty/calculate/dutyTotals.js +41 -0
  38. package/dist/duty/calculate/dutyViolations.d.ts +74 -0
  39. package/dist/duty/calculate/dutyViolations.js +65 -0
  40. package/dist/duty/calculate/evaluateDutyLog.d.ts +77 -0
  41. package/dist/duty/calculate/evaluateDutyLog.js +75 -0
  42. package/dist/duty/calculate/index.d.ts +7 -0
  43. package/dist/duty/calculate/index.js +7 -0
  44. package/dist/duty/calculate/longestRun.d.ts +28 -0
  45. package/dist/duty/calculate/longestRun.js +54 -0
  46. package/dist/duty/calculate/qualifyingRestPairs.d.ts +37 -0
  47. package/dist/duty/calculate/qualifyingRestPairs.js +58 -0
  48. package/dist/duty/calculate/qualifyingRests.d.ts +27 -0
  49. package/dist/duty/calculate/qualifyingRests.js +49 -0
  50. package/dist/duty/index.d.ts +3 -0
  51. package/dist/duty/index.js +4 -0
  52. package/dist/duty/validate/index.d.ts +1 -0
  53. package/dist/duty/validate/index.js +1 -0
  54. package/dist/duty/validate/isValidDutyLog.d.ts +24 -0
  55. package/dist/duty/validate/isValidDutyLog.js +34 -0
  56. package/dist/index.d.ts +1 -0
  57. package/dist/index.js +1 -0
  58. package/dist/instant/convert/classifyLocal.d.ts +5 -1
  59. package/dist/instant/convert/classifyLocal.js +16 -6
  60. package/dist/instant/convert/fromOffsetInstant.d.ts +4 -0
  61. package/dist/instant/convert/fromOffsetInstant.js +6 -1
  62. package/dist/instant/convert/resolveLocal.d.ts +7 -2
  63. package/dist/instant/convert/resolveLocal.js +16 -8
  64. package/dist/instant/convert/toOffsetInstant.d.ts +12 -8
  65. package/dist/instant/convert/toOffsetInstant.js +19 -11
  66. package/dist/instant/index.d.ts +1 -0
  67. package/dist/instant/index.js +1 -0
  68. package/dist/instant/validate/index.d.ts +1 -0
  69. package/dist/instant/validate/index.js +1 -0
  70. package/dist/instant/validate/isValidUtcOffset.d.ts +32 -0
  71. package/dist/instant/validate/isValidUtcOffset.js +35 -0
  72. package/dist/intermodal/calculate/chargeableDays.d.ts +6 -0
  73. package/dist/intermodal/calculate/chargeableDays.js +12 -4
  74. package/dist/intermodal/calculate/freeTimeExpiry.d.ts +7 -0
  75. package/dist/intermodal/calculate/freeTimeExpiry.js +15 -4
  76. package/dist/intermodal/calculate/index.d.ts +1 -0
  77. package/dist/intermodal/calculate/index.js +1 -0
  78. package/dist/intermodal/calculate/multimodalETA.d.ts +76 -0
  79. package/dist/intermodal/calculate/multimodalETA.js +145 -0
  80. package/dist/intermodal/format/bolTimestamp.d.ts +76 -0
  81. package/dist/intermodal/format/bolTimestamp.js +78 -0
  82. package/dist/intermodal/format/formatEdifactDate.d.ts +34 -0
  83. package/dist/intermodal/format/formatEdifactDate.js +42 -0
  84. package/dist/intermodal/format/formatEdifactDatePeriod.d.ts +35 -0
  85. package/dist/intermodal/format/formatEdifactDatePeriod.js +43 -0
  86. package/dist/intermodal/format/formatEdifactDateTime.d.ts +37 -0
  87. package/dist/intermodal/format/formatEdifactDateTime.js +45 -0
  88. package/dist/intermodal/format/formatEdifactDateTimePeriod.d.ts +40 -0
  89. package/dist/intermodal/format/formatEdifactDateTimePeriod.js +48 -0
  90. package/dist/intermodal/format/formatEdifactOffsetDateTime.d.ts +62 -0
  91. package/dist/intermodal/format/formatEdifactOffsetDateTime.js +70 -0
  92. package/dist/intermodal/format/formatEdifactTime.d.ts +35 -0
  93. package/dist/intermodal/format/formatEdifactTime.js +43 -0
  94. package/dist/intermodal/format/formatEpcisEvent.d.ts +47 -0
  95. package/dist/intermodal/format/formatEpcisEvent.js +79 -0
  96. package/dist/intermodal/format/formatX12Date.d.ts +35 -0
  97. package/dist/intermodal/format/formatX12Date.js +43 -0
  98. package/dist/intermodal/format/formatX12DateRange.d.ts +37 -0
  99. package/dist/intermodal/format/formatX12DateRange.js +45 -0
  100. package/dist/intermodal/format/formatX12DateTime.d.ts +39 -0
  101. package/dist/intermodal/format/formatX12DateTime.js +47 -0
  102. package/dist/intermodal/format/formatX12DateTimeRange.d.ts +40 -0
  103. package/dist/intermodal/format/formatX12DateTimeRange.js +48 -0
  104. package/dist/intermodal/format/formatX12Time.d.ts +42 -0
  105. package/dist/intermodal/format/formatX12Time.js +50 -0
  106. package/dist/intermodal/format/formatX12TimeElement.d.ts +46 -0
  107. package/dist/intermodal/format/formatX12TimeElement.js +54 -0
  108. package/dist/intermodal/format/index.d.ts +14 -0
  109. package/dist/intermodal/format/index.js +14 -0
  110. package/dist/intermodal/index.d.ts +3 -0
  111. package/dist/intermodal/index.js +3 -0
  112. package/dist/intermodal/parse/classifyEdifactDtmFormat.d.ts +48 -0
  113. package/dist/intermodal/parse/classifyEdifactDtmFormat.js +55 -0
  114. package/dist/intermodal/parse/classifyX12DateTimePeriodFormat.d.ts +50 -0
  115. package/dist/intermodal/parse/classifyX12DateTimePeriodFormat.js +57 -0
  116. package/dist/intermodal/parse/classifyX12TimeCode.d.ts +46 -0
  117. package/dist/intermodal/parse/classifyX12TimeCode.js +57 -0
  118. package/dist/intermodal/parse/index.d.ts +18 -0
  119. package/dist/intermodal/parse/index.js +18 -0
  120. package/dist/intermodal/parse/parseEdifactDate.d.ts +37 -0
  121. package/dist/intermodal/parse/parseEdifactDate.js +45 -0
  122. package/dist/intermodal/parse/parseEdifactDatePeriod.d.ts +43 -0
  123. package/dist/intermodal/parse/parseEdifactDatePeriod.js +51 -0
  124. package/dist/intermodal/parse/parseEdifactDateTime.d.ts +43 -0
  125. package/dist/intermodal/parse/parseEdifactDateTime.js +51 -0
  126. package/dist/intermodal/parse/parseEdifactDateTimePeriod.d.ts +45 -0
  127. package/dist/intermodal/parse/parseEdifactDateTimePeriod.js +53 -0
  128. package/dist/intermodal/parse/parseEdifactOffsetDateTime.d.ts +60 -0
  129. package/dist/intermodal/parse/parseEdifactOffsetDateTime.js +68 -0
  130. package/dist/intermodal/parse/parseEdifactTime.d.ts +37 -0
  131. package/dist/intermodal/parse/parseEdifactTime.js +45 -0
  132. package/dist/intermodal/parse/parseEpcisEvent.d.ts +95 -0
  133. package/dist/intermodal/parse/parseEpcisEvent.js +102 -0
  134. package/dist/intermodal/parse/parseX12Date.d.ts +39 -0
  135. package/dist/intermodal/parse/parseX12Date.js +47 -0
  136. package/dist/intermodal/parse/parseX12DateAndTime.d.ts +52 -0
  137. package/dist/intermodal/parse/parseX12DateAndTime.js +61 -0
  138. package/dist/intermodal/parse/parseX12DateRange.d.ts +44 -0
  139. package/dist/intermodal/parse/parseX12DateRange.js +52 -0
  140. package/dist/intermodal/parse/parseX12DateTime.d.ts +45 -0
  141. package/dist/intermodal/parse/parseX12DateTime.js +53 -0
  142. package/dist/intermodal/parse/parseX12DateTimeRange.d.ts +46 -0
  143. package/dist/intermodal/parse/parseX12DateTimeRange.js +54 -0
  144. package/dist/intermodal/parse/parseX12Time.d.ts +65 -0
  145. package/dist/intermodal/parse/parseX12Time.js +77 -0
  146. package/dist/intermodal/parse/x12TimeCodeOffset.d.ts +57 -0
  147. package/dist/intermodal/parse/x12TimeCodeOffset.js +110 -0
  148. package/dist/intermodal/parse/x12TimeCodeZone.d.ts +57 -0
  149. package/dist/intermodal/parse/x12TimeCodeZone.js +105 -0
  150. package/dist/intermodal/validate/index.d.ts +18 -0
  151. package/dist/intermodal/validate/index.js +18 -0
  152. package/dist/intermodal/validate/isValidEdifactDate.d.ts +26 -0
  153. package/dist/intermodal/validate/isValidEdifactDate.js +28 -0
  154. package/dist/intermodal/validate/isValidEdifactDatePeriod.d.ts +28 -0
  155. package/dist/intermodal/validate/isValidEdifactDatePeriod.js +30 -0
  156. package/dist/intermodal/validate/isValidEdifactDateTime.d.ts +30 -0
  157. package/dist/intermodal/validate/isValidEdifactDateTime.js +32 -0
  158. package/dist/intermodal/validate/isValidEdifactDateTimePeriod.d.ts +28 -0
  159. package/dist/intermodal/validate/isValidEdifactDateTimePeriod.js +30 -0
  160. package/dist/intermodal/validate/isValidEdifactDtmFormat.d.ts +39 -0
  161. package/dist/intermodal/validate/isValidEdifactDtmFormat.js +42 -0
  162. package/dist/intermodal/validate/isValidEdifactOffsetDateTime.d.ts +36 -0
  163. package/dist/intermodal/validate/isValidEdifactOffsetDateTime.js +38 -0
  164. package/dist/intermodal/validate/isValidEdifactTime.d.ts +28 -0
  165. package/dist/intermodal/validate/isValidEdifactTime.js +30 -0
  166. package/dist/intermodal/validate/isValidEpcisEvent.d.ts +41 -0
  167. package/dist/intermodal/validate/isValidEpcisEvent.js +58 -0
  168. package/dist/intermodal/validate/isValidEpcisEventTime.d.ts +33 -0
  169. package/dist/intermodal/validate/isValidEpcisEventTime.js +48 -0
  170. package/dist/intermodal/validate/isValidEpcisTimeZoneOffset.d.ts +30 -0
  171. package/dist/intermodal/validate/isValidEpcisTimeZoneOffset.js +38 -0
  172. package/dist/intermodal/validate/isValidX12Date.d.ts +28 -0
  173. package/dist/intermodal/validate/isValidX12Date.js +30 -0
  174. package/dist/intermodal/validate/isValidX12DateAndTime.d.ts +32 -0
  175. package/dist/intermodal/validate/isValidX12DateAndTime.js +35 -0
  176. package/dist/intermodal/validate/isValidX12DateRange.d.ts +29 -0
  177. package/dist/intermodal/validate/isValidX12DateRange.js +31 -0
  178. package/dist/intermodal/validate/isValidX12DateTime.d.ts +30 -0
  179. package/dist/intermodal/validate/isValidX12DateTime.js +32 -0
  180. package/dist/intermodal/validate/isValidX12DateTimePeriodFormat.d.ts +43 -0
  181. package/dist/intermodal/validate/isValidX12DateTimePeriodFormat.js +46 -0
  182. package/dist/intermodal/validate/isValidX12DateTimeRange.d.ts +31 -0
  183. package/dist/intermodal/validate/isValidX12DateTimeRange.js +33 -0
  184. package/dist/intermodal/validate/isValidX12Time.d.ts +38 -0
  185. package/dist/intermodal/validate/isValidX12Time.js +40 -0
  186. package/dist/intermodal/validate/isValidX12TimeCode.d.ts +38 -0
  187. package/dist/intermodal/validate/isValidX12TimeCode.js +41 -0
  188. package/dist/internal/businessCalendar.js +4 -9
  189. package/dist/internal/dutyEngine.d.ts +125 -0
  190. package/dist/internal/dutyEngine.js +1746 -0
  191. package/dist/internal/dutyLog.d.ts +27 -0
  192. package/dist/internal/dutyLog.js +47 -0
  193. package/dist/internal/dutyPeriods.d.ts +135 -0
  194. package/dist/internal/dutyPeriods.js +369 -0
  195. package/dist/internal/dutyRules.d.ts +197 -0
  196. package/dist/internal/dutyRules.js +484 -0
  197. package/dist/internal/ediDateTimeFields.d.ts +97 -0
  198. package/dist/internal/ediDateTimeFields.js +288 -0
  199. package/dist/internal/ediDateTimeWriter.d.ts +92 -0
  200. package/dist/internal/ediDateTimeWriter.js +298 -0
  201. package/dist/internal/ediGrammar.d.ts +158 -0
  202. package/dist/internal/ediGrammar.js +384 -0
  203. package/dist/internal/englishCalendarNames.d.ts +3 -1
  204. package/dist/internal/englishCalendarNames.js +3 -1
  205. package/dist/internal/freeTimeLedger.d.ts +5 -0
  206. package/dist/internal/freeTimeLedger.js +11 -2
  207. package/dist/internal/index.d.ts +5 -2
  208. package/dist/internal/index.js +9 -2
  209. package/dist/internal/intervalNanoseconds.js +2 -1
  210. package/dist/internal/isObject.d.ts +13 -6
  211. package/dist/internal/isObject.js +14 -7
  212. package/dist/internal/isoYearString.d.ts +21 -0
  213. package/dist/internal/isoYearString.js +27 -0
  214. package/dist/internal/maxPieces.js +2 -1
  215. package/dist/internal/normalizeTimeZone.d.ts +4 -1
  216. package/dist/internal/normalizeTimeZone.js +4 -1
  217. package/dist/internal/operatingSchedule.d.ts +13 -4
  218. package/dist/internal/operatingSchedule.js +146 -58
  219. package/dist/internal/patternToken.d.ts +10 -3
  220. package/dist/internal/patternToken.js +31 -12
  221. package/dist/internal/readDurationUnits.d.ts +34 -0
  222. package/dist/internal/readDurationUnits.js +78 -0
  223. package/dist/internal/readSetFields.d.ts +50 -0
  224. package/dist/internal/readSetFields.js +179 -0
  225. package/dist/internal/resolveRelativeUnit.d.ts +1 -1
  226. package/dist/internal/resolveRelativeUnit.js +1 -1
  227. package/dist/internal/resolveUnixIntervalPair.d.ts +8 -2
  228. package/dist/internal/resolveUnixIntervalPair.js +11 -7
  229. package/dist/internal/startOrEndOfUnix.d.ts +2 -1
  230. package/dist/internal/startOrEndOfUnix.js +9 -6
  231. package/dist/internal/twoDigitYear.d.ts +19 -0
  232. package/dist/internal/twoDigitYear.js +22 -0
  233. package/dist/internal/unixEpochValue.js +3 -2
  234. package/dist/internal/unixWallClock.d.ts +24 -0
  235. package/dist/internal/unixWallClock.js +35 -0
  236. package/dist/internal/utcWallClock.d.ts +20 -0
  237. package/dist/internal/utcWallClock.js +32 -0
  238. package/dist/internal/yearWindowStart.d.ts +28 -0
  239. package/dist/internal/yearWindowStart.js +52 -0
  240. package/dist/internal/zoneBucketCap.d.ts +18 -0
  241. package/dist/internal/zoneBucketCap.js +64 -0
  242. package/dist/internal/zoneFrame.d.ts +180 -0
  243. package/dist/internal/zoneFrame.js +221 -0
  244. package/dist/internal/zonedNowUnitValue.d.ts +7 -4
  245. package/dist/internal/zonedNowUnitValue.js +8 -4
  246. package/dist/internal/zonedWallClockDifference.js +4 -4
  247. package/dist/internal/zonedWallClockOperations.d.ts +5 -2
  248. package/dist/internal/zonedWallClockOperations.js +7 -10
  249. package/dist/plain/calculate/addDate.js +4 -7
  250. package/dist/plain/calculate/addDateTime.js +4 -7
  251. package/dist/plain/calculate/addTime.js +4 -7
  252. package/dist/plain/calculate/endOfTime.d.ts +1 -1
  253. package/dist/plain/calculate/setDate.d.ts +20 -3
  254. package/dist/plain/calculate/setDate.js +27 -7
  255. package/dist/plain/calculate/setDateTime.d.ts +15 -3
  256. package/dist/plain/calculate/setDateTime.js +22 -7
  257. package/dist/plain/calculate/setTime.d.ts +13 -1
  258. package/dist/plain/calculate/setTime.js +21 -6
  259. package/dist/plain/calculate/startOfTime.d.ts +1 -1
  260. package/dist/plain/calculate/subtractDate.js +4 -7
  261. package/dist/plain/calculate/subtractDateTime.js +4 -7
  262. package/dist/plain/calculate/subtractTime.js +4 -7
  263. package/dist/plain/format/formatCalendar.js +2 -1
  264. package/dist/plain/format/formatRelativeDate.js +2 -1
  265. package/dist/plain/format/formatRelativeDateTime.js +2 -1
  266. package/dist/plain/format/formatRelativeTime.js +2 -1
  267. package/dist/plain/format/{formatSql.d.ts → formatSqlDateTime.d.ts} +7 -7
  268. package/dist/plain/format/{formatSql.js → formatSqlDateTime.js} +7 -7
  269. package/dist/plain/format/index.d.ts +1 -1
  270. package/dist/plain/format/index.js +1 -1
  271. package/dist/plain/get/getNowUnit.d.ts +2 -0
  272. package/dist/plain/get/getNowUnit.js +2 -0
  273. package/dist/plain/get/getYear.d.ts +2 -0
  274. package/dist/plain/get/getYear.js +4 -3
  275. package/dist/plain/interval/intervalXorAllDate.js +2 -2
  276. package/dist/plain/interval/intervalXorAllDateTime.js +2 -2
  277. package/dist/plain/interval/intervalXorAllTime.js +2 -2
  278. package/dist/plain/interval/mergeIntervalsDate.js +2 -2
  279. package/dist/plain/interval/mergeIntervalsDateTime.js +2 -2
  280. package/dist/plain/interval/mergeIntervalsTime.js +2 -2
  281. package/dist/plain/parse/index.d.ts +1 -1
  282. package/dist/plain/parse/index.js +1 -1
  283. package/dist/plain/parse/parseDateTimeWithPattern.d.ts +16 -3
  284. package/dist/plain/parse/parseDateTimeWithPattern.js +20 -5
  285. package/dist/plain/parse/parseDateWithPattern.d.ts +17 -3
  286. package/dist/plain/parse/parseDateWithPattern.js +21 -5
  287. package/dist/plain/parse/{parseSql.d.ts → parseSqlDateTime.d.ts} +8 -8
  288. package/dist/plain/parse/{parseSql.js → parseSqlDateTime.js} +8 -8
  289. package/dist/plain/parse/parseTimeWithPattern.js +1 -0
  290. package/dist/plain/parse/parseUnitFromDate.d.ts +3 -0
  291. package/dist/plain/parse/parseUnitFromDate.js +5 -1
  292. package/dist/plain/parse/parseUnitFromDateTime.d.ts +3 -0
  293. package/dist/plain/parse/parseUnitFromDateTime.js +5 -1
  294. package/dist/plain/parse/parseYearFromDate.d.ts +5 -2
  295. package/dist/plain/parse/parseYearFromDate.js +7 -3
  296. package/dist/plain/parse/parseYearFromDateTime.d.ts +4 -2
  297. package/dist/plain/parse/parseYearFromDateTime.js +6 -3
  298. package/dist/plain/validate/index.d.ts +1 -0
  299. package/dist/plain/validate/index.js +1 -0
  300. package/dist/plain/validate/isValidSqlDateTime.d.ts +33 -0
  301. package/dist/plain/validate/isValidSqlDateTime.js +36 -0
  302. package/dist/precision/convert/fromNanoseconds.d.ts +9 -3
  303. package/dist/precision/convert/fromNanoseconds.js +9 -3
  304. package/dist/regex/epcis.d.ts +60 -0
  305. package/dist/regex/epcis.js +60 -0
  306. package/dist/regex/http-date.d.ts +6 -4
  307. package/dist/regex/http-date.js +6 -4
  308. package/dist/regex/index.d.ts +1 -0
  309. package/dist/regex/index.js +1 -0
  310. package/dist/regex/rfc-2822.d.ts +2 -0
  311. package/dist/regex/rfc-2822.js +2 -0
  312. package/dist/regex/rfc-3339.d.ts +3 -1
  313. package/dist/regex/rfc-3339.js +3 -1
  314. package/dist/regex/sql-date-time.d.ts +2 -1
  315. package/dist/regex/sql-date-time.js +2 -1
  316. package/dist/regex/time-zone-like.d.ts +3 -2
  317. package/dist/regex/time-zone-like.js +3 -2
  318. package/dist/regex/utc-offset.d.ts +2 -1
  319. package/dist/regex/utc-offset.js +2 -1
  320. package/dist/transport/calculate/crossingTime.d.ts +6 -1
  321. package/dist/transport/calculate/crossingTime.js +6 -1
  322. package/dist/transport/calculate/cutoffAt.d.ts +6 -1
  323. package/dist/transport/calculate/cutoffAt.js +2 -0
  324. package/dist/transport/calculate/cutoffSchedule.d.ts +6 -1
  325. package/dist/transport/calculate/cutoffSchedule.js +2 -0
  326. package/dist/transport/calculate/dwellTime.d.ts +6 -1
  327. package/dist/transport/calculate/dwellTime.js +6 -1
  328. package/dist/transport/calculate/scheduleDelivery.d.ts +13 -5
  329. package/dist/transport/calculate/scheduleDelivery.js +6 -1
  330. package/dist/transport/convert/etaAtZone.d.ts +6 -1
  331. package/dist/transport/convert/etaAtZone.js +6 -1
  332. package/dist/types/business-calendar.d.ts +5 -4
  333. package/dist/types/duty.d.ts +777 -0
  334. package/dist/types/duty.js +0 -0
  335. package/dist/types/edi.d.ts +407 -0
  336. package/dist/types/edi.js +0 -0
  337. package/dist/types/epcis.d.ts +25 -0
  338. package/dist/types/epcis.js +0 -0
  339. package/dist/types/exact-duration-unit.d.ts +8 -0
  340. package/dist/types/exact-duration-unit.js +0 -0
  341. package/dist/types/free-time-options.d.ts +4 -3
  342. package/dist/types/index.d.ts +5 -0
  343. package/dist/types/index.js +5 -0
  344. package/dist/types/operating-schedule.d.ts +3 -2
  345. package/dist/types/two-digit-year.d.ts +23 -0
  346. package/dist/types/two-digit-year.js +0 -0
  347. package/dist/types/zone-bucket-unit.d.ts +1 -1
  348. package/dist/unix/calculate/addUnix.d.ts +11 -2
  349. package/dist/unix/calculate/addUnix.js +14 -11
  350. package/dist/unix/calculate/diffUnix.d.ts +10 -2
  351. package/dist/unix/calculate/diffUnix.js +11 -6
  352. package/dist/unix/calculate/diffUnixAsDuration.d.ts +10 -2
  353. package/dist/unix/calculate/diffUnixAsDuration.js +10 -5
  354. package/dist/unix/calculate/endOfQuarterForUnix.d.ts +10 -2
  355. package/dist/unix/calculate/endOfQuarterForUnix.js +6 -0
  356. package/dist/unix/calculate/endOfUnix.d.ts +11 -2
  357. package/dist/unix/calculate/endOfUnix.js +7 -0
  358. package/dist/unix/calculate/isBetweenUnix.d.ts +3 -2
  359. package/dist/unix/calculate/isBetweenUnix.js +3 -3
  360. package/dist/unix/calculate/roundUnix.d.ts +10 -2
  361. package/dist/unix/calculate/roundUnix.js +13 -6
  362. package/dist/unix/calculate/setUnix.d.ts +25 -5
  363. package/dist/unix/calculate/setUnix.js +33 -12
  364. package/dist/unix/calculate/startOfQuarterForUnix.d.ts +10 -2
  365. package/dist/unix/calculate/startOfQuarterForUnix.js +6 -0
  366. package/dist/unix/calculate/startOfUnix.d.ts +11 -2
  367. package/dist/unix/calculate/startOfUnix.js +7 -0
  368. package/dist/unix/calculate/subtractUnix.d.ts +10 -2
  369. package/dist/unix/calculate/subtractUnix.js +13 -11
  370. package/dist/unix/compare/areUnixEqualBy.d.ts +11 -2
  371. package/dist/unix/compare/areUnixEqualBy.js +7 -0
  372. package/dist/unix/convert/convertUnixToPlainDate.d.ts +5 -2
  373. package/dist/unix/convert/convertUnixToPlainDate.js +5 -4
  374. package/dist/unix/convert/convertUnixToPlainDateTime.d.ts +5 -2
  375. package/dist/unix/convert/convertUnixToPlainDateTime.js +5 -4
  376. package/dist/unix/convert/convertUnixToPlainTime.d.ts +5 -2
  377. package/dist/unix/convert/convertUnixToPlainTime.js +5 -4
  378. package/dist/unix/convert/convertUnixToZoned.d.ts +5 -1
  379. package/dist/unix/convert/convertUnixToZoned.js +5 -1
  380. package/dist/unix/format/formatCalendarUnix.d.ts +6 -2
  381. package/dist/unix/format/formatCalendarUnix.js +6 -1
  382. package/dist/unix/format/formatRelativeUnix.d.ts +11 -3
  383. package/dist/unix/format/formatRelativeUnix.js +13 -5
  384. package/dist/unix/format/formatUnix.d.ts +7 -2
  385. package/dist/unix/format/formatUnix.js +4 -0
  386. package/dist/unix/get/getUnixDay.d.ts +1 -3
  387. package/dist/unix/get/getUnixDay.js +5 -12
  388. package/dist/unix/get/getUnixHour.d.ts +1 -3
  389. package/dist/unix/get/getUnixHour.js +5 -12
  390. package/dist/unix/get/getUnixMicrosecond.d.ts +1 -3
  391. package/dist/unix/get/getUnixMicrosecond.js +4 -11
  392. package/dist/unix/get/getUnixMillisecond.d.ts +1 -3
  393. package/dist/unix/get/getUnixMillisecond.js +5 -12
  394. package/dist/unix/get/getUnixMinute.d.ts +1 -3
  395. package/dist/unix/get/getUnixMinute.js +5 -12
  396. package/dist/unix/get/getUnixMonth.d.ts +1 -3
  397. package/dist/unix/get/getUnixMonth.js +5 -12
  398. package/dist/unix/get/getUnixNanosecond.d.ts +1 -3
  399. package/dist/unix/get/getUnixNanosecond.js +4 -11
  400. package/dist/unix/get/getUnixNowUnit.d.ts +2 -0
  401. package/dist/unix/get/getUnixNowUnit.js +2 -0
  402. package/dist/unix/get/getUnixSecond.d.ts +1 -3
  403. package/dist/unix/get/getUnixSecond.js +5 -12
  404. package/dist/unix/get/getUnixYear.d.ts +3 -3
  405. package/dist/unix/get/getUnixYear.js +5 -12
  406. package/dist/unix/interval/intervalCountUnix.d.ts +11 -2
  407. package/dist/unix/interval/intervalCountUnix.js +7 -0
  408. package/dist/unix/interval/intervalFromDurationUnix.d.ts +10 -2
  409. package/dist/unix/interval/intervalFromDurationUnix.js +12 -7
  410. package/dist/unix/interval/intervalLengthUnix.d.ts +10 -2
  411. package/dist/unix/interval/intervalLengthUnix.js +6 -0
  412. package/dist/unix/interval/intervalOverlappingDaysUnix.d.ts +10 -2
  413. package/dist/unix/interval/intervalOverlappingDaysUnix.js +10 -5
  414. package/dist/unix/interval/splitIntervalByUnitUnix.d.ts +10 -2
  415. package/dist/unix/interval/splitIntervalByUnitUnix.js +12 -6
  416. package/dist/unix/parse/parseDateFromUnix.d.ts +4 -2
  417. package/dist/unix/parse/parseDateFromUnix.js +3 -3
  418. package/dist/unix/parse/parseDayFromUnix.d.ts +4 -2
  419. package/dist/unix/parse/parseDayOfWeekFromUnix.d.ts +4 -2
  420. package/dist/unix/parse/parseDayOfWeekFromUnix.js +2 -2
  421. package/dist/unix/parse/parseHourFromUnix.d.ts +4 -2
  422. package/dist/unix/parse/parseMicrosecondFromUnix.d.ts +4 -2
  423. package/dist/unix/parse/parseMillisecondFromUnix.d.ts +4 -2
  424. package/dist/unix/parse/parseMinuteFromUnix.d.ts +4 -2
  425. package/dist/unix/parse/parseMonthFromUnix.d.ts +4 -2
  426. package/dist/unix/parse/parseNanosecondFromUnix.d.ts +4 -2
  427. package/dist/unix/parse/parseSecondFromUnix.d.ts +4 -2
  428. package/dist/unix/parse/parseTimeFromUnix.d.ts +5 -2
  429. package/dist/unix/parse/parseTimeFromUnix.js +4 -3
  430. package/dist/unix/parse/parseUnitFromUnix.d.ts +9 -3
  431. package/dist/unix/parse/parseUnitFromUnix.js +21 -14
  432. package/dist/unix/parse/parseWeekFromUnix.d.ts +3 -2
  433. package/dist/unix/parse/parseWeekFromUnix.js +4 -4
  434. package/dist/unix/parse/parseYearFromUnix.d.ts +8 -3
  435. package/dist/unix/parse/parseYearFromUnix.js +4 -1
  436. package/dist/unix/validate/isValidUnixUnit.d.ts +1 -1
  437. package/dist/utc/calculate/addUtc.js +4 -7
  438. package/dist/utc/calculate/setUtc.d.ts +16 -3
  439. package/dist/utc/calculate/setUtc.js +22 -8
  440. package/dist/utc/calculate/subtractUtc.js +4 -7
  441. package/dist/utc/convert/convertUtcToPlainDate.d.ts +8 -2
  442. package/dist/utc/convert/convertUtcToPlainDate.js +10 -7
  443. package/dist/utc/convert/convertUtcToPlainDateTime.d.ts +9 -2
  444. package/dist/utc/convert/convertUtcToPlainDateTime.js +12 -13
  445. package/dist/utc/convert/convertUtcToPlainTime.d.ts +5 -2
  446. package/dist/utc/convert/convertUtcToPlainTime.js +7 -6
  447. package/dist/utc/convert/convertUtcToZoned.d.ts +5 -1
  448. package/dist/utc/convert/convertUtcToZoned.js +5 -1
  449. package/dist/utc/format/formatCalendarUtc.d.ts +6 -2
  450. package/dist/utc/format/formatCalendarUtc.js +6 -1
  451. package/dist/utc/format/{formatHttp.d.ts → formatHttpDate.d.ts} +7 -7
  452. package/dist/utc/format/{formatHttp.js → formatHttpDate.js} +7 -7
  453. package/dist/utc/format/formatRelativeUtc.d.ts +11 -3
  454. package/dist/utc/format/formatRelativeUtc.js +13 -5
  455. package/dist/utc/format/formatUtc.d.ts +7 -2
  456. package/dist/utc/format/formatUtc.js +4 -0
  457. package/dist/utc/format/index.d.ts +1 -1
  458. package/dist/utc/format/index.js +1 -1
  459. package/dist/utc/get/getUtcDay.d.ts +1 -3
  460. package/dist/utc/get/getUtcDay.js +5 -12
  461. package/dist/utc/get/getUtcHour.d.ts +1 -3
  462. package/dist/utc/get/getUtcHour.js +5 -12
  463. package/dist/utc/get/getUtcMicrosecond.d.ts +1 -3
  464. package/dist/utc/get/getUtcMicrosecond.js +4 -11
  465. package/dist/utc/get/getUtcMillisecond.d.ts +1 -3
  466. package/dist/utc/get/getUtcMillisecond.js +5 -12
  467. package/dist/utc/get/getUtcMinute.d.ts +1 -3
  468. package/dist/utc/get/getUtcMinute.js +5 -12
  469. package/dist/utc/get/getUtcMonth.d.ts +1 -3
  470. package/dist/utc/get/getUtcMonth.js +5 -12
  471. package/dist/utc/get/getUtcNanosecond.d.ts +1 -3
  472. package/dist/utc/get/getUtcNanosecond.js +4 -11
  473. package/dist/utc/get/getUtcNow.d.ts +1 -3
  474. package/dist/utc/get/getUtcNow.js +2 -9
  475. package/dist/utc/get/getUtcNowUnit.d.ts +2 -0
  476. package/dist/utc/get/getUtcNowUnit.js +2 -0
  477. package/dist/utc/get/getUtcSecond.d.ts +1 -3
  478. package/dist/utc/get/getUtcSecond.js +5 -12
  479. package/dist/utc/get/getUtcYear.d.ts +3 -3
  480. package/dist/utc/get/getUtcYear.js +5 -12
  481. package/dist/utc/interval/intervalXorAllUtc.js +2 -2
  482. package/dist/utc/interval/mergeIntervalsUtc.js +2 -2
  483. package/dist/utc/parse/index.d.ts +1 -1
  484. package/dist/utc/parse/index.js +1 -1
  485. package/dist/utc/parse/parseDateFromUtc.d.ts +4 -2
  486. package/dist/utc/parse/parseDateFromUtc.js +2 -2
  487. package/dist/utc/parse/parseDayFromUtc.d.ts +4 -2
  488. package/dist/utc/parse/parseDayFromUtc.js +2 -2
  489. package/dist/utc/parse/parseDayOfWeekFromUtc.d.ts +4 -2
  490. package/dist/utc/parse/parseDayOfWeekFromUtc.js +4 -4
  491. package/dist/utc/parse/parseHourFromUtc.d.ts +4 -2
  492. package/dist/utc/parse/parseHourFromUtc.js +2 -2
  493. package/dist/utc/parse/{parseHttp.d.ts → parseHttpDate.d.ts} +12 -12
  494. package/dist/utc/parse/{parseHttp.js → parseHttpDate.js} +12 -12
  495. package/dist/utc/parse/parseMicrosecondFromUtc.d.ts +4 -2
  496. package/dist/utc/parse/parseMicrosecondFromUtc.js +2 -2
  497. package/dist/utc/parse/parseMillisecondFromUtc.d.ts +4 -2
  498. package/dist/utc/parse/parseMillisecondFromUtc.js +2 -2
  499. package/dist/utc/parse/parseMinuteFromUtc.d.ts +4 -2
  500. package/dist/utc/parse/parseMinuteFromUtc.js +2 -2
  501. package/dist/utc/parse/parseMonthFromUtc.d.ts +4 -2
  502. package/dist/utc/parse/parseMonthFromUtc.js +2 -2
  503. package/dist/utc/parse/parseNanosecondFromUtc.d.ts +4 -2
  504. package/dist/utc/parse/parseNanosecondFromUtc.js +2 -2
  505. package/dist/utc/parse/parseSecondFromUtc.d.ts +4 -2
  506. package/dist/utc/parse/parseSecondFromUtc.js +2 -2
  507. package/dist/utc/parse/parseTimeFromUtc.d.ts +5 -2
  508. package/dist/utc/parse/parseTimeFromUtc.js +5 -4
  509. package/dist/utc/parse/parseUnitFromUtc.d.ts +10 -3
  510. package/dist/utc/parse/parseUnitFromUtc.js +11 -5
  511. package/dist/utc/parse/parseWeekFromUtc.d.ts +4 -2
  512. package/dist/utc/parse/parseWeekFromUtc.js +4 -4
  513. package/dist/utc/parse/parseYearFromUtc.d.ts +8 -4
  514. package/dist/utc/parse/parseYearFromUtc.js +8 -5
  515. package/dist/utc/validate/index.d.ts +2 -0
  516. package/dist/utc/validate/index.js +2 -0
  517. package/dist/utc/validate/isValidHttpDate.d.ts +35 -0
  518. package/dist/utc/validate/isValidHttpDate.js +38 -0
  519. package/dist/utc/validate/isValidUtc.d.ts +4 -0
  520. package/dist/utc/validate/isValidUtc.js +4 -0
  521. package/dist/utc/validate/isValidUtcTimestamp.d.ts +43 -0
  522. package/dist/utc/validate/isValidUtcTimestamp.js +48 -0
  523. package/dist/zoned/calculate/addZoned.js +4 -7
  524. package/dist/zoned/calculate/setZoned.d.ts +19 -5
  525. package/dist/zoned/calculate/setZoned.js +26 -9
  526. package/dist/zoned/calculate/subtractZoned.js +4 -7
  527. package/dist/zoned/convert/convertPlainDateTimeToZoned.d.ts +4 -1
  528. package/dist/zoned/convert/convertPlainDateTimeToZoned.js +4 -1
  529. package/dist/zoned/convert/convertZonedToZoned.d.ts +5 -1
  530. package/dist/zoned/convert/convertZonedToZoned.js +5 -1
  531. package/dist/zoned/format/formatCalendarZoned.js +2 -1
  532. package/dist/zoned/format/formatRelativeZoned.js +2 -1
  533. package/dist/zoned/format/formatTimeZoneName.d.ts +5 -1
  534. package/dist/zoned/format/formatTimeZoneName.js +5 -1
  535. package/dist/zoned/get/getDstTransitions.d.ts +5 -3
  536. package/dist/zoned/get/getDstTransitions.js +12 -7
  537. package/dist/zoned/get/getSystemTimeZone.d.ts +3 -1
  538. package/dist/zoned/get/getSystemTimeZone.js +5 -2
  539. package/dist/zoned/get/getTimeZoneOffset.d.ts +10 -2
  540. package/dist/zoned/get/getTimeZoneOffset.js +18 -5
  541. package/dist/zoned/get/getZonedDay.d.ts +2 -1
  542. package/dist/zoned/get/getZonedDay.js +6 -7
  543. package/dist/zoned/get/getZonedDayOfWeek.d.ts +2 -1
  544. package/dist/zoned/get/getZonedDayOfWeek.js +6 -5
  545. package/dist/zoned/get/getZonedHour.d.ts +2 -1
  546. package/dist/zoned/get/getZonedHour.js +6 -7
  547. package/dist/zoned/get/getZonedMicrosecond.d.ts +2 -1
  548. package/dist/zoned/get/getZonedMicrosecond.js +6 -5
  549. package/dist/zoned/get/getZonedMillisecond.d.ts +2 -1
  550. package/dist/zoned/get/getZonedMillisecond.js +6 -7
  551. package/dist/zoned/get/getZonedMinute.d.ts +2 -1
  552. package/dist/zoned/get/getZonedMinute.js +6 -7
  553. package/dist/zoned/get/getZonedMonth.d.ts +2 -1
  554. package/dist/zoned/get/getZonedMonth.js +6 -7
  555. package/dist/zoned/get/getZonedNanosecond.d.ts +2 -1
  556. package/dist/zoned/get/getZonedNanosecond.js +6 -5
  557. package/dist/zoned/get/getZonedNow.d.ts +5 -1
  558. package/dist/zoned/get/getZonedNow.js +5 -1
  559. package/dist/zoned/get/getZonedNowUnit.d.ts +6 -3
  560. package/dist/zoned/get/getZonedNowUnit.js +10 -7
  561. package/dist/zoned/get/getZonedSecond.d.ts +2 -1
  562. package/dist/zoned/get/getZonedSecond.js +6 -7
  563. package/dist/zoned/get/getZonedToday.d.ts +2 -1
  564. package/dist/zoned/get/getZonedToday.js +6 -5
  565. package/dist/zoned/get/getZonedWeekOfYear.d.ts +2 -1
  566. package/dist/zoned/get/getZonedWeekOfYear.js +6 -5
  567. package/dist/zoned/get/getZonedYear.d.ts +4 -1
  568. package/dist/zoned/get/getZonedYear.js +9 -7
  569. package/dist/zoned/interval/intervalXorAllZoned.js +2 -2
  570. package/dist/zoned/interval/mergeIntervalsZoned.js +2 -2
  571. package/dist/zoned/parse/parseUnitFromZoned.d.ts +4 -1
  572. package/dist/zoned/parse/parseUnitFromZoned.js +5 -1
  573. package/dist/zoned/parse/parseYearFromZoned.d.ts +4 -2
  574. package/dist/zoned/parse/parseYearFromZoned.js +6 -3
  575. package/dist/zoned/validate/hasDaylightSaving.d.ts +4 -2
  576. package/dist/zoned/validate/hasDaylightSaving.js +13 -7
  577. package/dist/zoned/validate/index.d.ts +2 -0
  578. package/dist/zoned/validate/index.js +2 -0
  579. package/dist/zoned/validate/isValidRfc2822DateTime.d.ts +32 -0
  580. package/dist/zoned/validate/isValidRfc2822DateTime.js +35 -0
  581. package/dist/zoned/validate/isValidRfc3339DateTime.d.ts +31 -0
  582. package/dist/zoned/validate/isValidRfc3339DateTime.js +34 -0
  583. package/dist/zoned/validate/isValidTimeZone.d.ts +5 -1
  584. package/dist/zoned/validate/isValidTimeZone.js +6 -2
  585. package/package.json +50 -1
  586. package/skills/gmt-arithmetic/SKILL.md +99 -12
  587. package/skills/gmt-basics/SKILL.md +57 -15
  588. package/skills/gmt-integration/SKILL.md +24 -9
  589. package/skills/gmt-timezone/SKILL.md +134 -29
  590. package/dist/internal/unixZonedDateTime.d.ts +0 -22
  591. package/dist/internal/unixZonedDateTime.js +0 -32
  592. package/dist/internal/utcZonedDateTime.d.ts +0 -19
  593. package/dist/internal/utcZonedDateTime.js +0 -31
@@ -0,0 +1,34 @@
1
+ import { parseDutyLog } from "../../internal/dutyLog.js";
2
+ /**
3
+ * Validate whether a value is a duty log every `duty/` function accepts.
4
+ *
5
+ * - True for an array of `{ status, start, end }` entries where `status` is a string and `start`
6
+ * and `end` are ISO 8601 instant strings (offset required, no leap second), `end` after `start`.
7
+ * - Entries must be ordered by `start` and must not overlap. One may start exactly where the
8
+ * previous one ends, since entries are half-open, or later, leaving a gap. Order is by instant,
9
+ * not text.
10
+ * - `[]` is a valid, empty log. Extra keys on an entry are ignored.
11
+ * - Every other `duty/` function returns its sentinel for a log this rejects.
12
+ * - Returns `false` for a non-array, an entry that is not an object, a non-string status, a bound
13
+ * that is not an instant, a zero-length or inverted entry, and entries out of order or
14
+ * overlapping.
15
+ *
16
+ * @param log candidate array of `{ status, start, end }` records
17
+ * @returns boolean indicating whether the log is valid
18
+ *
19
+ * @example isValidDutyLog([{ status: "off", start: "2024-01-01T00:00:00Z", end: "2024-01-01T10:00:00Z" }, { status: "driving", start: "2024-01-01T10:00:00Z", end: "2024-01-01T15:00:00Z" }]) // true
20
+ * @example isValidDutyLog([]) // true — an empty log
21
+ * @example isValidDutyLog([{ status: "on", start: "2024-01-01T02:00:00Z", end: "2024-01-01T01:00:00Z" }]) // false — inverted
22
+ * @example isValidDutyLog([{ status: "on", start: "2024-01-01T00:00:00Z", end: "2024-01-01T02:00:00Z" }, { status: "off", start: "2024-01-01T01:59:59Z", end: "2024-01-01T03:00:00Z" }]) // false — overlapping
23
+ * @example isValidDutyLog([{ status: "on", start: "2024-01-01T00:00:00", end: "2024-01-01T01:00:00Z" }]) // false — no offset
24
+ */
25
+ export function isValidDutyLog(log) {
26
+ try {
27
+ return parseDutyLog(log) !== null;
28
+ }
29
+ catch {
30
+ // Never throws (Core Rule 3): a hostile
31
+ // argument is invalid input, not an exception.
32
+ return false;
33
+ }
34
+ }
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export * from "@js-temporal/polyfill";
2
2
  export * from "./calendar/index.js";
3
3
  export * from "./duration/index.js";
4
+ export * from "./duty/index.js";
4
5
  export * from "./instant/index.js";
5
6
  export * from "./intermodal/index.js";
6
7
  export * from "./interval/index.js";
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  export * from "@js-temporal/polyfill";
2
2
  export * from "./calendar/index.js";
3
3
  export * from "./duration/index.js";
4
+ export * from "./duty/index.js";
4
5
  export * from "./instant/index.js";
5
6
  export * from "./intermodal/index.js";
6
7
  export * from "./interval/index.js";
@@ -32,9 +32,12 @@ export type LocalTimeClassification = "unique" | "ambiguous" | "nonexistent";
32
32
  * annotations are read as `Temporal.PlainDateTime.from` reads them, so a time zone annotation
33
33
  * is ignored and `timeZone` alone is the zone.
34
34
  * - Returns null on invalid input — never `"unique"`, which would read as a verdict.
35
+ * - `timeZone` may be a UTC offset, including one `getTimeZoneOffset` returned with seconds. A
36
+ * fixed offset names one instant for every wall time, so the classification is always `"unique"`.
35
37
  *
36
38
  * @param localDateTime zoneless ISO 8601 local datetime string (e.g. "2024-11-03T01:30:00")
37
- * @param timeZone IANA name or UTC offset the wall time is read in
39
+ * @param timeZone IANA name or UTC offset the wall time is read in: a time zone identifier
40
+ * (`+05:30`, `+0530`, `-08`) or a stored offset (`±HH:MM[:SS]`, what `getTimeZoneOffset` returns)
38
41
  * @returns "unique" | "ambiguous" | "nonexistent", or null on invalid input
39
42
  *
40
43
  * @example classifyLocal("2024-07-15T12:00:00", "America/New_York") // "unique"
@@ -44,6 +47,7 @@ export type LocalTimeClassification = "unique" | "ambiguous" | "nonexistent";
44
47
  * @example classifyLocal("2024-09-29T03:15:00", "Pacific/Chatham") // "nonexistent" (a 45-minute-offset zone's gap)
45
48
  * @example classifyLocal("2011-12-30T12:00:00", "Pacific/Apia") // "nonexistent" (the day Samoa skipped crossing the date line)
46
49
  * @example classifyLocal("2024-11-03T01:30:00", "UTC") // "unique" (UTC has no transitions)
50
+ * @example classifyLocal("1970-01-01T12:00:00", "-00:44:30") // "unique" (a fixed offset has no transitions)
47
51
  * @example classifyLocal("2024-11-03T01:30:00-04:00", "America/New_York") // null (not a zoneless wall time)
48
52
  * @example classifyLocal("2024-11-03T01:30:00", "Invalid/Zone") // null
49
53
  */
@@ -1,7 +1,6 @@
1
1
  import { Temporal } from "@js-temporal/polyfill";
2
2
  import { isValidDateTime } from "../../plain/validate/index.js";
3
- import { isValidTimeZone } from "../../zoned/validate/index.js";
4
- import { plainToZoned } from "../../internal/index.js";
3
+ import { instantOfWallClock, isoStringBody, plainToZoned, zoneFrame, } from "../../internal/index.js";
5
4
  /**
6
5
  * Report whether a zoneless local wall time is unique, ambiguous or nonexistent in a zone —
7
6
  * before any policy resolves it.
@@ -20,9 +19,12 @@ import { plainToZoned } from "../../internal/index.js";
20
19
  * annotations are read as `Temporal.PlainDateTime.from` reads them, so a time zone annotation
21
20
  * is ignored and `timeZone` alone is the zone.
22
21
  * - Returns null on invalid input — never `"unique"`, which would read as a verdict.
22
+ * - `timeZone` may be a UTC offset, including one `getTimeZoneOffset` returned with seconds. A
23
+ * fixed offset names one instant for every wall time, so the classification is always `"unique"`.
23
24
  *
24
25
  * @param localDateTime zoneless ISO 8601 local datetime string (e.g. "2024-11-03T01:30:00")
25
- * @param timeZone IANA name or UTC offset the wall time is read in
26
+ * @param timeZone IANA name or UTC offset the wall time is read in: a time zone identifier
27
+ * (`+05:30`, `+0530`, `-08`) or a stored offset (`±HH:MM[:SS]`, what `getTimeZoneOffset` returns)
26
28
  * @returns "unique" | "ambiguous" | "nonexistent", or null on invalid input
27
29
  *
28
30
  * @example classifyLocal("2024-07-15T12:00:00", "America/New_York") // "unique"
@@ -32,17 +34,25 @@ import { plainToZoned } from "../../internal/index.js";
32
34
  * @example classifyLocal("2024-09-29T03:15:00", "Pacific/Chatham") // "nonexistent" (a 45-minute-offset zone's gap)
33
35
  * @example classifyLocal("2011-12-30T12:00:00", "Pacific/Apia") // "nonexistent" (the day Samoa skipped crossing the date line)
34
36
  * @example classifyLocal("2024-11-03T01:30:00", "UTC") // "unique" (UTC has no transitions)
37
+ * @example classifyLocal("1970-01-01T12:00:00", "-00:44:30") // "unique" (a fixed offset has no transitions)
35
38
  * @example classifyLocal("2024-11-03T01:30:00-04:00", "America/New_York") // null (not a zoneless wall time)
36
39
  * @example classifyLocal("2024-11-03T01:30:00", "Invalid/Zone") // null
37
40
  */
38
41
  export function classifyLocal(localDateTime, timeZone) {
39
- if (!isValidDateTime(localDateTime) || !isValidTimeZone(timeZone)) {
42
+ const frame = zoneFrame(timeZone);
43
+ if (!isValidDateTime(localDateTime) || frame === null) {
40
44
  return null;
41
45
  }
42
46
  try {
47
+ // A fixed offset has no transition: a wall time it can place is one instant, and one it
48
+ // cannot (past the instant range) throws.
49
+ if (frame.shiftNanoseconds !== 0n) {
50
+ instantOfWallClock(isoStringBody(localDateTime), frame);
51
+ return "unique";
52
+ }
43
53
  const wallClock = Temporal.PlainDateTime.from(localDateTime);
44
- const earliest = plainToZoned(wallClock, timeZone, "earlier");
45
- const latest = plainToZoned(wallClock, timeZone, "later");
54
+ const earliest = plainToZoned(wallClock, frame.timeZone, "earlier");
55
+ const latest = plainToZoned(wallClock, frame.timeZone, "later");
46
56
  if (earliest.epochNanoseconds === latest.epochNanoseconds) {
47
57
  return "unique";
48
58
  }
@@ -29,6 +29,10 @@ import type { OffsetInstant } from "./toOffsetInstant.js";
29
29
  * string whose local date is −271821-04-19 is refused by `toOffsetInstant`. Without a `timeZone` there is no zone to resolve against, so the
30
30
  * full `±HH:MM:SS` is written instead; that is ISO 8601, not RFC 9557.
31
31
  * - Returns `""` on invalid input.
32
+ * - A `timeZone` that is an offset with seconds (`-00:44:30`) returns `""`, as any offset there
33
+ * does. A written zone cannot carry seconds (RFC 9557 §4.1), so the result could not name it.
34
+ * Pass the IANA name as `timeZone`, or leave `timeZone` out for the local time with its full
35
+ * offset and no bracket.
32
36
  *
33
37
  * @param value `{ instant, offset, timeZone? }` pair, as produced by `toOffsetInstant`
34
38
  * @returns local ISO 8601 string carrying the pair's own offset, or "" on invalid input
@@ -1,6 +1,7 @@
1
1
  import { Temporal } from "@js-temporal/polyfill";
2
2
  import { formatUtcOffset, parseInstantNanoseconds, parseUtcOffsetNanoseconds, wallClockAtOffset, } from "../../internal/index.js";
3
3
  import { utcOffset } from "../../regex/index.js";
4
+ import { isObject } from "../../internal/isObject.js";
4
5
  /**
5
6
  * Render an instant-plus-offset pair back to the local time it describes.
6
7
  *
@@ -31,6 +32,10 @@ import { utcOffset } from "../../regex/index.js";
31
32
  * string whose local date is −271821-04-19 is refused by `toOffsetInstant`. Without a `timeZone` there is no zone to resolve against, so the
32
33
  * full `±HH:MM:SS` is written instead; that is ISO 8601, not RFC 9557.
33
34
  * - Returns `""` on invalid input.
35
+ * - A `timeZone` that is an offset with seconds (`-00:44:30`) returns `""`, as any offset there
36
+ * does. A written zone cannot carry seconds (RFC 9557 §4.1), so the result could not name it.
37
+ * Pass the IANA name as `timeZone`, or leave `timeZone` out for the local time with its full
38
+ * offset and no bracket.
34
39
  *
35
40
  * @param value `{ instant, offset, timeZone? }` pair, as produced by `toOffsetInstant`
36
41
  * @returns local ISO 8601 string carrying the pair's own offset, or "" on invalid input
@@ -50,7 +55,7 @@ import { utcOffset } from "../../regex/index.js";
50
55
  */
51
56
  export function fromOffsetInstant(value) {
52
57
  try {
53
- if (typeof value !== "object" || value === null) {
58
+ if (!isObject(value)) {
54
59
  return "";
55
60
  }
56
61
  const epochNanoseconds = parseInstantNanoseconds(value.instant);
@@ -1,6 +1,6 @@
1
1
  import type { Disambiguation } from "../../types/index.js";
2
2
  /**
3
- * Resolve a zoneless local wall time against an IANA zone and return the instant it names.
3
+ * Resolve a zoneless local wall time in a time zone and return the instant it names.
4
4
  *
5
5
  * Feeds deliver wall times with no offset all the time — "gate-out 08:00" — and turning one
6
6
  * into an instant takes a zone the sender did not send plus a policy for the two days a year
@@ -16,9 +16,13 @@ import type { Disambiguation } from "../../types/index.js";
16
16
  * are read as `Temporal.PlainDateTime.from` reads them, so a time zone annotation
17
17
  * (`[America/New_York]`) is ignored and `timeZone` alone resolves the wall time.
18
18
  * - Returns `""` on invalid input.
19
+ * - `timeZone` may be a UTC offset, including one `getTimeZoneOffset` returned with seconds. A
20
+ * fixed offset names one instant for every wall time, so `disambiguation` has nothing to decide
21
+ * and `"reject"` does not reject.
19
22
  *
20
23
  * @param localDateTime zoneless ISO 8601 local datetime string (e.g. "2024-11-03T01:30:00")
21
- * @param timeZone IANA name or UTC offset the wall time is read in
24
+ * @param timeZone IANA name or UTC offset the wall time is read in: a time zone identifier
25
+ * (`+05:30`, `+0530`, `-08`) or a stored offset (`±HH:MM[:SS]`, what `getTimeZoneOffset` returns)
22
26
  * @param optionsArg How an ambiguous or nonexistent wall time is resolved
23
27
  * @returns UTC instant string ending in "Z", or "" on invalid input
24
28
  *
@@ -29,6 +33,7 @@ import type { Disambiguation } from "../../types/index.js";
29
33
  * @example resolveLocal("2024-03-10T02:30:00", "America/New_York") // "2024-03-10T07:30:00Z" (nonexistent; "compatible" takes the later)
30
34
  * @example resolveLocal("2024-03-10T02:30:00", "America/New_York", { disambiguation: "earlier" }) // "2024-03-10T06:30:00Z"
31
35
  * @example resolveLocal("2024-07-15T12:00:00-04:00", "America/New_York") // "" (not a zoneless wall time)
36
+ * @example resolveLocal("1970-01-01T12:00:00", "-00:44:30") // "1970-01-01T12:44:30Z" (a stored offset with seconds, what `getTimeZoneOffset` returns for Africa/Monrovia then)
32
37
  * @example resolveLocal("2024-07-15T12:00:00[foo=bar]", "America/New_York") // "2024-07-15T16:00:00Z" (elective annotation ignored)
33
38
  * @example resolveLocal("2024-07-15T12:00:00", "Invalid/Zone") // ""
34
39
  */
@@ -1,6 +1,5 @@
1
1
  import { isValidDateTime } from "../../plain/validate/index.js";
2
- import { isValidTimeZone } from "../../zoned/validate/index.js";
3
- import { isoStringBody, zonedDateTimeFrom } from "../../internal/index.js";
2
+ import { instantOfWallClock, isoStringBody, zonedDateTimeFrom, zoneFrame, } from "../../internal/index.js";
4
3
  import { isOptionsArgument } from "../../internal/isObject.js";
5
4
  import { optionOrDefault } from "../../internal/optionOrDefault.js";
6
5
  const DISAMBIGUATIONS = [
@@ -10,7 +9,7 @@ const DISAMBIGUATIONS = [
10
9
  "reject",
11
10
  ];
12
11
  /**
13
- * Resolve a zoneless local wall time against an IANA zone and return the instant it names.
12
+ * Resolve a zoneless local wall time in a time zone and return the instant it names.
14
13
  *
15
14
  * Feeds deliver wall times with no offset all the time — "gate-out 08:00" — and turning one
16
15
  * into an instant takes a zone the sender did not send plus a policy for the two days a year
@@ -26,9 +25,13 @@ const DISAMBIGUATIONS = [
26
25
  * are read as `Temporal.PlainDateTime.from` reads them, so a time zone annotation
27
26
  * (`[America/New_York]`) is ignored and `timeZone` alone resolves the wall time.
28
27
  * - Returns `""` on invalid input.
28
+ * - `timeZone` may be a UTC offset, including one `getTimeZoneOffset` returned with seconds. A
29
+ * fixed offset names one instant for every wall time, so `disambiguation` has nothing to decide
30
+ * and `"reject"` does not reject.
29
31
  *
30
32
  * @param localDateTime zoneless ISO 8601 local datetime string (e.g. "2024-11-03T01:30:00")
31
- * @param timeZone IANA name or UTC offset the wall time is read in
33
+ * @param timeZone IANA name or UTC offset the wall time is read in: a time zone identifier
34
+ * (`+05:30`, `+0530`, `-08`) or a stored offset (`±HH:MM[:SS]`, what `getTimeZoneOffset` returns)
32
35
  * @param optionsArg How an ambiguous or nonexistent wall time is resolved
33
36
  * @returns UTC instant string ending in "Z", or "" on invalid input
34
37
  *
@@ -39,6 +42,7 @@ const DISAMBIGUATIONS = [
39
42
  * @example resolveLocal("2024-03-10T02:30:00", "America/New_York") // "2024-03-10T07:30:00Z" (nonexistent; "compatible" takes the later)
40
43
  * @example resolveLocal("2024-03-10T02:30:00", "America/New_York", { disambiguation: "earlier" }) // "2024-03-10T06:30:00Z"
41
44
  * @example resolveLocal("2024-07-15T12:00:00-04:00", "America/New_York") // "" (not a zoneless wall time)
45
+ * @example resolveLocal("1970-01-01T12:00:00", "-00:44:30") // "1970-01-01T12:44:30Z" (a stored offset with seconds, what `getTimeZoneOffset` returns for Africa/Monrovia then)
42
46
  * @example resolveLocal("2024-07-15T12:00:00[foo=bar]", "America/New_York") // "2024-07-15T16:00:00Z" (elective annotation ignored)
43
47
  * @example resolveLocal("2024-07-15T12:00:00", "Invalid/Zone") // ""
44
48
  */
@@ -48,15 +52,19 @@ export function resolveLocal(localDateTime, timeZone, optionsArg) {
48
52
  return "";
49
53
  }
50
54
  const disambiguation = optionOrDefault(optionsArg?.disambiguation, "compatible");
55
+ const frame = zoneFrame(timeZone);
51
56
  if (!isValidDateTime(localDateTime) ||
52
- !isValidTimeZone(timeZone) ||
57
+ frame === null ||
53
58
  !DISAMBIGUATIONS.includes(disambiguation)) {
54
59
  return "";
55
60
  }
56
61
  try {
57
- return zonedDateTimeFrom(`${isoStringBody(localDateTime)}[${timeZone}]`, {
58
- disambiguation,
59
- })
62
+ // An offset with seconds is no time zone identifier, so it cannot go in a bracket. It needs
63
+ // none: the wall time at a fixed offset is one instant, whatever `disambiguation` says.
64
+ if (frame.shiftNanoseconds !== 0n) {
65
+ return instantOfWallClock(isoStringBody(localDateTime), frame).toString();
66
+ }
67
+ return zonedDateTimeFrom(`${isoStringBody(localDateTime)}[${frame.timeZone}]`, { disambiguation })
60
68
  .toInstant()
61
69
  .toString();
62
70
  }
@@ -3,7 +3,8 @@
3
3
  *
4
4
  * Neither `instant` nor `offset` derives from the other, which is why both are stored. It is
5
5
  * the shape GS1 EPCIS 2.0 (`eventTime` + a required `eventTimeZoneOffset`), UN/EDIFACT DTM
6
- * (qualifier `303`/`304`) and DICOM (`DT` + `&ZZXX`) all exchange.
6
+ * (format codes `205` and `208`, a date and time with a `±HHMM` offset) and DICOM (`DT` +
7
+ * `&ZZXX`) all exchange.
7
8
  *
8
9
  * @example
9
10
  * import { OffsetInstant } from "@northguild/gmt/instant";
@@ -52,12 +53,13 @@ export interface OffsetInstant {
52
53
  * event happened when all it has is the offset it already stores. Every other bracketed
53
54
  * identifier Temporal accepts is kept, including the single-component IANA names (`EST5EDT`,
54
55
  * `Zulu`), in its IANA casing.
55
- * - `timeZone` names the zone the offset is read in, and is how a UTC-only feed gets a pair
56
- * with a local offset. It also overrides a zone bracketed in the string — the instant is
57
- * unchanged either way, only the local rendering differs. It is validated with
58
- * `isValidTimeZone`, so any IANA Zone or Link name is accepted, single-component ones
59
- * (`Japan`, `Zulu`, `EST5EDT`) included. An offset identifier (`"-05:00"`) sets the offset
60
- * and, like a bracketed offset zone, yields no `timeZone` field.
56
+ * - `timeZone` names the zone the offset is read in, and is how a UTC-only feed gets a pair with a
57
+ * local offset. It also overrides a zone bracketed in the string — the instant is unchanged
58
+ * either way, only the local rendering differs. Any IANA Zone or Link name is accepted,
59
+ * single-component ones (`Japan`, `Zulu`, `EST5EDT`) included, and so is a UTC offset: a time
60
+ * zone identifier (`+05:30`, `+0530`, `-08`) or a stored offset (`±HH:MM[:SS]`, what
61
+ * `getTimeZoneOffset` returns). An offset (`"-05:00"`, `"-00:44:30"`) sets the pair's offset and,
62
+ * like a bracketed offset zone, yields no `timeZone` field.
61
63
  * - The returned `timeZone` is the identifier in its IANA casing on every path —
62
64
  * `"america/new_york"` comes back as `"America/New_York"` — because identifiers match
63
65
  * case-insensitively (ECMA-402). That is what the bracket path and `fromOffsetInstant` return,
@@ -82,7 +84,8 @@ export interface OffsetInstant {
82
84
  * - Returns null on invalid input, not a zero-offset pair — `+00:00` is a real offset.
83
85
  *
84
86
  * @param value ISO 8601 instant string, with an offset designator and optionally a bracketed zone
85
- * @param timeZone optional IANA name or UTC offset to read the offset in
87
+ * @param timeZone optional IANA name or UTC offset to read the offset in: a time zone identifier
88
+ * (`+05:30`, `+0530`, `-08`) or a stored offset (`±HH:MM[:SS]`, what `getTimeZoneOffset` returns)
86
89
  * @returns `{ instant, offset, timeZone? }`, or null on invalid input
87
90
  *
88
91
  * @example toOffsetInstant("2024-07-15T12:00:00-04:00[America/New_York]") // { instant: "2024-07-15T16:00:00Z", offset: "-04:00", timeZone: "America/New_York" }
@@ -91,6 +94,7 @@ export interface OffsetInstant {
91
94
  * @example toOffsetInstant("2024-07-15T16:00:00Z", "America/New_York") // { instant: "2024-07-15T16:00:00Z", offset: "-04:00", timeZone: "America/New_York" }
92
95
  * @example toOffsetInstant("2024-01-15T17:00:00Z", "America/New_York") // { instant: "2024-01-15T17:00:00Z", offset: "-05:00", timeZone: "America/New_York" } — same wall time, different offset, six months apart
93
96
  * @example toOffsetInstant("1970-01-01T00:00:00Z", "Africa/Monrovia") // { instant: "1970-01-01T00:00:00Z", offset: "-00:44:30", timeZone: "Africa/Monrovia" }
97
+ * @example toOffsetInstant("1970-01-01T12:44:30Z", "-00:44:30") // { instant: "1970-01-01T12:44:30Z", offset: "-00:44:30" } — a stored offset with seconds, and no timeZone field
94
98
  * @example toOffsetInstant("1969-12-31T23:15:30-00:45[Africa/Monrovia]") // { instant: "1970-01-01T00:00:00Z", offset: "-00:44:30", timeZone: "Africa/Monrovia" } — the zone, not the rounded offset, fixes the instant
95
99
  * @example toOffsetInstant("2024-07-15T12:00:00-04:00[-04:00]") // { instant: "2024-07-15T16:00:00Z", offset: "-04:00" } — a bracketed offset is not a zone, so no timeZone field
96
100
  * @example toOffsetInstant("2024-07-15T12:00:00-05:00[America/New_York]") // null (offset contradicts the bracketed zone)
@@ -1,7 +1,6 @@
1
1
  import { Temporal } from "@js-temporal/polyfill";
2
- import { formatUtcOffset, isoStringBody, parseInstantNanoseconds, TIME_ZONE_ANNOTATION, zonedDateTimeFrom, } from "../../internal/index.js";
2
+ import { formatUtcOffset, frameOffset, isoStringBody, parseInstantNanoseconds, TIME_ZONE_ANNOTATION, zonedDateTimeFrom, zoneFrame, } from "../../internal/index.js";
3
3
  import { utcOffset } from "../../regex/index.js";
4
- import { isValidTimeZone } from "../../zoned/validate/index.js";
5
4
  /** A leading RFC 9557 time zone annotation: `[zone]` or `[!zone]`, with no `=`. */
6
5
  const timeZoneAnnotation = new RegExp(`^${TIME_ZONE_ANNOTATION}`);
7
6
  /**
@@ -24,12 +23,13 @@ const timeZoneAnnotation = new RegExp(`^${TIME_ZONE_ANNOTATION}`);
24
23
  * event happened when all it has is the offset it already stores. Every other bracketed
25
24
  * identifier Temporal accepts is kept, including the single-component IANA names (`EST5EDT`,
26
25
  * `Zulu`), in its IANA casing.
27
- * - `timeZone` names the zone the offset is read in, and is how a UTC-only feed gets a pair
28
- * with a local offset. It also overrides a zone bracketed in the string — the instant is
29
- * unchanged either way, only the local rendering differs. It is validated with
30
- * `isValidTimeZone`, so any IANA Zone or Link name is accepted, single-component ones
31
- * (`Japan`, `Zulu`, `EST5EDT`) included. An offset identifier (`"-05:00"`) sets the offset
32
- * and, like a bracketed offset zone, yields no `timeZone` field.
26
+ * - `timeZone` names the zone the offset is read in, and is how a UTC-only feed gets a pair with a
27
+ * local offset. It also overrides a zone bracketed in the string — the instant is unchanged
28
+ * either way, only the local rendering differs. Any IANA Zone or Link name is accepted,
29
+ * single-component ones (`Japan`, `Zulu`, `EST5EDT`) included, and so is a UTC offset: a time
30
+ * zone identifier (`+05:30`, `+0530`, `-08`) or a stored offset (`±HH:MM[:SS]`, what
31
+ * `getTimeZoneOffset` returns). An offset (`"-05:00"`, `"-00:44:30"`) sets the pair's offset and,
32
+ * like a bracketed offset zone, yields no `timeZone` field.
33
33
  * - The returned `timeZone` is the identifier in its IANA casing on every path —
34
34
  * `"america/new_york"` comes back as `"America/New_York"` — because identifiers match
35
35
  * case-insensitively (ECMA-402). That is what the bracket path and `fromOffsetInstant` return,
@@ -54,7 +54,8 @@ const timeZoneAnnotation = new RegExp(`^${TIME_ZONE_ANNOTATION}`);
54
54
  * - Returns null on invalid input, not a zero-offset pair — `+00:00` is a real offset.
55
55
  *
56
56
  * @param value ISO 8601 instant string, with an offset designator and optionally a bracketed zone
57
- * @param timeZone optional IANA name or UTC offset to read the offset in
57
+ * @param timeZone optional IANA name or UTC offset to read the offset in: a time zone identifier
58
+ * (`+05:30`, `+0530`, `-08`) or a stored offset (`±HH:MM[:SS]`, what `getTimeZoneOffset` returns)
58
59
  * @returns `{ instant, offset, timeZone? }`, or null on invalid input
59
60
  *
60
61
  * @example toOffsetInstant("2024-07-15T12:00:00-04:00[America/New_York]") // { instant: "2024-07-15T16:00:00Z", offset: "-04:00", timeZone: "America/New_York" }
@@ -63,6 +64,7 @@ const timeZoneAnnotation = new RegExp(`^${TIME_ZONE_ANNOTATION}`);
63
64
  * @example toOffsetInstant("2024-07-15T16:00:00Z", "America/New_York") // { instant: "2024-07-15T16:00:00Z", offset: "-04:00", timeZone: "America/New_York" }
64
65
  * @example toOffsetInstant("2024-01-15T17:00:00Z", "America/New_York") // { instant: "2024-01-15T17:00:00Z", offset: "-05:00", timeZone: "America/New_York" } — same wall time, different offset, six months apart
65
66
  * @example toOffsetInstant("1970-01-01T00:00:00Z", "Africa/Monrovia") // { instant: "1970-01-01T00:00:00Z", offset: "-00:44:30", timeZone: "Africa/Monrovia" }
67
+ * @example toOffsetInstant("1970-01-01T12:44:30Z", "-00:44:30") // { instant: "1970-01-01T12:44:30Z", offset: "-00:44:30" } — a stored offset with seconds, and no timeZone field
66
68
  * @example toOffsetInstant("1969-12-31T23:15:30-00:45[Africa/Monrovia]") // { instant: "1970-01-01T00:00:00Z", offset: "-00:44:30", timeZone: "Africa/Monrovia" } — the zone, not the rounded offset, fixes the instant
67
69
  * @example toOffsetInstant("2024-07-15T12:00:00-04:00[-04:00]") // { instant: "2024-07-15T16:00:00Z", offset: "-04:00" } — a bracketed offset is not a zone, so no timeZone field
68
70
  * @example toOffsetInstant("2024-07-15T12:00:00-05:00[America/New_York]") // null (offset contradicts the bracketed zone)
@@ -83,7 +85,8 @@ export function toOffsetInstant(value, timeZone) {
83
85
  if (epochNanoseconds === null) {
84
86
  return null;
85
87
  }
86
- if (timeZone !== undefined && !isValidTimeZone(timeZone)) {
88
+ const frame = timeZone === undefined ? undefined : zoneFrame(timeZone);
89
+ if (frame === null) {
87
90
  return null;
88
91
  }
89
92
  try {
@@ -116,7 +119,12 @@ export function toOffsetInstant(value, timeZone) {
116
119
  const instant = bracketed !== null
117
120
  ? bracketed.toInstant()
118
121
  : Temporal.Instant.fromEpochNanoseconds(epochNanoseconds);
119
- const resolvedZone = timeZone ?? bracketedZone;
122
+ // A stored offset with seconds is the pair's offset as it stands. Like an offset identifier it
123
+ // names no place, so it fills no `timeZone` field.
124
+ if (frame !== undefined && frame.shiftNanoseconds !== 0n) {
125
+ return { instant: instant.toString(), offset: frameOffset(frame) };
126
+ }
127
+ const resolvedZone = frame?.timeZone ?? bracketedZone;
120
128
  if (resolvedZone !== undefined) {
121
129
  return offsetInstantInZone(instant, resolvedZone);
122
130
  }
@@ -1,2 +1,3 @@
1
1
  export * from "@js-temporal/polyfill";
2
2
  export * from "./convert/index.js";
3
+ export * from "./validate/index.js";
@@ -1,3 +1,4 @@
1
1
  // Re-export the Temporal polyfill (`Temporal`, `Intl`, `toTemporalInstant`) so every namespace subpath offers it
2
2
  export * from "@js-temporal/polyfill";
3
3
  export * from "./convert/index.js";
4
+ export * from "./validate/index.js";
@@ -0,0 +1 @@
1
+ export * from "./isValidUtcOffset.js";
@@ -0,0 +1 @@
1
+ export * from "./isValidUtcOffset.js";
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Return true when `value` is a UTC offset in the form the offset-instant pair stores: ISO 8601
3
+ * extended `±HH:MM`, optionally `±HH:MM:SS`.
4
+ *
5
+ * - This is the offset `toOffsetInstant` returns and `fromOffsetInstant` takes, and the one
6
+ * `getTimeZoneOffset` and `getZonedOffset` return.
7
+ * - **The `utcOffset` pattern is the whole check.** Every string it matches is in range (hour
8
+ * `00`–`23`, minute and second `00`–`59`), so this validator is the pattern test plus the
9
+ * answer false for a non-string.
10
+ * - `Z` is false: it is a designator meaning "this string is already UTC", and for an event at
11
+ * UTC the pair's offset is `+00:00`.
12
+ * - Seconds are allowed because some zones did not run on a whole minute: `Africa/Monrovia` was
13
+ * `-00:44:30` until 1972. A fraction of a second is false.
14
+ * - Basic format (`-0400`) and an hour alone (`-04`) are false.
15
+ * - `-00:00` is true, and the functions that take an offset read it as `+00:00`.
16
+ * - A function whose result has no zone in it takes this offset in its time zone position too. A
17
+ * function that returns a zoned string, or formats with `Intl`, takes a time zone identifier
18
+ * only: check that with `isValidTimeZone`, which accepts `+0530` and `-08` and rejects an offset
19
+ * with seconds.
20
+ *
21
+ * @param value candidate UTC offset string
22
+ * @returns boolean indicating validity
23
+ *
24
+ * @example isValidUtcOffset("-04:00") // true
25
+ * @example isValidUtcOffset("+05:45") // true
26
+ * @example isValidUtcOffset("-00:44:30") // true (Africa/Monrovia before 1972)
27
+ * @example isValidUtcOffset("Z") // false (a designator, not an offset)
28
+ * @example isValidUtcOffset("-0400") // false (basic format)
29
+ * @example isValidUtcOffset("+24:00") // false (out of range)
30
+ * @example isValidUtcOffset("America/New_York") // false (a zone, not an offset)
31
+ */
32
+ export declare function isValidUtcOffset(value: string): boolean;
@@ -0,0 +1,35 @@
1
+ import { utcOffset } from "../../regex/index.js";
2
+ /**
3
+ * Return true when `value` is a UTC offset in the form the offset-instant pair stores: ISO 8601
4
+ * extended `±HH:MM`, optionally `±HH:MM:SS`.
5
+ *
6
+ * - This is the offset `toOffsetInstant` returns and `fromOffsetInstant` takes, and the one
7
+ * `getTimeZoneOffset` and `getZonedOffset` return.
8
+ * - **The `utcOffset` pattern is the whole check.** Every string it matches is in range (hour
9
+ * `00`–`23`, minute and second `00`–`59`), so this validator is the pattern test plus the
10
+ * answer false for a non-string.
11
+ * - `Z` is false: it is a designator meaning "this string is already UTC", and for an event at
12
+ * UTC the pair's offset is `+00:00`.
13
+ * - Seconds are allowed because some zones did not run on a whole minute: `Africa/Monrovia` was
14
+ * `-00:44:30` until 1972. A fraction of a second is false.
15
+ * - Basic format (`-0400`) and an hour alone (`-04`) are false.
16
+ * - `-00:00` is true, and the functions that take an offset read it as `+00:00`.
17
+ * - A function whose result has no zone in it takes this offset in its time zone position too. A
18
+ * function that returns a zoned string, or formats with `Intl`, takes a time zone identifier
19
+ * only: check that with `isValidTimeZone`, which accepts `+0530` and `-08` and rejects an offset
20
+ * with seconds.
21
+ *
22
+ * @param value candidate UTC offset string
23
+ * @returns boolean indicating validity
24
+ *
25
+ * @example isValidUtcOffset("-04:00") // true
26
+ * @example isValidUtcOffset("+05:45") // true
27
+ * @example isValidUtcOffset("-00:44:30") // true (Africa/Monrovia before 1972)
28
+ * @example isValidUtcOffset("Z") // false (a designator, not an offset)
29
+ * @example isValidUtcOffset("-0400") // false (basic format)
30
+ * @example isValidUtcOffset("+24:00") // false (out of range)
31
+ * @example isValidUtcOffset("America/New_York") // false (a zone, not an offset)
32
+ */
33
+ export function isValidUtcOffset(value) {
34
+ return typeof value === "string" && utcOffset.test(value);
35
+ }
@@ -77,6 +77,12 @@ export type FreeTimeChargeOptions = FreeTimeOptions & {
77
77
  * inverted dwell is a data error), `freeDays` is not a whole number of at least `0`, the
78
78
  * options fail as they do for `freeTimeExpiry`, `tiers` has a hole, an unsafe integer or does not ascend, or the walk would pass
79
79
  * 10,000 local days.
80
+ * - **Limit at an offset with seconds.** The instant is placed in the offset's whole-minute zone,
81
+ * moved by its seconds, and the moved instant must be inside Temporal's range. So within the
82
+ * offset's seconds (under a minute) of the last instant Temporal supports
83
+ * (`+275760-09-13T00:00:00Z`) for an offset east of UTC, or of the first
84
+ * (`-271821-04-20T00:00:00Z`) for one west, this returns `null`. An offset to the minute has no
85
+ * such limit.
80
86
  *
81
87
  * @param clockStart ISO 8601 instant string of the event that starts the clock
82
88
  * @param clockEnd ISO 8601 instant string of the event that stops it (gate-out or empty return)
@@ -1,5 +1,5 @@
1
1
  import { Temporal } from "@js-temporal/polyfill";
2
- import { bandsByTier, instantFrom, parseFreeDays, parseFreeTimeTerms, parseTiers, walkFreeTime, } from "../../internal/index.js";
2
+ import { bandsByTier, frameInstant, frameZoned, instantFrom, parseFreeDays, parseFreeTimeTerms, parseTiers, walkFreeTime, zoneFrame, } from "../../internal/index.js";
3
3
  import { isValidInstant } from "../../precision/validate/isValidInstant.js";
4
4
  /**
5
5
  * Count the days a container is charged for between the start of its clock and its exit,
@@ -38,6 +38,12 @@ import { isValidInstant } from "../../precision/validate/isValidInstant.js";
38
38
  * inverted dwell is a data error), `freeDays` is not a whole number of at least `0`, the
39
39
  * options fail as they do for `freeTimeExpiry`, `tiers` has a hole, an unsafe integer or does not ascend, or the walk would pass
40
40
  * 10,000 local days.
41
+ * - **Limit at an offset with seconds.** The instant is placed in the offset's whole-minute zone,
42
+ * moved by its seconds, and the moved instant must be inside Temporal's range. So within the
43
+ * offset's seconds (under a minute) of the last instant Temporal supports
44
+ * (`+275760-09-13T00:00:00Z`) for an offset east of UTC, or of the first
45
+ * (`-271821-04-20T00:00:00Z`) for one west, this returns `null`. An offset to the minute has no
46
+ * such limit.
41
47
  *
42
48
  * @param clockStart ISO 8601 instant string of the event that starts the clock
43
49
  * @param clockEnd ISO 8601 instant string of the event that stops it (gate-out or empty return)
@@ -64,15 +70,17 @@ export function chargeableDays(clockStart, clockEnd, freeDays, options) {
64
70
  const allowed = parseFreeDays(freeDays, 0);
65
71
  // Read after the terms, so a non-object `options` is never read from.
66
72
  const tiers = terms === null ? null : parseTiers(options.tiers);
73
+ const frame = terms === null ? null : zoneFrame(terms.timeZone);
67
74
  if (!isValidInstant(clockStart) ||
68
75
  !isValidInstant(clockEnd) ||
69
76
  terms === null ||
77
+ frame === null ||
70
78
  allowed === null ||
71
79
  tiers === null) {
72
80
  return null;
73
81
  }
74
- const start = instantFrom(clockStart).toZonedDateTimeISO(terms.timeZone);
75
- const end = instantFrom(clockEnd).toZonedDateTimeISO(terms.timeZone);
82
+ const start = frameZoned(instantFrom(clockStart), frame);
83
+ const end = frameZoned(instantFrom(clockEnd), frame);
76
84
  if (Temporal.ZonedDateTime.compare(start, end) > 0) {
77
85
  return null;
78
86
  }
@@ -83,7 +91,7 @@ export function chargeableDays(clockStart, clockEnd, freeDays, options) {
83
91
  return {
84
92
  freeDaysUsed: ledger.used,
85
93
  chargeableDays: ledger.charged.length,
86
- expiresAt: ledger.expiresAt.toInstant().toString(),
94
+ expiresAt: frameInstant(ledger.expiresAt, frame).toString(),
87
95
  chargedDates: ledger.charged.map((day) => day.date),
88
96
  byTier: bandsByTier(tiers, ledger.charged.length),
89
97
  };
@@ -46,6 +46,12 @@ export interface FreeTime {
46
46
  * least `1`, `options` is not an object, `basis` or `firstDay` is missing or unknown,
47
47
  * `timeZone` is invalid, `basis` is `"working"` without a valid `BusinessCalendar`, or the walk
48
48
  * would pass 10,000 local days.
49
+ * - **Limit at an offset with seconds.** The instant is placed in the offset's whole-minute zone,
50
+ * moved by its seconds, and the moved instant must be inside Temporal's range. So within the
51
+ * offset's seconds (under a minute) of the last instant Temporal supports
52
+ * (`+275760-09-13T00:00:00Z`) for an offset east of UTC, or of the first
53
+ * (`-271821-04-20T00:00:00Z`) for one west, this returns `null`. An offset to the minute has no
54
+ * such limit.
49
55
  *
50
56
  * @param clockStart ISO 8601 instant string of the event that starts the clock (discharge, availability or gate-out)
51
57
  * @param freeDays whole number of free days the tariff allows, at least 1
@@ -63,5 +69,6 @@ export interface FreeTime {
63
69
  * @example freeTimeExpiry("2024-06-14T19:00:00Z", 3, { basis: "working", timeZone: "America/New_York", firstDay: "eventDay" }) // null (a working-day count needs the terminal's calendar)
64
70
  * @example freeTimeExpiry("2024-06-14T19:00:00Z", 0, { basis: "calendar", timeZone: "America/New_York", firstDay: "eventDay" }) // null (no free days means no last free day)
65
71
  * @example freeTimeExpiry("2024-06-14T19:00:00", 3, { basis: "calendar", timeZone: "America/New_York", firstDay: "eventDay" }) // null (no offset: not an instant)
72
+ * @example freeTimeExpiry("1970-01-01T00:30:00Z", 3, { basis: "calendar", firstDay: "eventDay", timeZone: "-00:44:30" }) // { freeTimeStart: "1969-12-31", lastFreeDay: "1970-01-02", expiresAt: "1970-01-03T00:44:30Z" }
66
73
  */
67
74
  export declare function freeTimeExpiry(clockStart: string, freeDays: number, options: FreeTimeOptions): FreeTime | null;
@@ -1,4 +1,4 @@
1
- import { instantFrom, parseFreeDays, parseFreeTimeTerms, walkFreeTime, } from "../../internal/index.js";
1
+ import { frameInstant, frameZoned, instantFrom, parseFreeDays, parseFreeTimeTerms, walkFreeTime, zoneFrame, } from "../../internal/index.js";
2
2
  import { isValidInstant } from "../../precision/validate/isValidInstant.js";
3
3
  /**
4
4
  * Lay out a container's free time from the instant its clock started, and say when it ends.
@@ -38,6 +38,12 @@ import { isValidInstant } from "../../precision/validate/isValidInstant.js";
38
38
  * least `1`, `options` is not an object, `basis` or `firstDay` is missing or unknown,
39
39
  * `timeZone` is invalid, `basis` is `"working"` without a valid `BusinessCalendar`, or the walk
40
40
  * would pass 10,000 local days.
41
+ * - **Limit at an offset with seconds.** The instant is placed in the offset's whole-minute zone,
42
+ * moved by its seconds, and the moved instant must be inside Temporal's range. So within the
43
+ * offset's seconds (under a minute) of the last instant Temporal supports
44
+ * (`+275760-09-13T00:00:00Z`) for an offset east of UTC, or of the first
45
+ * (`-271821-04-20T00:00:00Z`) for one west, this returns `null`. An offset to the minute has no
46
+ * such limit.
41
47
  *
42
48
  * @param clockStart ISO 8601 instant string of the event that starts the clock (discharge, availability or gate-out)
43
49
  * @param freeDays whole number of free days the tariff allows, at least 1
@@ -55,15 +61,20 @@ import { isValidInstant } from "../../precision/validate/isValidInstant.js";
55
61
  * @example freeTimeExpiry("2024-06-14T19:00:00Z", 3, { basis: "working", timeZone: "America/New_York", firstDay: "eventDay" }) // null (a working-day count needs the terminal's calendar)
56
62
  * @example freeTimeExpiry("2024-06-14T19:00:00Z", 0, { basis: "calendar", timeZone: "America/New_York", firstDay: "eventDay" }) // null (no free days means no last free day)
57
63
  * @example freeTimeExpiry("2024-06-14T19:00:00", 3, { basis: "calendar", timeZone: "America/New_York", firstDay: "eventDay" }) // null (no offset: not an instant)
64
+ * @example freeTimeExpiry("1970-01-01T00:30:00Z", 3, { basis: "calendar", firstDay: "eventDay", timeZone: "-00:44:30" }) // { freeTimeStart: "1969-12-31", lastFreeDay: "1970-01-02", expiresAt: "1970-01-03T00:44:30Z" }
58
65
  */
59
66
  export function freeTimeExpiry(clockStart, freeDays, options) {
60
67
  try {
61
68
  const terms = parseFreeTimeTerms(options);
62
69
  const allowed = parseFreeDays(freeDays, 1);
63
- if (!isValidInstant(clockStart) || terms === null || allowed === null) {
70
+ const frame = terms === null ? null : zoneFrame(terms.timeZone);
71
+ if (!isValidInstant(clockStart) ||
72
+ terms === null ||
73
+ frame === null ||
74
+ allowed === null) {
64
75
  return null;
65
76
  }
66
- const start = instantFrom(clockStart).toZonedDateTimeISO(terms.timeZone);
77
+ const start = frameZoned(instantFrom(clockStart), frame);
67
78
  const ledger = walkFreeTime(start, allowed, terms);
68
79
  if (ledger === null) {
69
80
  return null;
@@ -71,7 +82,7 @@ export function freeTimeExpiry(clockStart, freeDays, options) {
71
82
  return {
72
83
  freeTimeStart: ledger.free[0].date,
73
84
  lastFreeDay: ledger.free[allowed - 1].date,
74
- expiresAt: ledger.expiresAt.toInstant().toString(),
85
+ expiresAt: frameInstant(ledger.expiresAt, frame).toString(),
75
86
  };
76
87
  }
77
88
  catch {
@@ -2,3 +2,4 @@ export * from "./billingTimeline.js";
2
2
  export * from "./chargeableDays.js";
3
3
  export * from "./demurrageClock.js";
4
4
  export * from "./freeTimeExpiry.js";
5
+ export * from "./multimodalETA.js";