@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.
- package/cfg/frontend/tsconfig.json +3 -3
- package/dist/abort.js +1 -4
- package/dist/array/array.util.d.ts +1 -1
- package/dist/array/array.util.js +47 -88
- package/dist/array/range.d.ts +2 -2
- package/dist/array/range.js +7 -12
- package/dist/bot.js +6 -10
- package/dist/browser/adminService.d.ts +1 -1
- package/dist/browser/adminService.js +10 -14
- package/dist/browser/analytics.util.js +10 -15
- package/dist/browser/i18n/fetchTranslationLoader.d.ts +3 -3
- package/dist/browser/i18n/fetchTranslationLoader.js +1 -5
- package/dist/browser/i18n/translation.service.d.ts +1 -1
- package/dist/browser/i18n/translation.service.js +5 -10
- package/dist/browser/imageFitter.js +1 -5
- package/dist/browser/script.util.js +8 -12
- package/dist/browser/topbar.js +7 -10
- package/dist/datetime/dateInterval.d.ts +2 -2
- package/dist/datetime/dateInterval.js +7 -11
- package/dist/datetime/localDate.d.ts +3 -3
- package/dist/datetime/localDate.js +40 -44
- package/dist/datetime/localTime.d.ts +3 -3
- package/dist/datetime/localTime.js +36 -40
- package/dist/datetime/timeInterval.d.ts +2 -2
- package/dist/datetime/timeInterval.js +6 -10
- package/dist/datetime/wallTime.d.ts +3 -3
- package/dist/datetime/wallTime.js +5 -9
- package/dist/decorators/asyncMemo.decorator.d.ts +3 -3
- package/dist/decorators/asyncMemo.decorator.js +12 -17
- package/dist/decorators/createPromiseDecorator.js +3 -6
- package/dist/decorators/debounce.d.ts +1 -1
- package/dist/decorators/debounce.decorator.d.ts +1 -1
- package/dist/decorators/debounce.decorator.js +5 -9
- package/dist/decorators/debounce.js +2 -6
- package/dist/decorators/decorator.util.d.ts +1 -1
- package/dist/decorators/decorator.util.js +3 -8
- package/dist/decorators/logMethod.decorator.d.ts +1 -1
- package/dist/decorators/logMethod.decorator.js +11 -14
- package/dist/decorators/memo.decorator.d.ts +3 -3
- package/dist/decorators/memo.decorator.js +11 -16
- package/dist/decorators/memo.util.d.ts +2 -2
- package/dist/decorators/memo.util.js +11 -17
- package/dist/decorators/memoFn.d.ts +3 -3
- package/dist/decorators/memoFn.js +3 -6
- package/dist/decorators/memoFnAsync.d.ts +3 -3
- package/dist/decorators/memoFnAsync.js +5 -8
- package/dist/decorators/memoSimple.decorator.d.ts +1 -1
- package/dist/decorators/memoSimple.decorator.js +6 -10
- package/dist/decorators/retry.decorator.d.ts +1 -1
- package/dist/decorators/retry.decorator.js +3 -6
- package/dist/decorators/swarmSafe.decorator.js +3 -7
- package/dist/decorators/timeout.decorator.d.ts +1 -1
- package/dist/decorators/timeout.decorator.js +7 -10
- package/dist/define.d.ts +1 -1
- package/dist/define.js +11 -19
- package/dist/deviceIdService.js +7 -11
- package/dist/enum.util.d.ts +1 -1
- package/dist/enum.util.js +20 -42
- package/dist/env/buildInfo.d.ts +1 -1
- package/dist/env/buildInfo.js +3 -6
- package/dist/env.js +2 -6
- package/dist/error/assert.d.ts +3 -3
- package/dist/error/assert.js +30 -44
- package/dist/error/error.model.d.ts +2 -2
- package/dist/error/error.model.js +1 -2
- package/dist/error/error.util.d.ts +1 -1
- package/dist/error/error.util.js +25 -44
- package/dist/error/errorMode.js +2 -5
- package/dist/error/try.d.ts +2 -2
- package/dist/error/try.js +15 -23
- package/dist/error/tryCatch.d.ts +2 -2
- package/dist/error/tryCatch.js +6 -11
- package/dist/form.util.d.ts +1 -1
- package/dist/form.util.js +2 -6
- package/dist/http/fetcher.d.ts +3 -3
- package/dist/http/fetcher.js +48 -53
- package/dist/http/fetcher.model.d.ts +5 -5
- package/dist/http/fetcher.model.js +1 -2
- package/dist/http/http.model.js +1 -4
- package/dist/index.d.ts +96 -96
- package/dist/index.js +96 -99
- package/dist/is.util.d.ts +2 -2
- package/dist/is.util.js +12 -27
- package/dist/iter/asyncIterable2.d.ts +3 -3
- package/dist/iter/asyncIterable2.js +8 -12
- package/dist/iter/iterable2.d.ts +2 -2
- package/dist/iter/iterable2.js +8 -12
- package/dist/json-schema/from-data/generateJsonSchemaFromData.d.ts +1 -1
- package/dist/json-schema/from-data/generateJsonSchemaFromData.js +4 -7
- package/dist/json-schema/jsonSchema.cnst.d.ts +1 -1
- package/dist/json-schema/jsonSchema.cnst.js +1 -4
- package/dist/json-schema/jsonSchema.model.d.ts +1 -1
- package/dist/json-schema/jsonSchema.model.js +1 -2
- package/dist/json-schema/jsonSchema.util.d.ts +2 -2
- package/dist/json-schema/jsonSchema.util.js +5 -8
- package/dist/json-schema/jsonSchemaBuilder.d.ts +2 -2
- package/dist/json-schema/jsonSchemaBuilder.js +16 -25
- package/dist/json-schema/jsonSchemas.d.ts +2 -2
- package/dist/json-schema/jsonSchemas.js +5 -8
- package/dist/log/commonLogger.js +14 -21
- package/dist/math/accumulatingAverage.js +1 -5
- package/dist/math/math.util.js +11 -19
- package/dist/math/sma.js +1 -5
- package/dist/math/stack.util.js +11 -16
- package/dist/nanoid.js +2 -6
- package/dist/number/createDeterministicRandom.js +1 -4
- package/dist/number/number.util.d.ts +1 -1
- package/dist/number/number.util.js +9 -20
- package/dist/object/deepEquals.js +3 -8
- package/dist/object/map2.js +1 -5
- package/dist/object/object.util.d.ts +2 -2
- package/dist/object/object.util.js +40 -70
- package/dist/object/set2.js +1 -5
- package/dist/object/sortObject.d.ts +1 -1
- package/dist/object/sortObject.js +1 -4
- package/dist/object/sortObjectDeep.js +1 -4
- package/dist/polyfill.js +1 -4
- package/dist/promise/abortable.d.ts +1 -1
- package/dist/promise/abortable.js +2 -7
- package/dist/promise/pDefer.js +1 -4
- package/dist/promise/pDelay.d.ts +2 -2
- package/dist/promise/pDelay.js +4 -8
- package/dist/promise/pFilter.d.ts +1 -1
- package/dist/promise/pFilter.js +1 -4
- package/dist/promise/pHang.js +1 -4
- package/dist/promise/pMap.d.ts +2 -2
- package/dist/promise/pMap.js +17 -20
- package/dist/promise/pProps.js +1 -4
- package/dist/promise/pQueue.d.ts +2 -2
- package/dist/promise/pQueue.js +7 -11
- package/dist/promise/pRetry.d.ts +1 -1
- package/dist/promise/pRetry.js +8 -12
- package/dist/promise/pState.js +1 -4
- package/dist/promise/pTimeout.d.ts +3 -3
- package/dist/promise/pTimeout.js +7 -11
- package/dist/semver.d.ts +1 -1
- package/dist/semver.js +13 -18
- package/dist/string/case.js +9 -14
- package/dist/string/escape.js +2 -6
- package/dist/string/hash.util.d.ts +1 -1
- package/dist/string/hash.util.js +4 -10
- package/dist/string/json.util.d.ts +1 -1
- package/dist/string/json.util.js +5 -10
- package/dist/string/leven.js +1 -4
- package/dist/string/lodash/unicodeWords.js +1 -4
- package/dist/string/lodash/words.js +3 -6
- package/dist/string/pupa.d.ts +1 -1
- package/dist/string/pupa.js +4 -9
- package/dist/string/readingTime.d.ts +1 -1
- package/dist/string/readingTime.js +1 -4
- package/dist/string/regex.js +1 -4
- package/dist/string/safeJsonStringify.d.ts +1 -1
- package/dist/string/safeJsonStringify.js +1 -4
- package/dist/string/slugify.js +1 -4
- package/dist/string/string.util.js +15 -32
- package/dist/string/stringify.d.ts +1 -1
- package/dist/string/stringify.js +10 -14
- package/dist/string/url.util.d.ts +1 -1
- package/dist/string/url.util.js +2 -6
- package/dist/time/time.util.d.ts +1 -1
- package/dist/time/time.util.js +3 -8
- package/dist/typeFest.js +1 -2
- package/dist/types.d.ts +7 -3
- package/dist/types.js +21 -23
- package/dist/unit/size.util.js +5 -12
- package/dist/web.d.ts +1 -1
- package/dist/web.js +1 -5
- package/dist/zod/index.d.ts +2 -2
- package/dist/zod/index.js +4 -10
- package/dist/zod/zod.shared.schemas.js +36 -39
- package/dist/zod/zod.util.js +7 -14
- package/package.json +7 -8
- package/src/array/array.util.ts +3 -3
- package/src/array/range.ts +2 -2
- package/src/bot.ts +1 -1
- package/src/browser/adminService.ts +4 -4
- package/src/browser/analytics.util.ts +1 -1
- package/src/browser/i18n/fetchTranslationLoader.ts +3 -3
- package/src/browser/i18n/translation.service.ts +2 -2
- package/src/browser/script.util.ts +2 -2
- package/src/datetime/dateInterval.ts +3 -3
- package/src/datetime/localDate.ts +5 -5
- package/src/datetime/localTime.ts +6 -6
- package/src/datetime/timeInterval.ts +3 -3
- package/src/datetime/wallTime.ts +4 -4
- package/src/decorators/asyncMemo.decorator.ts +7 -7
- package/src/decorators/createPromiseDecorator.ts +1 -1
- package/src/decorators/debounce.decorator.ts +2 -2
- package/src/decorators/debounce.ts +1 -1
- package/src/decorators/decorator.util.ts +1 -1
- package/src/decorators/logMethod.decorator.ts +4 -4
- package/src/decorators/memo.decorator.ts +7 -7
- package/src/decorators/memo.util.ts +4 -4
- package/src/decorators/memoFn.ts +4 -4
- package/src/decorators/memoFnAsync.ts +5 -5
- package/src/decorators/memoSimple.decorator.ts +4 -4
- package/src/decorators/retry.decorator.ts +2 -2
- package/src/decorators/swarmSafe.decorator.ts +2 -2
- package/src/decorators/timeout.decorator.ts +4 -4
- package/src/define.ts +3 -3
- package/src/deviceIdService.ts +3 -3
- package/src/enum.util.ts +1 -1
- package/src/env/buildInfo.ts +2 -2
- package/src/error/assert.ts +7 -7
- package/src/error/error.model.ts +2 -2
- package/src/error/error.util.ts +5 -5
- package/src/error/try.ts +5 -5
- package/src/error/tryCatch.ts +3 -3
- package/src/form.util.ts +1 -1
- package/src/http/fetcher.model.ts +5 -5
- package/src/http/fetcher.ts +20 -15
- package/src/index.ts +96 -96
- package/src/is.util.ts +2 -2
- package/src/iter/asyncIterable2.ts +3 -3
- package/src/iter/iterable2.ts +2 -2
- package/src/json-schema/from-data/generateJsonSchemaFromData.ts +2 -2
- package/src/json-schema/jsonSchema.cnst.ts +1 -1
- package/src/json-schema/jsonSchema.model.ts +1 -1
- package/src/json-schema/jsonSchema.util.ts +4 -4
- package/src/json-schema/jsonSchemaBuilder.ts +5 -5
- package/src/json-schema/jsonSchemas.ts +2 -2
- package/src/math/math.util.ts +2 -2
- package/src/math/stack.util.ts +1 -1
- package/src/number/number.util.ts +1 -1
- package/src/object/object.util.ts +3 -3
- package/src/object/sortObject.ts +1 -1
- package/src/promise/abortable.ts +1 -1
- package/src/promise/pDelay.ts +3 -3
- package/src/promise/pFilter.ts +1 -1
- package/src/promise/pMap.ts +2 -2
- package/src/promise/pQueue.ts +4 -4
- package/src/promise/pRetry.ts +2 -2
- package/src/promise/pTimeout.ts +4 -4
- package/src/semver.ts +3 -3
- package/src/string/case.ts +2 -2
- package/src/string/hash.util.ts +1 -1
- package/src/string/json.util.ts +2 -2
- package/src/string/lodash/words.ts +1 -1
- package/src/string/pupa.ts +2 -2
- package/src/string/readingTime.ts +1 -1
- package/src/string/safeJsonStringify.ts +1 -1
- package/src/string/stringify.ts +4 -4
- package/src/string/url.util.ts +1 -1
- package/src/time/time.util.ts +1 -1
- package/src/types.ts +15 -3
- package/src/web.ts +1 -1
- package/src/zod/index.ts +2 -2
- package/src/zod/zod.util.ts +1 -1
- package/dist-esm/abort.js +0 -12
- package/dist-esm/array/array.util.js +0 -458
- package/dist-esm/array/range.js +0 -34
- package/dist-esm/bot.js +0 -130
- package/dist-esm/browser/adminService.js +0 -94
- package/dist-esm/browser/analytics.util.js +0 -54
- package/dist-esm/browser/i18n/fetchTranslationLoader.js +0 -13
- package/dist-esm/browser/i18n/translation.service.js +0 -56
- package/dist-esm/browser/imageFitter.js +0 -65
- package/dist-esm/browser/script.util.js +0 -46
- package/dist-esm/browser/topbar.js +0 -135
- package/dist-esm/datetime/dateInterval.js +0 -80
- package/dist-esm/datetime/localDate.js +0 -719
- package/dist-esm/datetime/localTime.js +0 -996
- package/dist-esm/datetime/timeInterval.js +0 -88
- package/dist-esm/datetime/wallTime.js +0 -70
- package/dist-esm/decorators/asyncMemo.decorator.js +0 -111
- package/dist-esm/decorators/createPromiseDecorator.js +0 -82
- package/dist-esm/decorators/debounce.decorator.js +0 -17
- package/dist-esm/decorators/debounce.js +0 -114
- package/dist-esm/decorators/decorator.util.js +0 -31
- package/dist-esm/decorators/logMethod.decorator.js +0 -85
- package/dist-esm/decorators/memo.decorator.js +0 -80
- package/dist-esm/decorators/memo.util.js +0 -97
- package/dist-esm/decorators/memoFn.js +0 -29
- package/dist-esm/decorators/memoFnAsync.js +0 -35
- package/dist-esm/decorators/memoSimple.decorator.js +0 -55
- package/dist-esm/decorators/retry.decorator.js +0 -9
- package/dist-esm/decorators/swarmSafe.decorator.js +0 -38
- package/dist-esm/decorators/timeout.decorator.js +0 -19
- package/dist-esm/define.js +0 -109
- package/dist-esm/deviceIdService.js +0 -105
- package/dist-esm/enum.util.js +0 -157
- package/dist-esm/env/buildInfo.js +0 -19
- package/dist-esm/env.js +0 -19
- package/dist-esm/error/assert.js +0 -122
- package/dist-esm/error/error.model.js +0 -1
- package/dist-esm/error/error.util.js +0 -337
- package/dist-esm/error/errorMode.js +0 -20
- package/dist-esm/error/try.js +0 -105
- package/dist-esm/error/tryCatch.js +0 -41
- package/dist-esm/form.util.js +0 -16
- package/dist-esm/http/fetcher.js +0 -704
- package/dist-esm/http/fetcher.model.js +0 -3
- package/dist-esm/http/http.model.js +0 -1
- package/dist-esm/index.js +0 -96
- package/dist-esm/is.util.js +0 -70
- package/dist-esm/iter/asyncIterable2.js +0 -103
- package/dist-esm/iter/iterable2.js +0 -87
- package/dist-esm/json-schema/from-data/generateJsonSchemaFromData.js +0 -86
- package/dist-esm/json-schema/jsonSchema.cnst.js +0 -38
- package/dist-esm/json-schema/jsonSchema.model.js +0 -1
- package/dist-esm/json-schema/jsonSchema.util.js +0 -27
- package/dist-esm/json-schema/jsonSchemaBuilder.js +0 -352
- package/dist-esm/json-schema/jsonSchemas.js +0 -6
- package/dist-esm/log/commonLogger.js +0 -78
- package/dist-esm/math/accumulatingAverage.js +0 -32
- package/dist-esm/math/math.util.js +0 -85
- package/dist-esm/math/sma.js +0 -43
- package/dist-esm/math/stack.util.js +0 -82
- package/dist-esm/nanoid.js +0 -57
- package/dist-esm/number/createDeterministicRandom.js +0 -18
- package/dist-esm/number/number.util.js +0 -109
- package/dist-esm/object/deepEquals.js +0 -170
- package/dist-esm/object/map2.js +0 -21
- package/dist-esm/object/object.util.js +0 -435
- package/dist-esm/object/set2.js +0 -15
- package/dist-esm/object/sortObject.js +0 -21
- package/dist-esm/object/sortObjectDeep.js +0 -17
- package/dist-esm/polyfill.js +0 -6
- package/dist-esm/promise/abortable.js +0 -31
- package/dist-esm/promise/pDefer.js +0 -17
- package/dist-esm/promise/pDelay.js +0 -37
- package/dist-esm/promise/pFilter.js +0 -5
- package/dist-esm/promise/pHang.js +0 -6
- package/dist-esm/promise/pMap.js +0 -174
- package/dist-esm/promise/pProps.js +0 -20
- package/dist-esm/promise/pQueue.js +0 -101
- package/dist-esm/promise/pRetry.js +0 -64
- package/dist-esm/promise/pState.js +0 -14
- package/dist-esm/promise/pTimeout.js +0 -64
- package/dist-esm/semver.js +0 -149
- package/dist-esm/string/case.js +0 -24
- package/dist-esm/string/escape.js +0 -49
- package/dist-esm/string/hash.util.js +0 -67
- package/dist-esm/string/json.util.js +0 -46
- package/dist-esm/string/leven.js +0 -77
- package/dist-esm/string/lodash/unicodeWords.js +0 -68
- package/dist-esm/string/lodash/words.js +0 -31
- package/dist-esm/string/pupa.js +0 -54
- package/dist-esm/string/readingTime.js +0 -102
- package/dist-esm/string/regex.js +0 -6
- package/dist-esm/string/safeJsonStringify.js +0 -39
- package/dist-esm/string/slugify.js +0 -66
- package/dist-esm/string/string.util.js +0 -99
- package/dist-esm/string/stringify.js +0 -133
- package/dist-esm/string/url.util.js +0 -42
- package/dist-esm/time/time.util.js +0 -61
- package/dist-esm/typeFest.js +0 -2
- package/dist-esm/types.js +0 -59
- package/dist-esm/unit/size.util.js +0 -43
- package/dist-esm/web.js +0 -40
- package/dist-esm/zod/index.js +0 -4
- package/dist-esm/zod/zod.shared.schemas.js +0 -92
- 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);
|