@naturalcycles/js-lib 14.276.0 → 15.0.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 (353) hide show
  1. package/cfg/frontend/tsconfig.json +3 -3
  2. package/dist/abort.js +1 -4
  3. package/dist/array/array.util.d.ts +1 -1
  4. package/dist/array/array.util.js +47 -88
  5. package/dist/array/range.d.ts +2 -2
  6. package/dist/array/range.js +7 -12
  7. package/dist/bot.js +6 -10
  8. package/dist/browser/adminService.d.ts +1 -1
  9. package/dist/browser/adminService.js +10 -14
  10. package/dist/browser/analytics.util.js +10 -15
  11. package/dist/browser/i18n/fetchTranslationLoader.d.ts +3 -3
  12. package/dist/browser/i18n/fetchTranslationLoader.js +1 -5
  13. package/dist/browser/i18n/translation.service.d.ts +1 -1
  14. package/dist/browser/i18n/translation.service.js +5 -10
  15. package/dist/browser/imageFitter.js +1 -5
  16. package/dist/browser/script.util.js +8 -12
  17. package/dist/browser/topbar.js +7 -10
  18. package/dist/datetime/dateInterval.d.ts +2 -2
  19. package/dist/datetime/dateInterval.js +7 -11
  20. package/dist/datetime/localDate.d.ts +3 -3
  21. package/dist/datetime/localDate.js +40 -44
  22. package/dist/datetime/localTime.d.ts +3 -3
  23. package/dist/datetime/localTime.js +36 -40
  24. package/dist/datetime/timeInterval.d.ts +2 -2
  25. package/dist/datetime/timeInterval.js +6 -10
  26. package/dist/datetime/wallTime.d.ts +3 -3
  27. package/dist/datetime/wallTime.js +5 -9
  28. package/dist/decorators/asyncMemo.decorator.d.ts +3 -3
  29. package/dist/decorators/asyncMemo.decorator.js +12 -17
  30. package/dist/decorators/createPromiseDecorator.js +3 -6
  31. package/dist/decorators/debounce.d.ts +1 -1
  32. package/dist/decorators/debounce.decorator.d.ts +1 -1
  33. package/dist/decorators/debounce.decorator.js +5 -9
  34. package/dist/decorators/debounce.js +2 -6
  35. package/dist/decorators/decorator.util.d.ts +1 -1
  36. package/dist/decorators/decorator.util.js +3 -8
  37. package/dist/decorators/logMethod.decorator.d.ts +1 -1
  38. package/dist/decorators/logMethod.decorator.js +11 -14
  39. package/dist/decorators/memo.decorator.d.ts +3 -3
  40. package/dist/decorators/memo.decorator.js +11 -16
  41. package/dist/decorators/memo.util.d.ts +2 -2
  42. package/dist/decorators/memo.util.js +11 -17
  43. package/dist/decorators/memoFn.d.ts +3 -3
  44. package/dist/decorators/memoFn.js +3 -6
  45. package/dist/decorators/memoFnAsync.d.ts +3 -3
  46. package/dist/decorators/memoFnAsync.js +5 -8
  47. package/dist/decorators/memoSimple.decorator.d.ts +1 -1
  48. package/dist/decorators/memoSimple.decorator.js +6 -10
  49. package/dist/decorators/retry.decorator.d.ts +1 -1
  50. package/dist/decorators/retry.decorator.js +3 -6
  51. package/dist/decorators/swarmSafe.decorator.js +3 -7
  52. package/dist/decorators/timeout.decorator.d.ts +1 -1
  53. package/dist/decorators/timeout.decorator.js +7 -10
  54. package/dist/define.d.ts +1 -1
  55. package/dist/define.js +11 -19
  56. package/dist/deviceIdService.js +7 -11
  57. package/dist/enum.util.d.ts +1 -1
  58. package/dist/enum.util.js +20 -42
  59. package/dist/env/buildInfo.d.ts +1 -1
  60. package/dist/env/buildInfo.js +3 -6
  61. package/dist/env.js +2 -6
  62. package/dist/error/assert.d.ts +3 -3
  63. package/dist/error/assert.js +30 -44
  64. package/dist/error/error.model.d.ts +2 -2
  65. package/dist/error/error.model.js +1 -2
  66. package/dist/error/error.util.d.ts +1 -1
  67. package/dist/error/error.util.js +25 -44
  68. package/dist/error/errorMode.js +2 -5
  69. package/dist/error/try.d.ts +2 -2
  70. package/dist/error/try.js +15 -23
  71. package/dist/error/tryCatch.d.ts +2 -2
  72. package/dist/error/tryCatch.js +6 -11
  73. package/dist/form.util.d.ts +1 -1
  74. package/dist/form.util.js +2 -6
  75. package/dist/http/fetcher.d.ts +3 -3
  76. package/dist/http/fetcher.js +48 -53
  77. package/dist/http/fetcher.model.d.ts +5 -5
  78. package/dist/http/fetcher.model.js +1 -2
  79. package/dist/http/http.model.js +1 -4
  80. package/dist/index.d.ts +96 -96
  81. package/dist/index.js +96 -99
  82. package/dist/is.util.d.ts +2 -2
  83. package/dist/is.util.js +12 -27
  84. package/dist/iter/asyncIterable2.d.ts +3 -3
  85. package/dist/iter/asyncIterable2.js +8 -12
  86. package/dist/iter/iterable2.d.ts +2 -2
  87. package/dist/iter/iterable2.js +8 -12
  88. package/dist/json-schema/from-data/generateJsonSchemaFromData.d.ts +1 -1
  89. package/dist/json-schema/from-data/generateJsonSchemaFromData.js +4 -7
  90. package/dist/json-schema/jsonSchema.cnst.d.ts +1 -1
  91. package/dist/json-schema/jsonSchema.cnst.js +1 -4
  92. package/dist/json-schema/jsonSchema.model.d.ts +1 -1
  93. package/dist/json-schema/jsonSchema.model.js +1 -2
  94. package/dist/json-schema/jsonSchema.util.d.ts +2 -2
  95. package/dist/json-schema/jsonSchema.util.js +5 -8
  96. package/dist/json-schema/jsonSchemaBuilder.d.ts +2 -2
  97. package/dist/json-schema/jsonSchemaBuilder.js +16 -25
  98. package/dist/json-schema/jsonSchemas.d.ts +2 -2
  99. package/dist/json-schema/jsonSchemas.js +5 -8
  100. package/dist/log/commonLogger.js +14 -21
  101. package/dist/math/accumulatingAverage.js +1 -5
  102. package/dist/math/math.util.js +11 -19
  103. package/dist/math/sma.js +1 -5
  104. package/dist/math/stack.util.js +11 -16
  105. package/dist/nanoid.js +2 -6
  106. package/dist/number/createDeterministicRandom.js +1 -4
  107. package/dist/number/number.util.d.ts +1 -1
  108. package/dist/number/number.util.js +9 -20
  109. package/dist/object/deepEquals.js +3 -8
  110. package/dist/object/map2.js +1 -5
  111. package/dist/object/object.util.d.ts +2 -2
  112. package/dist/object/object.util.js +40 -70
  113. package/dist/object/set2.js +1 -5
  114. package/dist/object/sortObject.d.ts +1 -1
  115. package/dist/object/sortObject.js +1 -4
  116. package/dist/object/sortObjectDeep.js +1 -4
  117. package/dist/polyfill.js +1 -4
  118. package/dist/promise/abortable.d.ts +1 -1
  119. package/dist/promise/abortable.js +2 -7
  120. package/dist/promise/pDefer.js +1 -4
  121. package/dist/promise/pDelay.d.ts +2 -2
  122. package/dist/promise/pDelay.js +4 -8
  123. package/dist/promise/pFilter.d.ts +1 -1
  124. package/dist/promise/pFilter.js +1 -4
  125. package/dist/promise/pHang.js +1 -4
  126. package/dist/promise/pMap.d.ts +2 -2
  127. package/dist/promise/pMap.js +17 -20
  128. package/dist/promise/pProps.js +1 -4
  129. package/dist/promise/pQueue.d.ts +2 -2
  130. package/dist/promise/pQueue.js +7 -11
  131. package/dist/promise/pRetry.d.ts +1 -1
  132. package/dist/promise/pRetry.js +8 -12
  133. package/dist/promise/pState.js +1 -4
  134. package/dist/promise/pTimeout.d.ts +3 -3
  135. package/dist/promise/pTimeout.js +7 -11
  136. package/dist/semver.d.ts +1 -1
  137. package/dist/semver.js +13 -18
  138. package/dist/string/case.js +9 -14
  139. package/dist/string/escape.js +2 -6
  140. package/dist/string/hash.util.d.ts +1 -1
  141. package/dist/string/hash.util.js +4 -10
  142. package/dist/string/json.util.d.ts +1 -1
  143. package/dist/string/json.util.js +5 -10
  144. package/dist/string/leven.js +1 -4
  145. package/dist/string/lodash/unicodeWords.js +1 -4
  146. package/dist/string/lodash/words.js +3 -6
  147. package/dist/string/pupa.d.ts +1 -1
  148. package/dist/string/pupa.js +4 -9
  149. package/dist/string/readingTime.d.ts +1 -1
  150. package/dist/string/readingTime.js +1 -4
  151. package/dist/string/regex.js +1 -4
  152. package/dist/string/safeJsonStringify.d.ts +1 -1
  153. package/dist/string/safeJsonStringify.js +1 -4
  154. package/dist/string/slugify.js +1 -4
  155. package/dist/string/string.util.js +15 -32
  156. package/dist/string/stringify.d.ts +1 -1
  157. package/dist/string/stringify.js +10 -14
  158. package/dist/string/url.util.d.ts +1 -1
  159. package/dist/string/url.util.js +2 -6
  160. package/dist/time/time.util.d.ts +1 -1
  161. package/dist/time/time.util.js +3 -8
  162. package/dist/typeFest.js +1 -2
  163. package/dist/types.d.ts +7 -3
  164. package/dist/types.js +21 -23
  165. package/dist/unit/size.util.js +5 -12
  166. package/dist/web.d.ts +1 -1
  167. package/dist/web.js +1 -5
  168. package/dist/zod/index.d.ts +2 -2
  169. package/dist/zod/index.js +4 -10
  170. package/dist/zod/zod.shared.schemas.js +36 -39
  171. package/dist/zod/zod.util.js +7 -14
  172. package/package.json +7 -8
  173. package/src/array/array.util.ts +3 -3
  174. package/src/array/range.ts +2 -2
  175. package/src/bot.ts +1 -1
  176. package/src/browser/adminService.ts +4 -4
  177. package/src/browser/analytics.util.ts +1 -1
  178. package/src/browser/i18n/fetchTranslationLoader.ts +3 -3
  179. package/src/browser/i18n/translation.service.ts +2 -2
  180. package/src/browser/script.util.ts +2 -2
  181. package/src/datetime/dateInterval.ts +3 -3
  182. package/src/datetime/localDate.ts +5 -5
  183. package/src/datetime/localTime.ts +6 -6
  184. package/src/datetime/timeInterval.ts +3 -3
  185. package/src/datetime/wallTime.ts +4 -4
  186. package/src/decorators/asyncMemo.decorator.ts +7 -7
  187. package/src/decorators/createPromiseDecorator.ts +1 -1
  188. package/src/decorators/debounce.decorator.ts +2 -2
  189. package/src/decorators/debounce.ts +1 -1
  190. package/src/decorators/decorator.util.ts +1 -1
  191. package/src/decorators/logMethod.decorator.ts +4 -4
  192. package/src/decorators/memo.decorator.ts +7 -7
  193. package/src/decorators/memo.util.ts +4 -4
  194. package/src/decorators/memoFn.ts +4 -4
  195. package/src/decorators/memoFnAsync.ts +5 -5
  196. package/src/decorators/memoSimple.decorator.ts +4 -4
  197. package/src/decorators/retry.decorator.ts +2 -2
  198. package/src/decorators/swarmSafe.decorator.ts +2 -2
  199. package/src/decorators/timeout.decorator.ts +4 -4
  200. package/src/define.ts +3 -3
  201. package/src/deviceIdService.ts +3 -3
  202. package/src/enum.util.ts +1 -1
  203. package/src/env/buildInfo.ts +2 -2
  204. package/src/error/assert.ts +7 -7
  205. package/src/error/error.model.ts +2 -2
  206. package/src/error/error.util.ts +5 -5
  207. package/src/error/try.ts +5 -5
  208. package/src/error/tryCatch.ts +3 -3
  209. package/src/form.util.ts +1 -1
  210. package/src/http/fetcher.model.ts +5 -5
  211. package/src/http/fetcher.ts +20 -15
  212. package/src/index.ts +96 -96
  213. package/src/is.util.ts +2 -2
  214. package/src/iter/asyncIterable2.ts +3 -3
  215. package/src/iter/iterable2.ts +2 -2
  216. package/src/json-schema/from-data/generateJsonSchemaFromData.ts +2 -2
  217. package/src/json-schema/jsonSchema.cnst.ts +1 -1
  218. package/src/json-schema/jsonSchema.model.ts +1 -1
  219. package/src/json-schema/jsonSchema.util.ts +4 -4
  220. package/src/json-schema/jsonSchemaBuilder.ts +5 -5
  221. package/src/json-schema/jsonSchemas.ts +2 -2
  222. package/src/math/math.util.ts +2 -2
  223. package/src/math/stack.util.ts +1 -1
  224. package/src/number/number.util.ts +1 -1
  225. package/src/object/object.util.ts +3 -3
  226. package/src/object/sortObject.ts +1 -1
  227. package/src/promise/abortable.ts +1 -1
  228. package/src/promise/pDelay.ts +3 -3
  229. package/src/promise/pFilter.ts +1 -1
  230. package/src/promise/pMap.ts +2 -2
  231. package/src/promise/pQueue.ts +4 -4
  232. package/src/promise/pRetry.ts +2 -2
  233. package/src/promise/pTimeout.ts +4 -4
  234. package/src/semver.ts +3 -3
  235. package/src/string/case.ts +2 -2
  236. package/src/string/hash.util.ts +1 -1
  237. package/src/string/json.util.ts +2 -2
  238. package/src/string/lodash/words.ts +1 -1
  239. package/src/string/pupa.ts +2 -2
  240. package/src/string/readingTime.ts +1 -1
  241. package/src/string/safeJsonStringify.ts +1 -1
  242. package/src/string/stringify.ts +4 -4
  243. package/src/string/url.util.ts +1 -1
  244. package/src/time/time.util.ts +1 -1
  245. package/src/types.ts +15 -3
  246. package/src/web.ts +1 -1
  247. package/src/zod/index.ts +2 -2
  248. package/src/zod/zod.util.ts +1 -1
  249. package/dist-esm/abort.js +0 -12
  250. package/dist-esm/array/array.util.js +0 -458
  251. package/dist-esm/array/range.js +0 -34
  252. package/dist-esm/bot.js +0 -130
  253. package/dist-esm/browser/adminService.js +0 -94
  254. package/dist-esm/browser/analytics.util.js +0 -54
  255. package/dist-esm/browser/i18n/fetchTranslationLoader.js +0 -13
  256. package/dist-esm/browser/i18n/translation.service.js +0 -56
  257. package/dist-esm/browser/imageFitter.js +0 -65
  258. package/dist-esm/browser/script.util.js +0 -46
  259. package/dist-esm/browser/topbar.js +0 -135
  260. package/dist-esm/datetime/dateInterval.js +0 -80
  261. package/dist-esm/datetime/localDate.js +0 -719
  262. package/dist-esm/datetime/localTime.js +0 -996
  263. package/dist-esm/datetime/timeInterval.js +0 -88
  264. package/dist-esm/datetime/wallTime.js +0 -70
  265. package/dist-esm/decorators/asyncMemo.decorator.js +0 -111
  266. package/dist-esm/decorators/createPromiseDecorator.js +0 -82
  267. package/dist-esm/decorators/debounce.decorator.js +0 -17
  268. package/dist-esm/decorators/debounce.js +0 -114
  269. package/dist-esm/decorators/decorator.util.js +0 -31
  270. package/dist-esm/decorators/logMethod.decorator.js +0 -85
  271. package/dist-esm/decorators/memo.decorator.js +0 -80
  272. package/dist-esm/decorators/memo.util.js +0 -97
  273. package/dist-esm/decorators/memoFn.js +0 -29
  274. package/dist-esm/decorators/memoFnAsync.js +0 -35
  275. package/dist-esm/decorators/memoSimple.decorator.js +0 -55
  276. package/dist-esm/decorators/retry.decorator.js +0 -9
  277. package/dist-esm/decorators/swarmSafe.decorator.js +0 -38
  278. package/dist-esm/decorators/timeout.decorator.js +0 -19
  279. package/dist-esm/define.js +0 -109
  280. package/dist-esm/deviceIdService.js +0 -105
  281. package/dist-esm/enum.util.js +0 -157
  282. package/dist-esm/env/buildInfo.js +0 -19
  283. package/dist-esm/env.js +0 -19
  284. package/dist-esm/error/assert.js +0 -122
  285. package/dist-esm/error/error.model.js +0 -1
  286. package/dist-esm/error/error.util.js +0 -337
  287. package/dist-esm/error/errorMode.js +0 -20
  288. package/dist-esm/error/try.js +0 -105
  289. package/dist-esm/error/tryCatch.js +0 -41
  290. package/dist-esm/form.util.js +0 -16
  291. package/dist-esm/http/fetcher.js +0 -704
  292. package/dist-esm/http/fetcher.model.js +0 -3
  293. package/dist-esm/http/http.model.js +0 -1
  294. package/dist-esm/index.js +0 -96
  295. package/dist-esm/is.util.js +0 -70
  296. package/dist-esm/iter/asyncIterable2.js +0 -103
  297. package/dist-esm/iter/iterable2.js +0 -87
  298. package/dist-esm/json-schema/from-data/generateJsonSchemaFromData.js +0 -86
  299. package/dist-esm/json-schema/jsonSchema.cnst.js +0 -38
  300. package/dist-esm/json-schema/jsonSchema.model.js +0 -1
  301. package/dist-esm/json-schema/jsonSchema.util.js +0 -27
  302. package/dist-esm/json-schema/jsonSchemaBuilder.js +0 -352
  303. package/dist-esm/json-schema/jsonSchemas.js +0 -6
  304. package/dist-esm/log/commonLogger.js +0 -78
  305. package/dist-esm/math/accumulatingAverage.js +0 -32
  306. package/dist-esm/math/math.util.js +0 -85
  307. package/dist-esm/math/sma.js +0 -43
  308. package/dist-esm/math/stack.util.js +0 -82
  309. package/dist-esm/nanoid.js +0 -57
  310. package/dist-esm/number/createDeterministicRandom.js +0 -18
  311. package/dist-esm/number/number.util.js +0 -109
  312. package/dist-esm/object/deepEquals.js +0 -170
  313. package/dist-esm/object/map2.js +0 -21
  314. package/dist-esm/object/object.util.js +0 -435
  315. package/dist-esm/object/set2.js +0 -15
  316. package/dist-esm/object/sortObject.js +0 -21
  317. package/dist-esm/object/sortObjectDeep.js +0 -17
  318. package/dist-esm/polyfill.js +0 -6
  319. package/dist-esm/promise/abortable.js +0 -31
  320. package/dist-esm/promise/pDefer.js +0 -17
  321. package/dist-esm/promise/pDelay.js +0 -37
  322. package/dist-esm/promise/pFilter.js +0 -5
  323. package/dist-esm/promise/pHang.js +0 -6
  324. package/dist-esm/promise/pMap.js +0 -174
  325. package/dist-esm/promise/pProps.js +0 -20
  326. package/dist-esm/promise/pQueue.js +0 -101
  327. package/dist-esm/promise/pRetry.js +0 -64
  328. package/dist-esm/promise/pState.js +0 -14
  329. package/dist-esm/promise/pTimeout.js +0 -64
  330. package/dist-esm/semver.js +0 -149
  331. package/dist-esm/string/case.js +0 -24
  332. package/dist-esm/string/escape.js +0 -49
  333. package/dist-esm/string/hash.util.js +0 -67
  334. package/dist-esm/string/json.util.js +0 -46
  335. package/dist-esm/string/leven.js +0 -77
  336. package/dist-esm/string/lodash/unicodeWords.js +0 -68
  337. package/dist-esm/string/lodash/words.js +0 -31
  338. package/dist-esm/string/pupa.js +0 -54
  339. package/dist-esm/string/readingTime.js +0 -102
  340. package/dist-esm/string/regex.js +0 -6
  341. package/dist-esm/string/safeJsonStringify.js +0 -39
  342. package/dist-esm/string/slugify.js +0 -66
  343. package/dist-esm/string/string.util.js +0 -99
  344. package/dist-esm/string/stringify.js +0 -133
  345. package/dist-esm/string/url.util.js +0 -42
  346. package/dist-esm/time/time.util.js +0 -61
  347. package/dist-esm/typeFest.js +0 -2
  348. package/dist-esm/types.js +0 -59
  349. package/dist-esm/unit/size.util.js +0 -43
  350. package/dist-esm/web.js +0 -40
  351. package/dist-esm/zod/index.js +0 -4
  352. package/dist-esm/zod/zod.shared.schemas.js +0 -92
  353. package/dist-esm/zod/zod.util.js +0 -52
