@formatjs/intl-datetimeformat 7.1.0 → 7.1.2
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/add-all-tz.js +319 -318
- package/add-golden-tz.js +1 -1
- package/index.d.ts +1 -1
- package/index.js +1 -1
- package/package.json +5 -5
- package/polyfill-force.js +28 -44
- package/polyfill.iife.js +2803 -3046
- package/polyfill.js +29 -45
- package/should-polyfill.js +38 -50
- package/src/abstract/BasicFormatMatcher.d.ts +5 -5
- package/src/abstract/BasicFormatMatcher.js +87 -103
- package/src/abstract/BestFitFormatMatcher.d.ts +12 -12
- package/src/abstract/BestFitFormatMatcher.js +102 -108
- package/src/abstract/DateTimeStyleFormat.d.ts +2 -2
- package/src/abstract/DateTimeStyleFormat.js +47 -62
- package/src/abstract/FormatDateTime.d.ts +7 -7
- package/src/abstract/FormatDateTime.js +12 -12
- package/src/abstract/FormatDateTimePattern.d.ts +11 -11
- package/src/abstract/FormatDateTimePattern.js +185 -198
- package/src/abstract/FormatDateTimeRange.d.ts +3 -3
- package/src/abstract/FormatDateTimeRange.js +9 -8
- package/src/abstract/FormatDateTimeRangeToParts.d.ts +4 -4
- package/src/abstract/FormatDateTimeRangeToParts.js +14 -12
- package/src/abstract/FormatDateTimeToParts.d.ts +9 -9
- package/src/abstract/FormatDateTimeToParts.js +17 -18
- package/src/abstract/InitializeDateTimeFormat.d.ts +15 -15
- package/src/abstract/InitializeDateTimeFormat.js +206 -184
- package/src/abstract/PartitionDateTimePattern.d.ts +8 -8
- package/src/abstract/PartitionDateTimePattern.js +15 -14
- package/src/abstract/PartitionDateTimeRangePattern.d.ts +4 -4
- package/src/abstract/PartitionDateTimeRangePattern.js +168 -161
- package/src/abstract/ToDateTimeOptions.d.ts +5 -5
- package/src/abstract/ToDateTimeOptions.js +68 -60
- package/src/abstract/ToLocalTime.d.ts +21 -21
- package/src/abstract/ToLocalTime.js +116 -45
- package/src/abstract/skeleton.d.ts +8 -8
- package/src/abstract/skeleton.js +231 -280
- package/src/abstract/utils.d.ts +1 -1
- package/src/abstract/utils.js +21 -20
- package/src/core.d.ts +17 -17
- package/src/core.js +250 -286
- package/src/data/all-tz.generated.d.ts +8 -0
- package/src/data/all-tz.generated.js +462 -0
- package/src/data/links.generated.d.ts +261 -0
- package/src/data/links.generated.js +260 -0
- package/src/get_internal_slots.d.ts +3 -1
- package/src/get_internal_slots.js +8 -7
- package/src/packer.d.ts +2 -2
- package/src/packer.js +23 -35
- package/src/to_locale_string.d.ts +3 -3
- package/src/to_locale_string.js +11 -11
- package/src/types.d.ts +34 -39
- package/src/types.js +1 -1
- package/supported-locales.generated.js +573 -1
- package/test262-main.d.ts +4 -1
- package/test262-main.js +24600 -44193
- package/src/data/all-tz.d.ts +0 -6
- package/src/data/all-tz.js +0 -461
- package/src/data/links.d.ts +0 -259
- package/src/data/links.js +0 -260
package/polyfill.js
CHANGED
|
@@ -1,47 +1,31 @@
|
|
|
1
|
-
import { DateTimeFormat } from
|
|
2
|
-
import { defineProperty } from
|
|
3
|
-
import { shouldPolyfill } from
|
|
4
|
-
import { toLocaleString as _toLocaleString, toLocaleDateString as _toLocaleDateString, toLocaleTimeString as _toLocaleTimeString
|
|
1
|
+
import { DateTimeFormat } from "./index.js";
|
|
2
|
+
import { defineProperty } from "@formatjs/ecma402-abstract";
|
|
3
|
+
import { shouldPolyfill } from "./should-polyfill.js";
|
|
4
|
+
import { toLocaleString as _toLocaleString, toLocaleDateString as _toLocaleDateString, toLocaleTimeString as _toLocaleTimeString } from "./src/to_locale_string.js";
|
|
5
5
|
if (shouldPolyfill()) {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
},
|
|
33
|
-
});
|
|
34
|
-
defineProperty(Date.prototype, 'toLocaleTimeString', {
|
|
35
|
-
value: function toLocaleTimeString(locales, options) {
|
|
36
|
-
if (options === void 0) { options = {
|
|
37
|
-
timeStyle: 'medium',
|
|
38
|
-
}; }
|
|
39
|
-
try {
|
|
40
|
-
return _toLocaleTimeString(this, locales, options);
|
|
41
|
-
}
|
|
42
|
-
catch (_a) {
|
|
43
|
-
return 'Invalid Date';
|
|
44
|
-
}
|
|
45
|
-
},
|
|
46
|
-
});
|
|
6
|
+
defineProperty(Intl, "DateTimeFormat", { value: DateTimeFormat });
|
|
7
|
+
defineProperty(Date.prototype, "toLocaleString", { value: function toLocaleString(locales, options = {
|
|
8
|
+
dateStyle: "short",
|
|
9
|
+
timeStyle: "medium"
|
|
10
|
+
}) {
|
|
11
|
+
try {
|
|
12
|
+
return _toLocaleString(this, locales, options);
|
|
13
|
+
} catch {
|
|
14
|
+
return "Invalid Date";
|
|
15
|
+
}
|
|
16
|
+
} });
|
|
17
|
+
defineProperty(Date.prototype, "toLocaleDateString", { value: function toLocaleDateString(locales, options = { dateStyle: "short" }) {
|
|
18
|
+
try {
|
|
19
|
+
return _toLocaleDateString(this, locales, options);
|
|
20
|
+
} catch {
|
|
21
|
+
return "Invalid Date";
|
|
22
|
+
}
|
|
23
|
+
} });
|
|
24
|
+
defineProperty(Date.prototype, "toLocaleTimeString", { value: function toLocaleTimeString(locales, options = { timeStyle: "medium" }) {
|
|
25
|
+
try {
|
|
26
|
+
return _toLocaleTimeString(this, locales, options);
|
|
27
|
+
} catch {
|
|
28
|
+
return "Invalid Date";
|
|
29
|
+
}
|
|
30
|
+
} });
|
|
47
31
|
}
|
package/should-polyfill.js
CHANGED
|
@@ -1,61 +1,49 @@
|
|
|
1
|
-
import { match } from
|
|
2
|
-
import { supportedLocales } from
|
|
1
|
+
import { match } from "@formatjs/intl-localematcher";
|
|
2
|
+
import { supportedLocales } from "./supported-locales.generated.js";
|
|
3
3
|
function supportsDateStyle() {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
catch (_a) {
|
|
10
|
-
return false;
|
|
11
|
-
}
|
|
4
|
+
try {
|
|
5
|
+
return !!new Intl.DateTimeFormat(undefined, { dateStyle: "short" }).resolvedOptions().dateStyle;
|
|
6
|
+
} catch {
|
|
7
|
+
return false;
|
|
8
|
+
}
|
|
12
9
|
}
|
|
13
10
|
/**
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
* https://bugs.chromium.org/p/chromium/issues/detail?id=865351
|
|
12
|
+
*/
|
|
16
13
|
function hasChromeLt71Bug() {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}
|
|
14
|
+
try {
|
|
15
|
+
return new Intl.DateTimeFormat("en", {
|
|
16
|
+
hourCycle: "h11",
|
|
17
|
+
hour: "numeric"
|
|
18
|
+
}).formatToParts(0)[2].type !== "dayPeriod";
|
|
19
|
+
} catch {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
26
22
|
}
|
|
27
23
|
/**
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
24
|
+
* Node 14's version of Intl.DateTimeFormat does not throw
|
|
25
|
+
* when dateStyle/timeStyle is used with other options.
|
|
26
|
+
* This was fixed in newer V8 versions
|
|
27
|
+
*/
|
|
32
28
|
function hasUnthrownDateTimeStyleBug() {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
29
|
+
try {
|
|
30
|
+
return !!new Intl.DateTimeFormat("en", {
|
|
31
|
+
dateStyle: "short",
|
|
32
|
+
hour: "numeric"
|
|
33
|
+
}).format(new Date(0));
|
|
34
|
+
} catch {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
42
37
|
}
|
|
43
38
|
function supportedLocalesOf(locale) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
39
|
+
if (!locale) {
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
const locales = Array.isArray(locale) ? locale : [locale];
|
|
43
|
+
return Intl.DateTimeFormat.supportedLocalesOf(locales).length === locales.length;
|
|
49
44
|
}
|
|
50
|
-
export function shouldPolyfill(locale) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
!('formatRange' in Intl.DateTimeFormat.prototype) ||
|
|
55
|
-
hasChromeLt71Bug() ||
|
|
56
|
-
hasUnthrownDateTimeStyleBug() ||
|
|
57
|
-
!supportsDateStyle() ||
|
|
58
|
-
!supportedLocalesOf(locale)) {
|
|
59
|
-
return locale ? match([locale], supportedLocales, 'en') : undefined;
|
|
60
|
-
}
|
|
45
|
+
export function shouldPolyfill(locale = "en") {
|
|
46
|
+
if (!("DateTimeFormat" in Intl) || !("formatToParts" in Intl.DateTimeFormat.prototype) || !("formatRange" in Intl.DateTimeFormat.prototype) || hasChromeLt71Bug() || hasUnthrownDateTimeStyleBug() || !supportsDateStyle() || !supportedLocalesOf(locale)) {
|
|
47
|
+
return locale ? match([locale], supportedLocales, "en") : undefined;
|
|
48
|
+
}
|
|
61
49
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { Formats } from
|
|
1
|
+
import { type Formats } from "@formatjs/ecma402-abstract";
|
|
2
2
|
/**
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
* https://tc39.es/ecma402/#sec-basicformatmatcher
|
|
4
|
+
* @param options
|
|
5
|
+
* @param formats
|
|
6
|
+
*/
|
|
7
7
|
export declare function BasicFormatMatcher(options: Intl.DateTimeFormatOptions, formats: Formats[]): Formats;
|
|
@@ -1,106 +1,90 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { DATE_TIME_PROPS, additionPenalty, removalPenalty, longMorePenalty, shortMorePenalty, shortLessPenalty, longLessPenalty, offsetPenalty, } from './utils.js';
|
|
1
|
+
import { invariant } from "@formatjs/ecma402-abstract";
|
|
2
|
+
import { DATE_TIME_PROPS, additionPenalty, removalPenalty, longMorePenalty, shortMorePenalty, shortLessPenalty, longLessPenalty, offsetPenalty } from "./utils.js";
|
|
4
3
|
/**
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
* https://tc39.es/ecma402/#sec-basicformatmatcher
|
|
5
|
+
* @param options
|
|
6
|
+
* @param formats
|
|
7
|
+
*/
|
|
9
8
|
export function BasicFormatMatcher(options, formats) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}
|
|
92
|
-
else if (delta === -1) {
|
|
93
|
-
score -= shortLessPenalty;
|
|
94
|
-
}
|
|
95
|
-
else if (delta === -2) {
|
|
96
|
-
score -= longLessPenalty;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
if (score > bestScore) {
|
|
101
|
-
bestScore = score;
|
|
102
|
-
bestFormat = format;
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
return __assign({}, bestFormat);
|
|
9
|
+
let bestScore = -Infinity;
|
|
10
|
+
let bestFormat = formats[0];
|
|
11
|
+
invariant(Array.isArray(formats), "formats should be a list of things");
|
|
12
|
+
for (const format of formats) {
|
|
13
|
+
let score = 0;
|
|
14
|
+
for (const prop of DATE_TIME_PROPS) {
|
|
15
|
+
const optionsProp = options[prop];
|
|
16
|
+
const formatProp = format[prop];
|
|
17
|
+
if (optionsProp === undefined && formatProp !== undefined) {
|
|
18
|
+
score -= additionPenalty;
|
|
19
|
+
} else if (optionsProp !== undefined && formatProp === undefined) {
|
|
20
|
+
score -= removalPenalty;
|
|
21
|
+
} else if (prop === "timeZoneName") {
|
|
22
|
+
if (optionsProp === "short" || optionsProp === "shortGeneric") {
|
|
23
|
+
if (formatProp === "shortOffset") {
|
|
24
|
+
score -= offsetPenalty;
|
|
25
|
+
} else if (formatProp === "longOffset") {
|
|
26
|
+
score -= offsetPenalty + shortMorePenalty;
|
|
27
|
+
} else if (optionsProp === "short" && formatProp === "long") {
|
|
28
|
+
score -= shortMorePenalty;
|
|
29
|
+
} else if (optionsProp === "shortGeneric" && formatProp === "longGeneric") {
|
|
30
|
+
score -= shortMorePenalty;
|
|
31
|
+
} else if (optionsProp !== formatProp) {
|
|
32
|
+
score -= removalPenalty;
|
|
33
|
+
}
|
|
34
|
+
} else if (optionsProp === "shortOffset" && formatProp === "longOffset") {
|
|
35
|
+
score -= shortMorePenalty;
|
|
36
|
+
} else if (optionsProp === "long" || optionsProp === "longGeneric") {
|
|
37
|
+
if (formatProp === "longOffset") {
|
|
38
|
+
score -= offsetPenalty;
|
|
39
|
+
} else if (formatProp === "shortOffset") {
|
|
40
|
+
score -= offsetPenalty + longLessPenalty;
|
|
41
|
+
} else if (optionsProp === "long" && formatProp === "short") {
|
|
42
|
+
score -= longLessPenalty;
|
|
43
|
+
} else if (optionsProp === "longGeneric" && formatProp === "shortGeneric") {
|
|
44
|
+
score -= longLessPenalty;
|
|
45
|
+
} else if (optionsProp !== formatProp) {
|
|
46
|
+
score -= removalPenalty;
|
|
47
|
+
}
|
|
48
|
+
} else if (optionsProp === "longOffset" && formatProp === "shortOffset") {
|
|
49
|
+
score -= longLessPenalty;
|
|
50
|
+
} else if (optionsProp !== formatProp) {
|
|
51
|
+
score -= removalPenalty;
|
|
52
|
+
}
|
|
53
|
+
} else if (optionsProp !== formatProp) {
|
|
54
|
+
let values;
|
|
55
|
+
if (prop === "fractionalSecondDigits") {
|
|
56
|
+
values = [
|
|
57
|
+
1,
|
|
58
|
+
2,
|
|
59
|
+
3
|
|
60
|
+
];
|
|
61
|
+
} else {
|
|
62
|
+
values = [
|
|
63
|
+
"2-digit",
|
|
64
|
+
"numeric",
|
|
65
|
+
"narrow",
|
|
66
|
+
"short",
|
|
67
|
+
"long"
|
|
68
|
+
];
|
|
69
|
+
}
|
|
70
|
+
const optionsPropIndex = values.indexOf(optionsProp);
|
|
71
|
+
const formatPropIndex = values.indexOf(formatProp);
|
|
72
|
+
const delta = Math.max(-2, Math.min(formatPropIndex - optionsPropIndex, 2));
|
|
73
|
+
if (delta === 2) {
|
|
74
|
+
score -= longMorePenalty;
|
|
75
|
+
} else if (delta === 1) {
|
|
76
|
+
score -= shortMorePenalty;
|
|
77
|
+
} else if (delta === -1) {
|
|
78
|
+
score -= shortLessPenalty;
|
|
79
|
+
} else if (delta === -2) {
|
|
80
|
+
score -= longLessPenalty;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
if (score > bestScore) {
|
|
85
|
+
bestScore = score;
|
|
86
|
+
bestFormat = format;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return { ...bestFormat };
|
|
106
90
|
}
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import { Formats } from
|
|
1
|
+
import { type Formats } from "@formatjs/ecma402-abstract";
|
|
2
2
|
/**
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
* Credit: https://github.com/andyearnshaw/Intl.js/blob/0958dc1ad8153f1056653ea22b8208f0df289a4e/src/12.datetimeformat.js#L611
|
|
4
|
+
* with some modifications
|
|
5
|
+
* @param options
|
|
6
|
+
* @param format
|
|
7
|
+
*/
|
|
8
8
|
export declare function bestFitFormatMatcherScore(options: Intl.DateTimeFormatOptions, format: Formats): number;
|
|
9
9
|
/**
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
* https://tc39.es/ecma402/#sec-bestfitformatmatcher
|
|
11
|
+
* Just alias to basic for now
|
|
12
|
+
* @param options
|
|
13
|
+
* @param formats
|
|
14
|
+
* @param implDetails Implementation details
|
|
15
|
+
*/
|
|
16
16
|
export declare function BestFitFormatMatcher(options: Intl.DateTimeFormatOptions, formats: Formats[]): Formats;
|
|
@@ -1,116 +1,110 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { DATE_TIME_PROPS, additionPenalty, differentNumericTypePenalty, longLessPenalty, longMorePenalty, removalPenalty, shortLessPenalty, shortMorePenalty, } from './utils.js';
|
|
1
|
+
import { invariant } from "@formatjs/ecma402-abstract";
|
|
2
|
+
import { processDateTimePattern } from "./skeleton.js";
|
|
3
|
+
import { DATE_TIME_PROPS, additionPenalty, differentNumericTypePenalty, longLessPenalty, longMorePenalty, removalPenalty, shortLessPenalty, shortMorePenalty } from "./utils.js";
|
|
5
4
|
function isNumericType(t) {
|
|
6
|
-
|
|
5
|
+
return t === "numeric" || t === "2-digit";
|
|
7
6
|
}
|
|
8
7
|
/**
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
* Credit: https://github.com/andyearnshaw/Intl.js/blob/0958dc1ad8153f1056653ea22b8208f0df289a4e/src/12.datetimeformat.js#L611
|
|
9
|
+
* with some modifications
|
|
10
|
+
* @param options
|
|
11
|
+
* @param format
|
|
12
|
+
*/
|
|
14
13
|
export function bestFitFormatMatcherScore(options, format) {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
return score;
|
|
14
|
+
let score = 0;
|
|
15
|
+
if (options.hour12 && !format.hour12) {
|
|
16
|
+
score -= removalPenalty;
|
|
17
|
+
} else if (!options.hour12 && format.hour12) {
|
|
18
|
+
score -= additionPenalty;
|
|
19
|
+
}
|
|
20
|
+
for (const prop of DATE_TIME_PROPS) {
|
|
21
|
+
const optionsProp = options[prop];
|
|
22
|
+
const formatProp = format[prop];
|
|
23
|
+
if (optionsProp === undefined && formatProp !== undefined) {
|
|
24
|
+
score -= additionPenalty;
|
|
25
|
+
} else if (optionsProp !== undefined && formatProp === undefined) {
|
|
26
|
+
score -= removalPenalty;
|
|
27
|
+
} else if (optionsProp !== formatProp) {
|
|
28
|
+
// extra penalty for numeric vs non-numeric
|
|
29
|
+
if (isNumericType(optionsProp) !== isNumericType(formatProp)) {
|
|
30
|
+
score -= differentNumericTypePenalty;
|
|
31
|
+
} else {
|
|
32
|
+
const values = [
|
|
33
|
+
"2-digit",
|
|
34
|
+
"numeric",
|
|
35
|
+
"narrow",
|
|
36
|
+
"short",
|
|
37
|
+
"long"
|
|
38
|
+
];
|
|
39
|
+
const optionsPropIndex = values.indexOf(optionsProp);
|
|
40
|
+
const formatPropIndex = values.indexOf(formatProp);
|
|
41
|
+
const delta = Math.max(-2, Math.min(formatPropIndex - optionsPropIndex, 2));
|
|
42
|
+
if (delta === 2) {
|
|
43
|
+
score -= longMorePenalty;
|
|
44
|
+
} else if (delta === 1) {
|
|
45
|
+
score -= shortMorePenalty;
|
|
46
|
+
} else if (delta === -1) {
|
|
47
|
+
score -= shortLessPenalty;
|
|
48
|
+
} else if (delta === -2) {
|
|
49
|
+
score -= longLessPenalty;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return score;
|
|
59
55
|
}
|
|
60
56
|
/**
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
57
|
+
* https://tc39.es/ecma402/#sec-bestfitformatmatcher
|
|
58
|
+
* Just alias to basic for now
|
|
59
|
+
* @param options
|
|
60
|
+
* @param formats
|
|
61
|
+
* @param implDetails Implementation details
|
|
62
|
+
*/
|
|
67
63
|
export function BestFitFormatMatcher(options, formats) {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
patternFormat.rangePatterns12 = skeletonFormat.rangePatterns12;
|
|
115
|
-
return patternFormat;
|
|
64
|
+
let bestScore = -Infinity;
|
|
65
|
+
let bestFormat = formats[0];
|
|
66
|
+
invariant(Array.isArray(formats), "formats should be a list of things");
|
|
67
|
+
for (const format of formats) {
|
|
68
|
+
const score = bestFitFormatMatcherScore(options, format);
|
|
69
|
+
if (score > bestScore) {
|
|
70
|
+
bestScore = score;
|
|
71
|
+
bestFormat = format;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
const skeletonFormat = { ...bestFormat };
|
|
75
|
+
const patternFormat = { rawPattern: bestFormat.rawPattern };
|
|
76
|
+
processDateTimePattern(bestFormat.rawPattern, patternFormat);
|
|
77
|
+
// Kinda following https://github.com/unicode-org/icu/blob/dd50e38f459d84e9bf1b0c618be8483d318458ad/icu4j/main/classes/core/src/com/ibm/icu/text/DateTimePatternGenerator.java
|
|
78
|
+
// Method adjustFieldTypes
|
|
79
|
+
for (const prop in skeletonFormat) {
|
|
80
|
+
const skeletonValue = skeletonFormat[prop];
|
|
81
|
+
const patternValue = patternFormat[prop];
|
|
82
|
+
const requestedValue = options[prop];
|
|
83
|
+
// Don't mess with minute/second or we can get in the situation of
|
|
84
|
+
// 7:0:0 which is weird
|
|
85
|
+
if (prop === "minute" || prop === "second") {
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
// Nothing to do here
|
|
89
|
+
if (!requestedValue) {
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
// https://unicode.org/reports/tr35/tr35-dates.html#Matching_Skeletons
|
|
93
|
+
// Looks like we should not convert numeric to alphabetic but the other way
|
|
94
|
+
// around is ok
|
|
95
|
+
if (isNumericType(patternValue) && !isNumericType(requestedValue)) {
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
if (skeletonValue === requestedValue) {
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
patternFormat[prop] = requestedValue;
|
|
102
|
+
}
|
|
103
|
+
// Copy those over
|
|
104
|
+
patternFormat.pattern = skeletonFormat.pattern;
|
|
105
|
+
patternFormat.pattern12 = skeletonFormat.pattern12;
|
|
106
|
+
patternFormat.skeleton = skeletonFormat.skeleton;
|
|
107
|
+
patternFormat.rangePatterns = skeletonFormat.rangePatterns;
|
|
108
|
+
patternFormat.rangePatterns12 = skeletonFormat.rangePatterns12;
|
|
109
|
+
return patternFormat;
|
|
116
110
|
}
|