@thi.ng/date 2.5.5 → 2.5.6

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/i18n.js CHANGED
@@ -1,124 +1,53 @@
1
1
  import { isString } from "@thi.ng/checks/is-string";
2
2
  import { EN_SHORT } from "./i18n/en.js";
3
3
  const prepLocale = (spec) => {
4
- const locale = {
5
- sepED: " ",
6
- sepDM: "/",
7
- sepMY: "/",
8
- sepHM: ":",
9
- date: ["E", "/ED", "d", "/DM", "MMM", "/MY", "yyyy"],
10
- time: ["H", "/HM", "mm"],
11
- ...spec,
12
- };
13
- !locale.dateTime &&
14
- (locale.dateTime = [...locale.date, ", ", ...locale.time]);
15
- return locale;
4
+ const locale = {
5
+ sepED: " ",
6
+ sepDM: "/",
7
+ sepMY: "/",
8
+ sepHM: ":",
9
+ date: ["E", "/ED", "d", "/DM", "MMM", "/MY", "yyyy"],
10
+ time: ["H", "/HM", "mm"],
11
+ ...spec
12
+ };
13
+ !locale.dateTime && (locale.dateTime = [...locale.date, ", ", ...locale.time]);
14
+ return locale;
16
15
  };
17
- /**
18
- * Sets {@link LOCALE} for formatting and fills in missing default values.
19
- * Unless called explicitly, the package uses {@link EN_SHORT} by default.
20
- *
21
- * @param locale -
22
- */
23
- export const setLocale = (locale) => (LOCALE = prepLocale(locale));
24
- /**
25
- * Executes given `fn` with temporarily active `locale`. Returns result of `fn`.
26
- *
27
- * @remarks
28
- * `fn` will be called within a try/catch block and the previous locale will be
29
- * restored even if `fn` throws an error.
30
- *
31
- * @param locale -
32
- * @param fn -
33
- */
34
- export const withLocale = (locale, fn) => {
35
- const old = LOCALE;
36
- setLocale(locale);
37
- try {
38
- const res = fn();
39
- setLocale(old);
40
- return res;
41
- }
42
- catch (e) {
43
- setLocale(old);
44
- throw e;
45
- }
16
+ const setLocale = (locale) => LOCALE = prepLocale(locale);
17
+ const withLocale = (locale, fn) => {
18
+ const old = LOCALE;
19
+ setLocale(locale);
20
+ try {
21
+ const res = fn();
22
+ setLocale(old);
23
+ return res;
24
+ } catch (e) {
25
+ setLocale(old);
26
+ throw e;
27
+ }
46
28
  };
47
- export let LOCALE = prepLocale(EN_SHORT);
48
- /**
49
- * Returns a copy of current {@link LOCALE}'s weekday names array.
50
- */
51
- export const weekdayNames = () => LOCALE.days.slice();
52
- /**
53
- * Returns a copy of current {@link LOCALE}'s month names array.
54
- */
55
- export const monthNames = () => LOCALE.months.slice();
56
- /**
57
- * Returns a suitable version of requested `unit` from current {@link LOCALE},
58
- * based on quantity `x` and optional dativ grammar form. If `unitsOnly` is true
59
- * (default false) only the unit (w/o quantity) will be returned.
60
- *
61
- * @remarks
62
- * Also see {@link unitsLessThan}, {@link formatRelative},
63
- * {@link formatRelativeParts}.
64
- *
65
- * @example
66
- * ```ts
67
- * withLocale(FR_LONG, () => units(1, "y"));
68
- * // "1 année"
69
- *
70
- * withLocale(FR_LONG, () => units(1, "y", true));
71
- * // "1 an"
72
- *
73
- * withLocale(FR_LONG, () => units(2, "y"));
74
- * // "2 ans"
75
- *
76
- * withLocale(FR_LONG, () => units(2, "y", true));
77
- * // "2 ans"
78
- *
79
- * withLocale(DE_LONG, () => units(2, "y"));
80
- * // "2 Jahre"
81
- *
82
- * withLocale(DE_LONG, () => units(2, "y", true));
83
- * // "2 Jahren"
84
- * ```
85
- *
86
- * @param x -
87
- * @param unit -
88
- * @param isDativ -
89
- * @param unitsOnly -
90
- */
91
- export const units = (x, unit, isDativ = false, unitsOnly = false) => {
92
- unit = isString(unit) ? LOCALE.units[unit] : unit;
93
- const res = x > 1 || x === 0
94
- ? isDativ
95
- ? unit.pd || unit.p
96
- : unit.p
97
- : isDativ
98
- ? unit.sd || unit.s
99
- : unit.s;
100
- return unitsOnly ? res : `${x} ${res}`;
29
+ let LOCALE = prepLocale(EN_SHORT);
30
+ const weekdayNames = () => LOCALE.days.slice();
31
+ const monthNames = () => LOCALE.months.slice();
32
+ const units = (x, unit, isDativ = false, unitsOnly = false) => {
33
+ unit = isString(unit) ? LOCALE.units[unit] : unit;
34
+ const res = x > 1 || x === 0 ? isDativ ? unit.pd || unit.p : unit.p : isDativ ? unit.sd || unit.s : unit.s;
35
+ return unitsOnly ? res : `${x} ${res}`;
36
+ };
37
+ const unitsLessThan = (x, unit, isDativ = false) => `${LOCALE.less.replace("%s", String(x))} ${units(
38
+ Math.max(x, 1),
39
+ unit,
40
+ isDativ,
41
+ true
42
+ )}`;
43
+ const tense = (sign, res) => (sign < 0 ? LOCALE.past : LOCALE.future).replace("%s", res);
44
+ export {
45
+ LOCALE,
46
+ monthNames,
47
+ setLocale,
48
+ tense,
49
+ units,
50
+ unitsLessThan,
51
+ weekdayNames,
52
+ withLocale
101
53
  };
102
- /**
103
- * Similar to {@link units}, but for cases to express/format the phrase `less
104
- * than {x} {unit(s)}`.
105
- *
106
- * @example
107
- * ```ts
108
- * withLocale(DE_LONG, () => unitsLessThan(1, "y"));
109
- * // "weniger als 1 Jahr"
110
- * ```
111
- *
112
- * @param x -
113
- * @param unit -
114
- * @param isDativ -
115
- */
116
- export const unitsLessThan = (x, unit, isDativ = false) => `${LOCALE.less.replace("%s", String(x))} ${units(Math.max(x, 1), unit, isDativ, true)}`;
117
- /**
118
- * Wraps given (presumably localized) string in current {@link LOCALE}'s `past`
119
- * or `future` phrases, depending on given `sign`.
120
- *
121
- * @param sign -
122
- * @param res -
123
- */
124
- export const tense = (sign, res) => (sign < 0 ? LOCALE.past : LOCALE.future).replace("%s", res);
@@ -1,16 +1,6 @@
1
- /**
2
- * Converts a {@link Precision} into a numeric ID.
3
- *
4
- * @param prec -
5
- *
6
- * @internal
7
- */
8
- export const __precisionToID = (prec) => "yMdhmst".indexOf(prec);
9
- /**
10
- * Inverse op of {@link __precisionToID}.
11
- *
12
- * @param id -
13
- *
14
- * @internal
15
- */
16
- export const __idToPrecision = (id) => "yMdhmst".charAt(id);
1
+ const __precisionToID = (prec) => "yMdhmst".indexOf(prec);
2
+ const __idToPrecision = (id) => "yMdhmst".charAt(id);
3
+ export {
4
+ __idToPrecision,
5
+ __precisionToID
6
+ };
package/iterators.js CHANGED
@@ -1,97 +1,45 @@
1
1
  import { isString } from "@thi.ng/checks/is-string";
2
2
  import { DateTime } from "./datetime.js";
3
3
  import { floorQuarter, floorWeek } from "./round.js";
4
- /**
5
- * Higher-order epoch iterator factory. Returns iterator with configured
6
- * precision and `tick` fn.
7
- *
8
- * @param prec -
9
- * @param tick -
10
- */
11
- export const defIterator = (prec, tick) => {
12
- return function* (...xs) {
13
- let [from, to] = (xs.length > 1 ? xs : xs[0]).map((x) => new DateTime(x).getTime());
14
- let state = isString(prec) ? new DateTime(from, prec) : prec(from);
15
- let epoch = from;
16
- while (epoch < to) {
17
- epoch = state.getTime();
18
- if (epoch >= from && epoch < to)
19
- yield epoch;
20
- tick(state);
21
- }
22
- };
4
+ const defIterator = (prec, tick) => {
5
+ return function* (...xs) {
6
+ let [from, to] = (xs.length > 1 ? xs : xs[0]).map(
7
+ (x) => new DateTime(x).getTime()
8
+ );
9
+ let state = isString(prec) ? new DateTime(from, prec) : prec(from);
10
+ let epoch = from;
11
+ while (epoch < to) {
12
+ epoch = state.getTime();
13
+ if (epoch >= from && epoch < to)
14
+ yield epoch;
15
+ tick(state);
16
+ }
17
+ };
18
+ };
19
+ const years = defIterator("y", (d) => d.incYear());
20
+ const quarters = defIterator(
21
+ (from) => new DateTime(floorQuarter(from)),
22
+ (d) => d.incQuarter()
23
+ );
24
+ const months = defIterator("M", (d) => d.incMonth());
25
+ const weeks = defIterator(
26
+ (from) => new DateTime(floorWeek(from)),
27
+ (d) => d.incWeek()
28
+ );
29
+ const days = defIterator("d", (d) => d.incDay());
30
+ const hours = defIterator("h", (d) => d.incHour());
31
+ const minutes = defIterator("m", (d) => d.incMinute());
32
+ const seconds = defIterator("s", (d) => d.incSecond());
33
+ const milliseconds = defIterator("t", (d) => d.incMillisecond());
34
+ export {
35
+ days,
36
+ defIterator,
37
+ hours,
38
+ milliseconds,
39
+ minutes,
40
+ months,
41
+ quarters,
42
+ seconds,
43
+ weeks,
44
+ years
23
45
  };
24
- /**
25
- * Yields iterator of UTC timestamps in given semi-open interval in yearly
26
- * precision (each timestamp is at beginning of each year).
27
- *
28
- * @param from -
29
- * @param to -
30
- */
31
- export const years = defIterator("y", (d) => d.incYear());
32
- /**
33
- * Yields iterator of UTC timestamps in given semi-open interval in monthly
34
- * precision (each timestamp is at beginning of a month), but spaced at 3 month
35
- * intervals.
36
- *
37
- * @param from -
38
- * @param to -
39
- */
40
- export const quarters = defIterator((from) => new DateTime(floorQuarter(from)), (d) => d.incQuarter());
41
- /**
42
- * Yields iterator of UTC timestamps in given semi-open interval in monthly
43
- * precision (each timestamp is at beginning of each month).
44
- *
45
- * @param from -
46
- * @param to -
47
- */
48
- export const months = defIterator("M", (d) => d.incMonth());
49
- /**
50
- * Yields iterator of UTC timestamps in given semi-open interval in daily
51
- * precision (each timestamp is 7 days apart). As per ISO8601, weeks start on
52
- * Mondays.
53
- *
54
- * @param from -
55
- * @param to -
56
- */
57
- export const weeks = defIterator((from) => new DateTime(floorWeek(from)), (d) => d.incWeek());
58
- /**
59
- * Yields iterator of UTC timestamps in given semi-open interval in daily
60
- * precision (each timestamp is at midnight/beginning of each day).
61
- *
62
- * @param from -
63
- * @param to -
64
- */
65
- export const days = defIterator("d", (d) => d.incDay());
66
- /**
67
- * Yields iterator of UTC timestamps in given semi-open interval in hourly
68
- * precision.
69
- *
70
- * @param from -
71
- * @param to -
72
- */
73
- export const hours = defIterator("h", (d) => d.incHour());
74
- /**
75
- * Yields iterator of UTC timestamps in given semi-open interval in minute
76
- * precision.
77
- *
78
- * @param from -
79
- * @param to -
80
- */
81
- export const minutes = defIterator("m", (d) => d.incMinute());
82
- /**
83
- * Yields iterator of UTC timestamps in given semi-open interval in second
84
- * precision.
85
- *
86
- * @param from -
87
- * @param to -
88
- */
89
- export const seconds = defIterator("s", (d) => d.incSecond());
90
- /**
91
- * Yields iterator of UTC timestamps in given semi-open interval in millisecond
92
- * precision.
93
- *
94
- * @param from -
95
- * @param to -
96
- */
97
- export const milliseconds = defIterator("t", (d) => d.incMillisecond());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thi.ng/date",
3
- "version": "2.5.5",
3
+ "version": "2.5.6",
4
4
  "description": "Datetime types, relative dates, math, iterators, composable formatters, locales",
5
5
  "type": "module",
6
6
  "module": "./index.js",
@@ -24,7 +24,9 @@
24
24
  "author": "Karsten Schmidt (https://thi.ng)",
25
25
  "license": "Apache-2.0",
26
26
  "scripts": {
27
- "build": "yarn clean && tsc --declaration",
27
+ "build": "yarn build:esbuild && yarn build:decl",
28
+ "build:decl": "tsc --declaration --emitDeclarationOnly",
29
+ "build:esbuild": "esbuild --format=esm --platform=neutral --target=es2022 --tsconfig=tsconfig.json --outdir=. src/**/*.ts",
28
30
  "clean": "rimraf --glob '*.js' '*.d.ts' '*.map' doc internal i18n",
29
31
  "doc": "typedoc --excludePrivate --excludeInternal --out doc src/index.ts",
30
32
  "doc:ae": "mkdir -p .ae/doc .ae/temp && api-extractor run --local --verbose",
@@ -33,12 +35,13 @@
33
35
  "test": "bun test"
34
36
  },
35
37
  "dependencies": {
36
- "@thi.ng/api": "^8.9.11",
37
- "@thi.ng/checks": "^3.4.11",
38
- "@thi.ng/strings": "^3.7.2"
38
+ "@thi.ng/api": "^8.9.12",
39
+ "@thi.ng/checks": "^3.4.12",
40
+ "@thi.ng/strings": "^3.7.3"
39
41
  },
40
42
  "devDependencies": {
41
43
  "@microsoft/api-extractor": "^7.38.3",
44
+ "esbuild": "^0.19.8",
42
45
  "rimraf": "^5.0.5",
43
46
  "tools": "^0.0.1",
44
47
  "typedoc": "^0.25.4",
@@ -130,5 +133,5 @@
130
133
  "thi.ng": {
131
134
  "year": 2020
132
135
  },
133
- "gitHead": "25f2ac8ff795a432a930119661b364d4d93b59a0\n"
136
+ "gitHead": "5e7bafedfc3d53bc131469a28de31dd8e5b4a3ff\n"
134
137
  }
package/relative.js CHANGED
@@ -1,178 +1,118 @@
1
- import { DAY, HOUR, MINUTE, SECOND, } from "./api.js";
1
+ import {
2
+ DAY,
3
+ HOUR,
4
+ MINUTE,
5
+ SECOND
6
+ } from "./api.js";
2
7
  import { ensureEpoch } from "./checks.js";
3
8
  import { dateTime, ensureDateTime } from "./datetime.js";
4
9
  import { EN_LONG, EN_SHORT } from "./i18n/en.js";
5
- /**
6
- * Takes a relative time `offset` string in plain english and an optional `base`
7
- * date (default: now). Parses `offset` and returns new date with relative
8
- * offset applied. Returns `undefined` if parsing failed.
9
- *
10
- * @remarks
11
- * This function only handles the parsing and input normalization aspect for
12
- * {@link relative}. The latter function applies the actual offset.
13
- *
14
- * The following input formats are supported:
15
- *
16
- * - `"tomorrow"` / `"yesterday"` - ±1 day
17
- * - any weekday names in {@link EN_SHORT} and {@link EN_LONG} (always in future)
18
- * - `<"-"|"+">?<num><period><" ago">?"` - ±num periods (if prefixed with "-" or
19
- * if the `" ago"` suffix is given, the offset will be applied towards the
20
- * past)
21
- *
22
- * (Note: If both negative offset and "ago" is given, the suffix will, like a
23
- * double-negative, flip the direction back towards the future).
24
- *
25
- * If using the latter form:
26
- *
27
- * - `<num>` can be a positve integer or strings: `"next "`, `"a "` or `"an "`
28
- * - `<period>` can be:
29
- * - `ms` / `millis` / `millisecond` / `milliseconds`
30
- * - `s` / `sec` / `secs` / `second` / `seconds`
31
- * - `min` / `mins` / `minute` / `minutes`
32
- * - `h` / `hour` / `hours`
33
- * - `d` / `day` / `days`
34
- * - `w` / `week` / `weeks`
35
- * - `mo` / `month` / `months`
36
- * - `q` / `quarter` / `quarters`
37
- * - `y` / `year` / `years`
38
- *
39
- * @param offset -
40
- * @param base -
41
- */
42
- export const parseRelative = (offset, base) => {
43
- offset = offset.toLowerCase();
44
- const epoch = dateTime(base);
45
- switch (offset) {
46
- case "today":
47
- return epoch;
48
- case "tomorrow":
49
- epoch.incDay();
50
- return epoch;
51
- case "yesterday":
52
- epoch.decDay();
53
- return epoch;
54
- default: {
55
- let idx = findIndex(EN_SHORT.days, offset);
56
- if (idx < 0) {
57
- idx = findIndex(EN_LONG.days, offset);
58
- }
59
- if (idx >= 0) {
60
- do {
61
- epoch.incDay();
62
- } while (epoch.toDate().getDay() != idx);
63
- return epoch;
64
- }
65
- const match = /^(an? |next |[-+]?\d+\s?)((ms|milli(?:(s?|seconds?)))|s(?:(ecs?|econds?))?|min(?:(s|utes?))?|h(?:ours?)?|d(?:ays?)?|w(?:eeks?)?|mo(?:nths?)?|q(?:uarters?)?|y(?:ears?)?)(\s+ago)?$/.exec(offset);
66
- return match
67
- ? relative(parseNum(match[1], !!match[7]), parsePeriod(match[2]), base)
68
- : undefined;
69
- }
10
+ const parseRelative = (offset, base) => {
11
+ offset = offset.toLowerCase();
12
+ const epoch = dateTime(base);
13
+ switch (offset) {
14
+ case "today":
15
+ return epoch;
16
+ case "tomorrow":
17
+ epoch.incDay();
18
+ return epoch;
19
+ case "yesterday":
20
+ epoch.decDay();
21
+ return epoch;
22
+ default: {
23
+ let idx = findIndex(EN_SHORT.days, offset);
24
+ if (idx < 0) {
25
+ idx = findIndex(EN_LONG.days, offset);
26
+ }
27
+ if (idx >= 0) {
28
+ do {
29
+ epoch.incDay();
30
+ } while (epoch.toDate().getDay() != idx);
31
+ return epoch;
32
+ }
33
+ const match = /^(an? |next |[-+]?\d+\s?)((ms|milli(?:(s?|seconds?)))|s(?:(ecs?|econds?))?|min(?:(s|utes?))?|h(?:ours?)?|d(?:ays?)?|w(?:eeks?)?|mo(?:nths?)?|q(?:uarters?)?|y(?:ears?)?)(\s+ago)?$/.exec(
34
+ offset
35
+ );
36
+ return match ? relative(
37
+ parseNum(match[1], !!match[7]),
38
+ parsePeriod(match[2]),
39
+ base
40
+ ) : void 0;
70
41
  }
42
+ }
71
43
  };
72
44
  const findIndex = (items, x) => items.findIndex((y) => y.toLowerCase() === x);
73
- const parseNum = (x, past) => (x === "next " || x === "a " || x === "an " ? 1 : Number(x)) *
74
- (past ? -1 : 1);
45
+ const parseNum = (x, past) => (x === "next " || x === "a " || x === "an " ? 1 : Number(x)) * (past ? -1 : 1);
75
46
  const parsePeriod = (x) => {
76
- x =
77
- x !== "s" && x !== "ms" && x.endsWith("s")
78
- ? x.substring(0, x.length - 1)
79
- : x;
80
- return {
81
- ms: "t",
82
- milli: "t",
83
- millisecond: "t",
84
- sec: "s",
85
- second: "s",
86
- min: "m",
87
- minute: "m",
88
- hour: "h",
89
- day: "d",
90
- week: "w",
91
- mo: "M",
92
- month: "M",
93
- quarter: "q",
94
- year: "y",
95
- }[x] || x;
47
+ x = x !== "s" && x !== "ms" && x.endsWith("s") ? x.substring(0, x.length - 1) : x;
48
+ return {
49
+ ms: "t",
50
+ milli: "t",
51
+ millisecond: "t",
52
+ sec: "s",
53
+ second: "s",
54
+ min: "m",
55
+ minute: "m",
56
+ hour: "h",
57
+ day: "d",
58
+ week: "w",
59
+ mo: "M",
60
+ month: "M",
61
+ quarter: "q",
62
+ year: "y"
63
+ }[x] || x;
96
64
  };
97
- /**
98
- * Applies the given relative offset (defined by `num` and `period`) to the
99
- * optionally given `base` date (default: now). If `num < 0` the result date
100
- * will be in the past (relative to `base`).
101
- *
102
- * @param num -
103
- * @param period -
104
- * @param base -
105
- */
106
- export const relative = (num, period, base = dateTime()) => dateTime(base).add(num, period);
107
- /**
108
- * Returns the signed difference in milliseconds between given two dates `a` and
109
- * `b` (as `diff = a - b`).
110
- *
111
- * @remarks
112
- * Also see {@link absDifference}.
113
- *
114
- * @param a -
115
- * @param b -
116
- */
117
- export const difference = (a, b) => ensureEpoch(a) - ensureEpoch(b);
118
- /**
119
- * Returns the unsigned difference in milliseconds between given dates.
120
- *
121
- * @remarks
122
- * Also see {@link difference} for signed difference.
123
- *
124
- * @param a
125
- * @param b
126
- */
127
- export const absDifference = (a, b) => Math.abs(difference(a, b));
128
- /**
129
- * Computes and decomposes difference between given dates. Returns tuple of:
130
- * `[sign, years, months, days, hours, mins, secs, millis]`. The `sign` is used
131
- * to indicate the relative order of `a` compared to `b`, i.e. same contract as
132
- * [`ICompare`](https://docs.thi.ng/umbrella/api/interfaces/ICompare.html).
133
- *
134
- * @param a -
135
- * @param b -
136
- */
137
- export const decomposeDifference = (a, b = new Date()) => {
138
- const dur = ensureEpoch(a) - ensureEpoch(b);
139
- let abs = Math.abs(dur);
140
- const milli = abs % SECOND;
141
- abs -= milli;
142
- const sec = abs % MINUTE;
143
- abs -= sec;
144
- const min = abs % HOUR;
145
- abs -= min;
146
- const hour = abs % DAY;
147
- abs -= hour;
148
- const parts = [
149
- Math.sign(dur),
150
- 0, // year
151
- 0, // month
152
- 0, // day
153
- hour / HOUR,
154
- min / MINUTE,
155
- sec / SECOND,
156
- milli,
157
- ];
158
- if (!abs)
159
- return parts;
160
- const diff = (a, b) => {
161
- const months = (b.y - a.y) * 12 + (b.M - a.M);
162
- const bstart = +a.add(months, "M");
163
- let frac = +b - bstart;
164
- frac /=
165
- frac < 0
166
- ? bstart - +a.add(months - 1, "M")
167
- : +a.add(months + 1, "M") - bstart;
168
- return -(months + frac) || 0;
169
- };
170
- const aa = ensureDateTime(a, "d");
171
- const bb = ensureDateTime(b, "d");
172
- const months = Math.abs(aa.d < bb.d ? -diff(bb, aa) : diff(aa, bb)) | 0;
173
- const days = (start, end) => Math.abs(+start.withPrecision("d").add(months, "M") - +end.withPrecision("d")) / DAY;
174
- parts[1] = (months / 12) | 0;
175
- parts[2] = months % 12;
176
- parts[3] = dur < 0 ? days(aa, bb) : days(bb, aa);
65
+ const relative = (num, period, base = dateTime()) => dateTime(base).add(num, period);
66
+ const difference = (a, b) => ensureEpoch(a) - ensureEpoch(b);
67
+ const absDifference = (a, b) => Math.abs(difference(a, b));
68
+ const decomposeDifference = (a, b = /* @__PURE__ */ new Date()) => {
69
+ const dur = ensureEpoch(a) - ensureEpoch(b);
70
+ let abs = Math.abs(dur);
71
+ const milli = abs % SECOND;
72
+ abs -= milli;
73
+ const sec = abs % MINUTE;
74
+ abs -= sec;
75
+ const min = abs % HOUR;
76
+ abs -= min;
77
+ const hour = abs % DAY;
78
+ abs -= hour;
79
+ const parts = [
80
+ Math.sign(dur),
81
+ 0,
82
+ // year
83
+ 0,
84
+ // month
85
+ 0,
86
+ // day
87
+ hour / HOUR,
88
+ min / MINUTE,
89
+ sec / SECOND,
90
+ milli
91
+ ];
92
+ if (!abs)
177
93
  return parts;
94
+ const diff = (a2, b2) => {
95
+ const months2 = (b2.y - a2.y) * 12 + (b2.M - a2.M);
96
+ const bstart = +a2.add(months2, "M");
97
+ let frac = +b2 - bstart;
98
+ frac /= frac < 0 ? bstart - +a2.add(months2 - 1, "M") : +a2.add(months2 + 1, "M") - bstart;
99
+ return -(months2 + frac) || 0;
100
+ };
101
+ const aa = ensureDateTime(a, "d");
102
+ const bb = ensureDateTime(b, "d");
103
+ const months = Math.abs(aa.d < bb.d ? -diff(bb, aa) : diff(aa, bb)) | 0;
104
+ const days = (start, end) => Math.abs(
105
+ +start.withPrecision("d").add(months, "M") - +end.withPrecision("d")
106
+ ) / DAY;
107
+ parts[1] = months / 12 | 0;
108
+ parts[2] = months % 12;
109
+ parts[3] = dur < 0 ? days(aa, bb) : days(bb, aa);
110
+ return parts;
111
+ };
112
+ export {
113
+ absDifference,
114
+ decomposeDifference,
115
+ difference,
116
+ parseRelative,
117
+ relative
178
118
  };