@@ -1,996 +0,0 @@
1
- import { _assert } from '../error/assert';
2
- import { _ms } from '../time/time.util';
3
- import { localDate } from './localDate';
4
- import { WallTime } from './wallTime';
5
- export var ISODayOfWeek;
6
- (function (ISODayOfWeek) {
7
- ISODayOfWeek[ISODayOfWeek["MONDAY"] = 1] = "MONDAY";
8
- ISODayOfWeek[ISODayOfWeek["TUESDAY"] = 2] = "TUESDAY";
9
- ISODayOfWeek[ISODayOfWeek["WEDNESDAY"] = 3] = "WEDNESDAY";
10
- ISODayOfWeek[ISODayOfWeek["THURSDAY"] = 4] = "THURSDAY";
11
- ISODayOfWeek[ISODayOfWeek["FRIDAY"] = 5] = "FRIDAY";
12
- ISODayOfWeek[ISODayOfWeek["SATURDAY"] = 6] = "SATURDAY";
13
- ISODayOfWeek[ISODayOfWeek["SUNDAY"] = 7] = "SUNDAY";
14
- })(ISODayOfWeek || (ISODayOfWeek = {}));
15
- const weekStartsOn = 1; // mon, as per ISO
16
- const MILLISECONDS_IN_WEEK = 604800000;
17
- const SECONDS_IN_DAY = 86400;
18
- // const MILLISECONDS_IN_DAY = 86400000
19
- // const MILLISECONDS_IN_MINUTE = 60000
20
- export const VALID_DAYS_OF_WEEK = new Set([1, 2, 3, 4, 5, 6, 7]);
21
- /**
22
- * It supports 2 forms:
23
- * 1. 2023-03-03
24
- * 2. 2023-03-03T05:10:02
25
- */
26
- const DATE_TIME_REGEX_LOOSE = /^(\d{4})-(\d{2})-(\d{2})([Tt\s](\d{2}):?(\d{2})?:?(\d{2})?)?/;
27
- /**
28
- * Supports 2 forms:
29
- * 1. 2023-03-03
30
- * 2. 2023-03-03T05:10:02
31
- * Ok, now it allows arbitrary stuff after `:ss`, to allow millis/timezone info,
32
- * but it will not take it into account.
33
- */
34
- const DATE_TIME_REGEX_STRICT = /^(\d{4})-(\d{2})-(\d{2})[Tt\s](\d{2}):(\d{2}):(\d{2})/;
35
- const DATE_REGEX_STRICT = /^(\d\d\d\d)-(\d\d)-(\d\d)$/;
36
- export class LocalTime {
37
- constructor($date) {
38
- this.$date = $date;
39
- }
40
- /**
41
- * Returns [cloned] LocalTime that is based on the same unixtimestamp, but in UTC timezone.
42
- * Opposite of `.local()` method.
43
- */
44
- toUTC() {
45
- return new LocalTime(new Date(this.$date.toISOString()));
46
- }
47
- /**
48
- * Returns [cloned] LocalTime that is based on the same unixtimestamp, but in local timezone.
49
- * Opposite of `.utc()` method.
50
- */
51
- toLocal() {
52
- return new LocalTime(new Date(this.$date));
53
- }
54
- /**
55
- * Returns [cloned] fake LocalTime that has yyyy-mm-dd hh:mm:ss in the provided timezone.
56
- * It is a fake LocalTime in a sense that it's timezone is not real.
57
- * See this ("common errors"): https://stackoverflow.com/a/15171030/4919972
58
- * Fake also means that unixTimestamp of that new LocalDate is not the same.
59
- * For that reason we return WallTime, and not a LocalTime.
60
- * WallTime can be pretty-printed as Date-only, Time-only or DateAndTime.
61
- *
62
- * E.g `inTimezone('America/New_York').toISOTime()`
63
- *
64
- * https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
65
- *
66
- * @experimental
67
- */
68
- inTimezone(tz) {
69
- const d = new Date(this.$date.toLocaleString('en-US', { timeZone: tz }));
70
- return new WallTime({
71
- year: d.getFullYear(),
72
- month: d.getMonth() + 1,
73
- day: d.getDate(),
74
- hour: d.getHours(),
75
- minute: d.getMinutes(),
76
- second: d.getSeconds(),
77
- });
78
- }
79
- /**
80
- * UTC offset is the opposite of "timezone offset" - it's the number of minutes to add
81
- * to the local time to get UTC time.
82
- *
83
- * E.g utcOffset for CEST is -120,
84
- * which means that you need to add -120 minutes to the local time to get UTC time.
85
- *
86
- * Instead of -0 it returns 0, for the peace of mind and less weird test/snapshot differences.
87
- *
88
- * If timezone (tz) is specified, e.g `America/New_York`,
89
- * it will return the UTC offset for that timezone.
90
- *
91
- * https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
92
- */
93
- getUTCOffsetMinutes(tz) {
94
- if (tz) {
95
- // based on: https://stackoverflow.com/a/53652131/4919972
96
- const nowTime = this.$date.getTime();
97
- const tzTime = new Date(this.$date.toLocaleString('en-US', { timeZone: tz })).getTime();
98
- return Math.round((tzTime - nowTime) / 60000) || 0;
99
- }
100
- return -this.$date.getTimezoneOffset() || 0;
101
- }
102
- /**
103
- * Same as getUTCOffsetMinutes, but rounded to hours.
104
- *
105
- * E.g for CEST it is -2.
106
- *
107
- * Instead of -0 it returns 0, for the peace of mind and less weird test/snapshot differences.
108
- *
109
- * If timezone (tz) is specified, e.g `America/New_York`,
110
- * it will return the UTC offset for that timezone.
111
- */
112
- getUTCOffsetHours(tz) {
113
- return Math.round(this.getUTCOffsetMinutes(tz) / 60);
114
- }
115
- /**
116
- * Returns e.g `-05:00` for New_York winter time.
117
- */
118
- getUTCOffsetString(tz) {
119
- const minutes = this.getUTCOffsetMinutes(tz);
120
- const hours = Math.trunc(minutes / 60);
121
- const sign = hours < 0 ? '-' : '+';
122
- const h = String(Math.abs(hours)).padStart(2, '0');
123
- const m = String(minutes % 60).padStart(2, '0');
124
- return `${sign}${h}:${m}`;
125
- }
126
- get(unit) {
127
- if (unit === 'year') {
128
- return this.$date.getFullYear();
129
- }
130
- if (unit === 'month') {
131
- return this.$date.getMonth() + 1;
132
- }
133
- if (unit === 'day') {
134
- return this.$date.getDate();
135
- }
136
- if (unit === 'hour') {
137
- return this.$date.getHours();
138
- }
139
- if (unit === 'minute') {
140
- return this.$date.getMinutes();
141
- }
142
- if (unit === 'week') {
143
- return getWeek(this.$date);
144
- }
145
- // second
146
- return this.$date.getSeconds();
147
- }
148
- set(unit, v, mutate = false) {
149
- const t = mutate ? this : this.clone();
150
- if (unit === 'year') {
151
- t.$date.setFullYear(v);
152
- }
153
- else if (unit === 'month') {
154
- t.$date.setMonth(v - 1);
155
- }
156
- else if (unit === 'day') {
157
- t.$date.setDate(v);
158
- }
159
- else if (unit === 'hour') {
160
- t.$date.setHours(v);
161
- }
162
- else if (unit === 'minute') {
163
- t.$date.setMinutes(v);
164
- }
165
- else if (unit === 'second') {
166
- t.$date.setSeconds(v);
167
- }
168
- else if (unit === 'week') {
169
- setWeek(t.$date, v, true);
170
- }
171
- return t;
172
- }
173
- get year() {
174
- return this.$date.getFullYear();
175
- }
176
- setYear(v) {
177
- return this.set('year', v);
178
- }
179
- get month() {
180
- return this.$date.getMonth() + 1;
181
- }
182
- setMonth(v) {
183
- return this.set('month', v);
184
- }
185
- get week() {
186
- return getWeek(this.$date);
187
- }
188
- setWeek(v) {
189
- return this.set('week', v);
190
- }
191
- get day() {
192
- return this.$date.getDate();
193
- }
194
- setDay(v) {
195
- return this.set('day', v);
196
- }
197
- get hour() {
198
- return this.$date.getHours();
199
- }
200
- setHour(v) {
201
- return this.set('hour', v);
202
- }
203
- get minute() {
204
- return this.$date.getMinutes();
205
- }
206
- setMinute(v) {
207
- return this.set('minute', v);
208
- }
209
- get second() {
210
- return this.$date.getSeconds();
211
- }
212
- setSecond(v) {
213
- return this.set('second', v);
214
- }
215
- /**
216
- * Based on ISO: 1-7 is Mon-Sun.
217
- */
218
- get dayOfWeek() {
219
- return (this.$date.getDay() || 7);
220
- }
221
- /**
222
- * Returns LocalTime for the given DayOfWeek (e.g Monday), that is in the same week as this.
223
- * It may move the time into the future, or the past, depending on how the desired DayOfWeek is in
224
- * relation to `this`.
225
- */
226
- setDayOfWeek(dow) {
227
- _assert(VALID_DAYS_OF_WEEK.has(dow), `Invalid dayOfWeek: ${dow}`);
228
- const delta = dow - this.dayOfWeek;
229
- return this.plus(delta, 'day');
230
- }
231
- /**
232
- * Returns LocalTime for the given DayOfWeek (e.g Monday), that is in the future,
233
- * in relation to this.
234
- * If this LocalTime is Monday, and desired DoW is also Monday - `this` is returned.
235
- */
236
- setNextDayOfWeek(dow) {
237
- _assert(VALID_DAYS_OF_WEEK.has(dow), `Invalid dayOfWeek: ${dow}`);
238
- let delta = dow - this.dayOfWeek;
239
- if (delta < 0)
240
- delta += 7;
241
- return this.plus(delta, 'day');
242
- }
243
- setComponents(c, mutate = false) {
244
- const d = mutate ? this.$date : new Date(this.$date);
245
- // Year, month and day set all-at-once, to avoid 30/31 (and 28/29) mishap
246
- if (c.day || c.month !== undefined || c.year !== undefined) {
247
- d.setFullYear(c.year ?? d.getFullYear(), c.month ? c.month - 1 : d.getMonth(), c.day || d.getDate());
248
- }
249
- if (c.hour !== undefined) {
250
- d.setHours(c.hour);
251
- }
252
- if (c.minute !== undefined) {
253
- d.setMinutes(c.minute);
254
- }
255
- if (c.second !== undefined) {
256
- d.setSeconds(c.second);
257
- }
258
- return mutate ? this : new LocalTime(d);
259
- }
260
- plusSeconds(num) {
261
- return this.plus(num, 'second');
262
- }
263
- plusMinutes(num) {
264
- return this.plus(num, 'minute');
265
- }
266
- plusHours(num) {
267
- return this.plus(num, 'hour');
268
- }
269
- plusDays(num) {
270
- return this.plus(num, 'day');
271
- }
272
- plusWeeks(num) {
273
- return this.plus(num, 'week');
274
- }
275
- plusMonths(num) {
276
- return this.plus(num, 'month');
277
- }
278
- plusYears(num) {
279
- return this.plus(num, 'year');
280
- }
281
- minusSeconds(num) {
282
- return this.plus(-num, 'second');
283
- }
284
- minusMinutes(num) {
285
- return this.plus(-num, 'minute');
286
- }
287
- minusHours(num) {
288
- return this.plus(-num, 'hour');
289
- }
290
- minusDays(num) {
291
- return this.plus(-num, 'day');
292
- }
293
- minusWeeks(num) {
294
- return this.plus(-num, 'week');
295
- }
296
- minusMonths(num) {
297
- return this.plus(-num, 'month');
298
- }
299
- minusYears(num) {
300
- return this.plus(-num, 'year');
301
- }
302
- plus(num, unit, mutate = false) {
303
- if (unit === 'week') {
304
- num *= 7;
305
- unit = 'day';
306
- }
307
- if (unit === 'year' || unit === 'month') {
308
- const d = addMonths(this.$date, unit === 'month' ? num : num * 12, mutate);
309
- return mutate ? this : localTime.fromInput(d);
310
- }
311
- return this.set(unit, this.get(unit) + num, mutate);
312
- }
313
- minus(num, unit, mutate = false) {
314
- return this.plus(num * -1, unit, mutate);
315
- }
316
- absDiff(other, unit) {
317
- return Math.abs(this.diff(other, unit));
318
- }
319
- diff(other, unit) {
320
- const date2 = localTime.fromInput(other).$date;
321
- const secDiff = (this.$date.valueOf() - date2.valueOf()) / 1000;
322
- if (!secDiff)
323
- return 0;
324
- let r;
325
- if (unit === 'year') {
326
- r = differenceInMonths(this.$date, date2) / 12;
327
- }
328
- else if (unit === 'month') {
329
- r = differenceInMonths(this.$date, date2);
330
- }
331
- else if (unit === 'day') {
332
- r = secDiff / SECONDS_IN_DAY;
333
- }
334
- else if (unit === 'week') {
335
- r = secDiff / (7 * 24 * 60 * 60);
336
- }
337
- else if (unit === 'hour') {
338
- r = secDiff / 3600;
339
- }
340
- else if (unit === 'minute') {
341
- r = secDiff / 60;
342
- }
343
- else {
344
- // unit === 'second'
345
- r = secDiff;
346
- }
347
- // `|| 0` is to avoid returning -0
348
- return Math.trunc(r) || 0;
349
- }
350
- startOf(unit, mutate = false) {
351
- if (unit === 'second')
352
- return this;
353
- const d = mutate ? this.$date : new Date(this.$date);
354
- d.setSeconds(0, 0);
355
- if (unit !== 'minute') {
356
- d.setMinutes(0);
357
- if (unit !== 'hour') {
358
- d.setHours(0);
359
- if (unit !== 'day') {
360
- // year, month or week
361
- if (unit === 'year') {
362
- d.setMonth(0);
363
- d.setDate(1);
364
- }
365
- else if (unit === 'month') {
366
- d.setDate(1);
367
- }
368
- else {
369
- // week
370
- startOfWeek(d, true);
371
- }
372
- }
373
- }
374
- }
375
- return mutate ? this : new LocalTime(d);
376
- }
377
- endOf(unit, mutate = false) {
378
- if (unit === 'second')
379
- return this;
380
- const d = mutate ? this.$date : new Date(this.$date);
381
- d.setSeconds(59, 0);
382
- if (unit !== 'minute') {
383
- d.setMinutes(59);
384
- if (unit !== 'hour') {
385
- d.setHours(23);
386
- if (unit !== 'day') {
387
- // year, month or week
388
- if (unit === 'year') {
389
- d.setMonth(11);
390
- }
391
- if (unit === 'week') {
392
- endOfWeek(d, true);
393
- }
394
- else {
395
- // year or month
396
- const lastDay = localDate.getMonthLength(d.getFullYear(), d.getMonth() + 1);
397
- d.setDate(lastDay);
398
- }
399
- }
400
- }
401
- }
402
- return mutate ? this : new LocalTime(d);
403
- }
404
- /**
405
- * Returns how many days are in the current month.
406
- * E.g 31 for January.
407
- */
408
- get daysInMonth() {
409
- return localDate.getMonthLength(this.$date.getFullYear(), this.$date.getMonth() + 1);
410
- }
411
- isSame(d) {
412
- return this.compare(d) === 0;
413
- }
414
- isBefore(d, inclusive = false) {
415
- const r = this.compare(d);
416
- return r === -1 || (r === 0 && inclusive);
417
- }
418
- isSameOrBefore(d) {
419
- return this.compare(d) <= 0;
420
- }
421
- isAfter(d, inclusive = false) {
422
- const r = this.compare(d);
423
- return r === 1 || (r === 0 && inclusive);
424
- }
425
- isSameOrAfter(d) {
426
- return this.compare(d) >= 0;
427
- }
428
- isBetween(min, max, incl = '[)') {
429
- let r = this.compare(min);
430
- // eslint-disable-next-line @typescript-eslint/prefer-string-starts-ends-with
431
- if (r < 0 || (r === 0 && incl[0] === '('))
432
- return false;
433
- r = this.compare(max);
434
- if (r > 0 || (r === 0 && incl[1] === ')'))
435
- return false;
436
- return true;
437
- }
438
- /**
439
- * Checks if this localTime is older (<) than "now" by X units.
440
- *
441
- * Example:
442
- *
443
- * localTime(expirationDate).isOlderThan(5, 'day')
444
- *
445
- * Third argument allows to override "now".
446
- */
447
- isOlderThan(n, unit, now) {
448
- return this.isBefore(localTime.fromInput(now ?? new Date()).plus(-n, unit));
449
- }
450
- /**
451
- * Checks if this localTime is same or older (<=) than "now" by X units.
452
- */
453
- isSameOrOlderThan(n, unit, now) {
454
- return this.isSameOrBefore(localTime.fromInput(now ?? new Date()).plus(-n, unit));
455
- }
456
- /**
457
- * Checks if this localTime is younger (>) than "now" by X units.
458
- *
459
- * Example:
460
- *
461
- * localTime(expirationDate).isYoungerThan(5, 'day')
462
- *
463
- * Third argument allows to override "now".
464
- */
465
- isYoungerThan(n, unit, now) {
466
- return this.isAfter(localTime.fromInput(now ?? new Date()).plus(-n, unit));
467
- }
468
- /**
469
- * Checks if this localTime is same or younger (>=) than "now" by X units.
470
- */
471
- isSameOrYoungerThan(n, unit, now) {
472
- return this.isSameOrAfter(localTime.fromInput(now ?? new Date()).plus(-n, unit));
473
- }
474
- getAgeInYears(now) {
475
- return this.getAgeIn('year', now);
476
- }
477
- getAgeInMonths(now) {
478
- return this.getAgeIn('month', now);
479
- }
480
- getAgeInDays(now) {
481
- return this.getAgeIn('day', now);
482
- }
483
- getAgeInHours(now) {
484
- return this.getAgeIn('hour', now);
485
- }
486
- getAgeInMinutes(now) {
487
- return this.getAgeIn('minute', now);
488
- }
489
- getAgeInSeconds(now) {
490
- return this.getAgeIn('second', now);
491
- }
492
- getAgeIn(unit, now) {
493
- return localTime.fromInput(now ?? new Date()).diff(this, unit);
494
- }
495
- isAfterNow() {
496
- return this.$date.valueOf() > Date.now();
497
- }
498
- isBeforeNow() {
499
- return this.$date.valueOf() < Date.now();
500
- }
501
- /**
502
- * Returns 1 if this > d
503
- * returns 0 if they are equal
504
- * returns -1 if this < d
505
- */
506
- compare(d) {
507
- const t1 = this.$date.valueOf();
508
- const t2 = localTime.fromInput(d).$date.valueOf();
509
- if (t1 === t2)
510
- return 0;
511
- return t1 < t2 ? -1 : 1;
512
- }
513
- toDateTimeObject() {
514
- return {
515
- ...this.toDateObject(),
516
- ...this.toTimeObject(),
517
- };
518
- }
519
- toDateObject() {
520
- return {
521
- year: this.$date.getFullYear(),
522
- month: this.$date.getMonth() + 1,
523
- day: this.$date.getDate(),
524
- };
525
- }
526
- toTimeObject() {
527
- return {
528
- hour: this.$date.getHours(),
529
- minute: this.$date.getMinutes(),
530
- second: this.$date.getSeconds(),
531
- };
532
- }
533
- toFromNowString(now = new Date()) {
534
- const msDiff = localTime.fromInput(now).$date.valueOf() - this.$date.valueOf();
535
- if (msDiff === 0)
536
- return 'now';
537
- if (msDiff >= 0) {
538
- return `${_ms(msDiff)} ago`;
539
- }
540
- return `in ${_ms(msDiff * -1)}`;
541
- }
542
- toDate() {
543
- return this.$date;
544
- }
545
- clone() {
546
- return new LocalTime(new Date(this.$date));
547
- }
548
- get unix() {
549
- return Math.floor(this.$date.valueOf() / 1000);
550
- }
551
- get unixMillis() {
552
- return this.$date.valueOf();
553
- }
554
- valueOf() {
555
- return Math.floor(this.$date.valueOf() / 1000);
556
- }
557
- toLocalDate() {
558
- return localDate.fromDate(this.$date);
559
- }
560
- /**
561
- * Returns e.g: `1984-06-21 17:56:21`
562
- * or (if seconds=false):
563
- * `1984-06-21 17:56`
564
- */
565
- toPretty(seconds = true) {
566
- return (this.toISODate() + ' ' + this.toISOTime(seconds));
567
- // !! Not using toISOString(), as it returns time in UTC, not in local timezone (unexpected!)
568
- // const s = this.$date.toISOString()
569
- // return s.slice(0, 10) + ' ' + s.slice(11, seconds ? 19 : 16)
570
- }
571
- /**
572
- * Returns e.g: `1984-06-21T17:56:21`
573
- */
574
- toISODateTime() {
575
- return (this.toISODate() + 'T' + this.toISOTime());
576
- // !! Not using toISOString(), as it returns time in UTC, not in local timezone (unexpected!)
577
- // return this.$date.toISOString().slice(0, 19)
578
- }
579
- /**
580
- * Returns e.g: `1984-06-21`, only the date part of DateTime
581
- */
582
- toISODate() {
583
- const { year, month, day } = this.toDateObject();
584
- return [
585
- String(year).padStart(4, '0'),
586
- String(month).padStart(2, '0'),
587
- String(day).padStart(2, '0'),
588
- ].join('-');
589
- // !! Not using toISOString(), as it returns time in UTC, not in local timezone (unexpected!)
590
- // return this.$date.toISOString().slice(0, 10)
591
- }
592
- /**
593
- * Returns e.g: `17:03:15` (or `17:03` with seconds=false)
594
- */
595
- toISOTime(seconds = true) {
596
- const { hour, minute, second } = this.toTimeObject();
597
- return [
598
- String(hour).padStart(2, '0'),
599
- String(minute).padStart(2, '0'),
600
- seconds && String(second).padStart(2, '0'),
601
- ]
602
- .filter(Boolean)
603
- .join(':');
604
- // !! Not using toISOString(), as it returns time in UTC, not in local timezone (unexpected!)
605
- // return this.$date.toISOString().slice(11, seconds ? 19 : 16)
606
- }
607
- toWallTime() {
608
- return new WallTime(this.toDateTimeObject());
609
- }
610
- /**
611
- * Returns e.g: `19840621_1705`
612
- */
613
- toStringCompact(seconds = false) {
614
- const { year, month, day, hour, minute, second } = this.toDateTimeObject();
615
- return [
616
- String(year).padStart(4, '0'),
617
- String(month).padStart(2, '0'),
618
- String(day).padStart(2, '0'),
619
- '_',
620
- String(hour).padStart(2, '0'),
621
- String(minute).padStart(2, '0'),
622
- seconds ? String(second).padStart(2, '0') : '',
623
- ].join('');
624
- }
625
- toString() {
626
- return this.toISODateTime();
627
- }
628
- toJSON() {
629
- return this.unix;
630
- }
631
- toMonthId() {
632
- return this.toISODate().slice(0, 7);
633
- }
634
- format(fmt) {
635
- if (fmt instanceof Intl.DateTimeFormat) {
636
- return fmt.format(this.$date);
637
- }
638
- return fmt(this);
639
- }
640
- }
641
- class LocalTimeFactory {
642
- /**
643
- * Creates a LocalTime from the input, unless it's falsy - then returns undefined.
644
- *
645
- * `localTime` function will instead return LocalTime of `now` for falsy input.
646
- */
647
- orUndefined(input) {
648
- return input || input === 0 ? this.fromInput(input) : undefined;
649
- }
650
- /**
651
- * Creates a LocalTime from the input, unless it's falsy - then returns LocalTime.now
652
- */
653
- orNow(input) {
654
- return input || input === 0 ? this.fromInput(input) : this.now();
655
- }
656
- now() {
657
- return new LocalTime(new Date());
658
- }
659
- /**
660
- Convenience function to return current Unix timestamp in seconds.
661
- Like Date.now(), but in seconds.
662
- */
663
- nowUnix() {
664
- return Math.floor(Date.now() / 1000);
665
- }
666
- /**
667
- Convenience function that retuns the same as Date.now(), but with proper type of UnixTimestampMillis.
668
- */
669
- nowUnixMillis() {
670
- return Date.now();
671
- }
672
- /**
673
- * Create LocalTime from LocalTimeInput.
674
- * Input can already be a LocalTime - it is returned as-is in that case.
675
- * Date - will be used as-is.
676
- * String - will be parsed as strict `yyyy-mm-ddThh:mm:ss`.
677
- * Number - will be treated as unix timestamp in seconds.
678
- */
679
- fromInput(input) {
680
- if (input instanceof LocalTime)
681
- return input;
682
- if (input instanceof Date) {
683
- return this.fromDate(input);
684
- }
685
- if (typeof input === 'number') {
686
- return this.fromUnix(input);
687
- }
688
- // It means it's a string
689
- // Will parse it STRICTLY
690
- return this.fromIsoDateTimeString(input);
691
- }
692
- /**
693
- * Returns true if input is valid to create LocalTime.
694
- */
695
- isValid(input) {
696
- if (!input)
697
- return false;
698
- if (input instanceof LocalTime)
699
- return true;
700
- if (input instanceof Date)
701
- return !Number.isNaN(input.getDate());
702
- // We currently don't validate Unixtimestamp input, treat it as always valid
703
- if (typeof input === 'number')
704
- return true;
705
- return this.isValidString(input);
706
- }
707
- /**
708
- * Returns true if isoString is a valid iso8601 string like `yyyy-mm-ddThh:mm:dd`.
709
- */
710
- isValidString(isoString) {
711
- return !!this.parseStrictlyOrUndefined(isoString);
712
- }
713
- /**
714
- * Tries to convert/parse the input into LocalTime.
715
- * Uses LOOSE parsing.
716
- * If invalid - doesn't throw, but returns undefined instead.
717
- */
718
- try(input) {
719
- if (input instanceof LocalTime)
720
- return input;
721
- if (input instanceof Date) {
722
- if (Number.isNaN(input.getDate()))
723
- return;
724
- return new LocalTime(input);
725
- }
726
- if (typeof input === 'number') {
727
- return this.fromUnix(input);
728
- }
729
- if (!input)
730
- return;
731
- const date = this.parseLooselyOrUndefined(input);
732
- return date ? new LocalTime(date) : undefined;
733
- }
734
- /**
735
- * Performs STRICT parsing.
736
- * Only allows IsoDateTime or IsoDate input, nothing else.
737
- */
738
- fromIsoDateTimeString(s) {
739
- const d = this.parseStrictlyOrUndefined(s);
740
- _assert(d, `Cannot parse "${s}" into LocalTime`);
741
- return new LocalTime(d);
742
- }
743
- /**
744
- * Performs LOOSE parsing.
745
- * Tries to coerce imprefect/incorrect string input into IsoDateTimeString.
746
- * Use with caution.
747
- * Allows to input IsoDate, will set h:m:s to zeros.
748
- */
749
- parse(s) {
750
- const d = this.parseLooselyOrUndefined(String(s));
751
- _assert(d, `Cannot parse "${s}" into LocalTime`);
752
- return new LocalTime(d);
753
- }
754
- parseStrictlyOrUndefined(s) {
755
- if (!s || typeof s !== 'string')
756
- return;
757
- let m = DATE_TIME_REGEX_STRICT.exec(s);
758
- if (!m) {
759
- // DateTime regex didn't match, try just-Date regex
760
- m = DATE_REGEX_STRICT.exec(s);
761
- if (!m)
762
- return;
763
- }
764
- const o = {
765
- year: Number(m[1]),
766
- month: Number(m[2]),
767
- day: Number(m[3]),
768
- hour: Number(m[4]) || 0,
769
- minute: Number(m[5]) || 0,
770
- second: Number(m[6]) || 0,
771
- };
772
- if (!this.isDateTimeObjectValid(o))
773
- return;
774
- return this.createDateFromDateTimeObject(o);
775
- }
776
- parseLooselyOrUndefined(s) {
777
- if (!s || typeof s !== 'string')
778
- return;
779
- const m = DATE_TIME_REGEX_LOOSE.exec(s);
780
- if (!m) {
781
- if (s.length < 8)
782
- return;
783
- // Attempt to parse with Date constructor
784
- const d = new Date(s);
785
- return Number.isNaN(d.getDate()) ? undefined : d;
786
- }
787
- const o = {
788
- year: Number(m[1]),
789
- month: Number(m[2]),
790
- day: Number(m[3]) || 1,
791
- // [4] is skipped due to extra regex parentheses group
792
- hour: Number(m[5]) || 0,
793
- minute: Number(m[6]) || 0,
794
- second: Number(m[7]) || 0,
795
- };
796
- if (!this.isDateTimeObjectValid(o))
797
- return;
798
- return this.createDateFromDateTimeObject(o);
799
- }
800
- /**
801
- * Throws on invalid value.
802
- */
803
- validateDateTimeObject(o) {
804
- _assert(this.isDateTimeObjectValid(o), `Cannot construct LocalTime from: ${o.year}-${o.month}-${o.day} ${o.hour}:${o.minute}:${o.second}`);
805
- }
806
- isDateTimeObjectValid(o) {
807
- return localDate.isDateObjectValid(o) && this.isTimeObjectValid(o);
808
- }
809
- isTimeObjectValid({ hour, minute, second }) {
810
- return hour >= 0 && hour <= 23 && minute >= 0 && minute <= 59 && second >= 0 && second <= 59;
811
- }
812
- fromDate(date) {
813
- _assert(!Number.isNaN(date.getDate()), 'localTime.fromDate is called on Date object that is invalid');
814
- return new LocalTime(date);
815
- }
816
- fromUnix(ts) {
817
- return new LocalTime(new Date(ts * 1000));
818
- }
819
- /**
820
- * Create LocalTime from unixTimestamp in milliseconds (not in seconds).
821
- */
822
- fromMillis(millis) {
823
- return new LocalTime(new Date(millis));
824
- }
825
- fromDateTimeObject(o) {
826
- // todo: validate?
827
- return new LocalTime(this.createDateFromDateTimeObject(o));
828
- }
829
- createDateFromDateTimeObject(o) {
830
- return new Date(o.year, o.month - 1, o.day || 1, o.hour || 0, o.minute || 0, o.second || 0);
831
- }
832
- // private assertNotNull(
833
- // lt: LocalTime | null,
834
- // input: LocalTimeInputNullable,
835
- // ): asserts lt is LocalTime {
836
- // _assert(lt !== null, `Cannot parse "${input}" into LocalTime`, {
837
- // input,
838
- // })
839
- // }
840
- /**
841
- * Returns the IANA timezone e.g `Europe/Stockholm`.
842
- * https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
843
- */
844
- getTimezone() {
845
- return Intl.DateTimeFormat().resolvedOptions().timeZone;
846
- }
847
- /**
848
- * Returns true if passed IANA timezone is valid/supported.
849
- * E.g `Europe/Stockholm` is valid, but `Europe/Stockholm2` is not.
850
- *
851
- * This implementation is not optimized for performance. If you need frequent validation -
852
- * consider caching the Intl.supportedValuesOf values as Set and reuse that.
853
- */
854
- isTimezoneValid(tz) {
855
- if (tz === 'UTC')
856
- return true; // we deliberately consider UTC a valid timezone, while it's mostly used in testing
857
- return Intl.supportedValuesOf('timeZone').includes(tz);
858
- }
859
- sort(items, dir = 'asc', mutate = false) {
860
- const mod = dir === 'desc' ? -1 : 1;
861
- return (mutate ? items : [...items]).sort((a, b) => {
862
- const v1 = a.$date.valueOf();
863
- const v2 = b.$date.valueOf();
864
- if (v1 === v2)
865
- return 0;
866
- return (v1 < v2 ? -1 : 1) * mod;
867
- });
868
- }
869
- minOrUndefined(items) {
870
- let min;
871
- for (const item of items) {
872
- if (!item)
873
- continue;
874
- const lt = this.fromInput(item);
875
- if (!min || lt.$date.valueOf() < min.$date.valueOf()) {
876
- min = lt;
877
- }
878
- }
879
- return min;
880
- }
881
- min(items) {
882
- const min = this.minOrUndefined(items);
883
- _assert(min, 'localTime.min called on empty array');
884
- return min;
885
- }
886
- maxOrUndefined(items) {
887
- let max;
888
- for (const item of items) {
889
- if (!item)
890
- continue;
891
- const lt = this.fromInput(item);
892
- if (!max || lt.$date.valueOf() > max.$date.valueOf()) {
893
- max = lt;
894
- }
895
- }
896
- return max;
897
- }
898
- max(items) {
899
- const max = this.maxOrUndefined(items);
900
- _assert(max, 'localTime.max called on empty array');
901
- return max;
902
- }
903
- }
904
- // based on: https://github.com/date-fns/date-fns/blob/master/src/getISOWeek/index.ts
905
- function getWeek(date) {
906
- const diff = startOfWeek(date).getTime() - startOfWeekYear(date).getTime();
907
- return Math.round(diff / MILLISECONDS_IN_WEEK) + 1;
908
- }
909
- function setWeek(date, week, mutate = false) {
910
- const d = mutate ? date : new Date(date);
911
- const diff = getWeek(d) - week;
912
- d.setDate(d.getDate() - diff * 7);
913
- return d;
914
- }
915
- // based on: https://github.com/date-fns/date-fns/blob/master/src/startOfISOWeekYear/index.ts
916
- function startOfWeekYear(date) {
917
- const year = getWeekYear(date);
918
- const fourthOfJanuary = new Date(0);
919
- fourthOfJanuary.setFullYear(year, 0, 4);
920
- fourthOfJanuary.setHours(0, 0, 0, 0);
921
- return startOfWeek(fourthOfJanuary, true);
922
- }
923
- // based on: https://github.com/date-fns/date-fns/blob/fd6bb1a0bab143f2da068c05a9c562b9bee1357d/src/getISOWeekYear/index.ts
924
- function getWeekYear(date) {
925
- const year = date.getFullYear();
926
- const fourthOfJanuaryOfNextYear = new Date(0);
927
- fourthOfJanuaryOfNextYear.setFullYear(year + 1, 0, 4);
928
- fourthOfJanuaryOfNextYear.setHours(0, 0, 0, 0);
929
- const startOfNextYear = startOfWeek(fourthOfJanuaryOfNextYear, true);
930
- const fourthOfJanuaryOfThisYear = new Date(0);
931
- fourthOfJanuaryOfThisYear.setFullYear(year, 0, 4);
932
- fourthOfJanuaryOfThisYear.setHours(0, 0, 0, 0);
933
- const startOfThisYear = startOfWeek(fourthOfJanuaryOfThisYear, true);
934
- if (date.getTime() >= startOfNextYear.getTime()) {
935
- return year + 1;
936
- }
937
- if (date.getTime() >= startOfThisYear.getTime()) {
938
- return year;
939
- }
940
- return year - 1;
941
- }
942
- // based on: https://github.com/date-fns/date-fns/blob/fd6bb1a0bab143f2da068c05a9c562b9bee1357d/src/startOfWeek/index.ts
943
- function startOfWeek(date, mutate = false) {
944
- const d = mutate ? date : new Date(date);
945
- const day = d.getDay();
946
- const diff = (day < weekStartsOn ? 7 : 0) + day - weekStartsOn;
947
- d.setDate(d.getDate() - diff);
948
- d.setHours(0, 0, 0, 0);
949
- return d;
950
- }
951
- // based on: https://github.com/date-fns/date-fns/blob/master/src/endOfWeek/index.ts
952
- function endOfWeek(date, mutate = false) {
953
- const d = mutate ? date : new Date(date);
954
- const day = d.getDay();
955
- const diff = (day < weekStartsOn ? -7 : 0) + 6 - (day - weekStartsOn);
956
- d.setDate(d.getDate() + diff);
957
- return d;
958
- }
959
- function addMonths(d, num, mutate = false) {
960
- if (!mutate)
961
- d = new Date(d);
962
- let day = d.getDate();
963
- let month = d.getMonth() + 1 + num;
964
- if (day < 29) {
965
- d.setMonth(month - 1);
966
- return d;
967
- }
968
- let year = d.getFullYear();
969
- while (month > 12) {
970
- year++;
971
- month -= 12;
972
- }
973
- while (month < 1) {
974
- year--;
975
- month += 12;
976
- }
977
- const monthLen = localDate.getMonthLength(year, month);
978
- if (day > monthLen)
979
- day = monthLen;
980
- d.setFullYear(year, month - 1, day);
981
- return d;
982
- }
983
- function differenceInMonths(a, b) {
984
- if (a.getDate() < b.getDate())
985
- return -differenceInMonths(b, a);
986
- const wholeMonthDiff = (b.getFullYear() - a.getFullYear()) * 12 + (b.getMonth() - a.getMonth());
987
- const anchor = addMonths(a, wholeMonthDiff).getTime();
988
- const sign = b.getTime() - anchor >= 0 ? 1 : -1;
989
- const anchor2 = addMonths(a, wholeMonthDiff + sign).getTime();
990
- return -(wholeMonthDiff + ((b.getTime() - anchor) / (anchor2 - anchor)) * sign);
991
- }
992
- const localTimeFactory = new LocalTimeFactory();
993
- export const localTime = localTimeFactory.fromInput.bind(localTimeFactory);
994
- // The line below is the blackest of black magic I have ever written in 2024.
995
- // And probably 2023 as well.
996
- Object.setPrototypeOf(localTime, localTimeFactory);