@bbn/bbn 2.0.33 → 2.0.35
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.
|
@@ -16,12 +16,13 @@ type CommonFormats = {
|
|
|
16
16
|
}>;
|
|
17
17
|
};
|
|
18
18
|
/**
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* - weekday / year / month / day
|
|
22
|
-
* - hour / minute / second / timeZoneName
|
|
19
|
+
* Get a curated set of *common* date, time and datetime formats
|
|
20
|
+
* for the given locale, without exploding into thousands of combos.
|
|
23
21
|
*
|
|
24
|
-
*
|
|
22
|
+
* Rules:
|
|
23
|
+
* - Date: only sensible combos (Y-M-D ± weekday, Y-M, M-D).
|
|
24
|
+
* - Time: hour / hour:minute / hour:minute:second (+ optional TZ).
|
|
25
|
+
* - Datetime: only full dates (Y-M-D ± weekday) combined with time.
|
|
25
26
|
*/
|
|
26
27
|
export declare function getCommonFormatsForLocale(lng: string | string[]): CommonFormats;
|
|
27
28
|
export default function buildLocaleFromIntl(): void;
|
|
@@ -2,8 +2,9 @@ import extend from "../../fn/object/extend.js";
|
|
|
2
2
|
import numProperties from "../../fn/object/numProperties.js";
|
|
3
3
|
/**
|
|
4
4
|
* Build a token pattern (YYYY, MM, DD, dddd, HH, II, SS, A, z) from Intl parts.
|
|
5
|
+
* Uses Intl options to distinguish MMM vs MMMM, ddd vs dddd, etc.
|
|
5
6
|
*/
|
|
6
|
-
function partsToPattern(parts, hourCycle) {
|
|
7
|
+
function partsToPattern(parts, hourCycle, opts) {
|
|
7
8
|
let pattern = '';
|
|
8
9
|
const hasDayPeriod = parts.some(p => p.type === 'dayPeriod');
|
|
9
10
|
const is12h = hasDayPeriod || hourCycle === 'h12' || hourCycle === 'h11';
|
|
@@ -13,18 +14,38 @@ function partsToPattern(parts, hourCycle) {
|
|
|
13
14
|
pattern += 'YYYY';
|
|
14
15
|
break;
|
|
15
16
|
case 'month':
|
|
16
|
-
if (
|
|
17
|
-
pattern +=
|
|
17
|
+
if (opts.month === 'short') {
|
|
18
|
+
pattern += 'MMM';
|
|
19
|
+
}
|
|
20
|
+
else if (opts.month === 'long') {
|
|
21
|
+
pattern += 'MMMM';
|
|
22
|
+
}
|
|
23
|
+
else if (opts.month === 'numeric' || opts.month === '2-digit') {
|
|
24
|
+
pattern += /^\d{2}$/.test(p.value) ? 'MM' : 'M';
|
|
18
25
|
}
|
|
19
26
|
else {
|
|
20
|
-
|
|
27
|
+
// Fallback
|
|
28
|
+
if (/^\d+$/.test(p.value)) {
|
|
29
|
+
pattern += p.value.length === 2 ? 'MM' : 'M';
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
pattern += p.value.length > 3 ? 'MMMM' : 'MMM';
|
|
33
|
+
}
|
|
21
34
|
}
|
|
22
35
|
break;
|
|
23
36
|
case 'day':
|
|
24
37
|
pattern += p.value.length === 2 ? 'DD' : 'D';
|
|
25
38
|
break;
|
|
26
39
|
case 'weekday':
|
|
27
|
-
|
|
40
|
+
if (opts.weekday === 'short' || opts.weekday === 'narrow') {
|
|
41
|
+
pattern += 'ddd';
|
|
42
|
+
}
|
|
43
|
+
else if (opts.weekday === 'long') {
|
|
44
|
+
pattern += 'dddd';
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
pattern += p.value.length > 3 ? 'dddd' : 'ddd';
|
|
48
|
+
}
|
|
28
49
|
break;
|
|
29
50
|
case 'hour':
|
|
30
51
|
if (is12h) {
|
|
@@ -55,15 +76,15 @@ function partsToPattern(parts, hourCycle) {
|
|
|
55
76
|
return pattern;
|
|
56
77
|
}
|
|
57
78
|
/**
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
* - weekday / year / month / day
|
|
61
|
-
* - hour / minute / second / timeZoneName
|
|
79
|
+
* Get a curated set of *common* date, time and datetime formats
|
|
80
|
+
* for the given locale, without exploding into thousands of combos.
|
|
62
81
|
*
|
|
63
|
-
*
|
|
82
|
+
* Rules:
|
|
83
|
+
* - Date: only sensible combos (Y-M-D ± weekday, Y-M, M-D).
|
|
84
|
+
* - Time: hour / hour:minute / hour:minute:second (+ optional TZ).
|
|
85
|
+
* - Datetime: only full dates (Y-M-D ± weekday) combined with time.
|
|
64
86
|
*/
|
|
65
87
|
export function getCommonFormatsForLocale(lng) {
|
|
66
|
-
// Fixed sample: 2 Jan 2000, 13:45:30 UTC
|
|
67
88
|
const sample = new Date(Date.UTC(2000, 0, 2, 13, 45, 30));
|
|
68
89
|
const date = [];
|
|
69
90
|
const time = [];
|
|
@@ -71,121 +92,84 @@ export function getCommonFormatsForLocale(lng) {
|
|
|
71
92
|
const seenDatePatterns = new Set();
|
|
72
93
|
const seenTimePatterns = new Set();
|
|
73
94
|
const seenDateTimePatterns = new Set();
|
|
74
|
-
// ---- 1) DATE
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
'
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
'
|
|
95
|
+
// ---- 1) DATE: curated list of useful patterns ----
|
|
96
|
+
// Includes your important one: { day: "numeric", month: "short", year: "numeric" }
|
|
97
|
+
const dateOptionsList = [
|
|
98
|
+
// Full dates
|
|
99
|
+
{ year: 'numeric', month: '2-digit', day: '2-digit' },
|
|
100
|
+
{ year: 'numeric', month: 'numeric', day: 'numeric' },
|
|
101
|
+
{ year: 'numeric', month: 'short', day: 'numeric' },
|
|
102
|
+
{ year: 'numeric', month: 'long', day: 'numeric' },
|
|
103
|
+
// Full dates with weekday
|
|
104
|
+
{ weekday: 'short', year: 'numeric', month: 'short', day: 'numeric' },
|
|
105
|
+
{ weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' },
|
|
106
|
+
// Year–month
|
|
107
|
+
{ year: 'numeric', month: 'numeric' },
|
|
108
|
+
{ year: 'numeric', month: '2-digit' },
|
|
109
|
+
{ year: 'numeric', month: 'short' },
|
|
110
|
+
{ year: 'numeric', month: 'long' },
|
|
111
|
+
// Month–day (no year)
|
|
112
|
+
{ month: 'numeric', day: 'numeric' },
|
|
113
|
+
{ month: '2-digit', day: '2-digit' },
|
|
114
|
+
{ month: 'short', day: 'numeric' }, // ← e.g. "22 janv."
|
|
115
|
+
{ month: 'long', day: 'numeric' }
|
|
84
116
|
];
|
|
85
|
-
const
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
options.weekday = weekday;
|
|
103
|
-
if (year)
|
|
104
|
-
options.year = year;
|
|
105
|
-
if (month)
|
|
106
|
-
options.month = month;
|
|
107
|
-
if (day)
|
|
108
|
-
options.day = day;
|
|
109
|
-
const fmt = new Intl.DateTimeFormat(lng, options);
|
|
110
|
-
const parts = fmt.formatToParts(sample);
|
|
111
|
-
const resolved = fmt.resolvedOptions();
|
|
112
|
-
const pattern = partsToPattern(parts, resolved.hourCycle);
|
|
113
|
-
if (!seenDatePatterns.has(pattern)) {
|
|
114
|
-
seenDatePatterns.add(pattern);
|
|
115
|
-
dateOptionsList.push(options);
|
|
116
|
-
date.push({
|
|
117
|
-
pattern,
|
|
118
|
-
sample: fmt.format(sample),
|
|
119
|
-
options
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
}
|
|
117
|
+
const fullDateOptions = []; // Y+M+D (± weekday)
|
|
118
|
+
for (const opts of dateOptionsList) {
|
|
119
|
+
const fmt = new Intl.DateTimeFormat(lng, opts);
|
|
120
|
+
const parts = fmt.formatToParts(sample);
|
|
121
|
+
const resolved = fmt.resolvedOptions();
|
|
122
|
+
const pattern = partsToPattern(parts, resolved.hourCycle, opts);
|
|
123
|
+
if (!seenDatePatterns.has(pattern)) {
|
|
124
|
+
seenDatePatterns.add(pattern);
|
|
125
|
+
date.push({
|
|
126
|
+
pattern,
|
|
127
|
+
sample: fmt.format(sample),
|
|
128
|
+
options: opts
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
// keep track of "full dates" (year+month+day) for datetime
|
|
132
|
+
if (opts.year && opts.month && opts.day) {
|
|
133
|
+
fullDateOptions.push(opts);
|
|
124
134
|
}
|
|
125
135
|
}
|
|
126
|
-
|
|
127
|
-
const
|
|
128
|
-
|
|
129
|
-
'
|
|
130
|
-
'2-digit'
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
'numeric',
|
|
135
|
-
'2-digit'
|
|
136
|
+
// ---- 2) TIME: curated, valid combos (always have hour, then minute/second) ----
|
|
137
|
+
const timeOptionsList = [
|
|
138
|
+
{ hour: 'numeric' },
|
|
139
|
+
{ hour: '2-digit', minute: '2-digit' },
|
|
140
|
+
{ hour: '2-digit', minute: '2-digit', second: '2-digit' },
|
|
141
|
+
{ hour: '2-digit', minute: '2-digit', timeZoneName: 'short' },
|
|
142
|
+
{ hour: '2-digit', minute: '2-digit', second: '2-digit', timeZoneName: 'short' },
|
|
143
|
+
{ hour: '2-digit', minute: '2-digit', timeZoneName: 'long' }
|
|
136
144
|
];
|
|
137
|
-
const
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
continue;
|
|
150
|
-
}
|
|
151
|
-
const options = { hour };
|
|
152
|
-
if (minute)
|
|
153
|
-
options.minute = minute;
|
|
154
|
-
if (second)
|
|
155
|
-
options.second = second;
|
|
156
|
-
if (tzName)
|
|
157
|
-
options.timeZoneName = tzName;
|
|
158
|
-
const fmt = new Intl.DateTimeFormat(lng, options);
|
|
159
|
-
const parts = fmt.formatToParts(sample);
|
|
160
|
-
const resolved = fmt.resolvedOptions();
|
|
161
|
-
const pattern = partsToPattern(parts, resolved.hourCycle);
|
|
162
|
-
if (!seenTimePatterns.has(pattern)) {
|
|
163
|
-
seenTimePatterns.add(pattern);
|
|
164
|
-
timeOptionsList.push(options);
|
|
165
|
-
time.push({
|
|
166
|
-
pattern,
|
|
167
|
-
sample: fmt.format(sample),
|
|
168
|
-
options
|
|
169
|
-
});
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
}
|
|
145
|
+
for (const opts of timeOptionsList) {
|
|
146
|
+
const fmt = new Intl.DateTimeFormat(lng, opts);
|
|
147
|
+
const parts = fmt.formatToParts(sample);
|
|
148
|
+
const resolved = fmt.resolvedOptions();
|
|
149
|
+
const pattern = partsToPattern(parts, resolved.hourCycle, opts);
|
|
150
|
+
if (!seenTimePatterns.has(pattern)) {
|
|
151
|
+
seenTimePatterns.add(pattern);
|
|
152
|
+
time.push({
|
|
153
|
+
pattern,
|
|
154
|
+
sample: fmt.format(sample),
|
|
155
|
+
options: opts
|
|
156
|
+
});
|
|
173
157
|
}
|
|
174
158
|
}
|
|
175
|
-
// ---- 3) DATETIME
|
|
176
|
-
for (const
|
|
177
|
-
for (const
|
|
178
|
-
const
|
|
179
|
-
const fmt = new Intl.DateTimeFormat(lng,
|
|
159
|
+
// ---- 3) DATETIME: only full dates (Y-M-D ± weekday) × time
|
|
160
|
+
for (const dOpts of fullDateOptions) {
|
|
161
|
+
for (const tOpts of timeOptionsList) {
|
|
162
|
+
const opts = Object.assign(Object.assign({}, dOpts), tOpts);
|
|
163
|
+
const fmt = new Intl.DateTimeFormat(lng, opts);
|
|
180
164
|
const parts = fmt.formatToParts(sample);
|
|
181
165
|
const resolved = fmt.resolvedOptions();
|
|
182
|
-
const pattern = partsToPattern(parts, resolved.hourCycle);
|
|
166
|
+
const pattern = partsToPattern(parts, resolved.hourCycle, opts);
|
|
183
167
|
if (!seenDateTimePatterns.has(pattern)) {
|
|
184
168
|
seenDateTimePatterns.add(pattern);
|
|
185
169
|
datetime.push({
|
|
186
170
|
pattern,
|
|
187
171
|
sample: fmt.format(sample),
|
|
188
|
-
options
|
|
172
|
+
options: opts
|
|
189
173
|
});
|
|
190
174
|
}
|
|
191
175
|
}
|
|
@@ -1,12 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* Guess a date format string for the given input.
|
|
3
|
-
*
|
|
4
|
-
* - If `formats` is provided, it will try those formats in order and return
|
|
5
|
-
* the first one that successfully parses.
|
|
6
|
-
* - If `formats` is not provided, it will try a set of built-in common formats
|
|
7
|
-
* (MySQL, ISO/JS, EU/US, full-text using bbn.dt.locales).
|
|
8
|
-
* - Returns `null` if no format matches.
|
|
9
|
-
*
|
|
10
|
-
* NOTE: It relies on `this.parse(input, format)` NOT throwing when the format is correct.
|
|
11
|
-
*/
|
|
12
|
-
export default function guessFormat(input: string, formats?: string[] | string): string | null;
|
|
1
|
+
export default function guessFormat(input: string, formats?: string | string[], lng?: string): string | null;
|
|
@@ -1,120 +1,45 @@
|
|
|
1
|
-
import buildLocaleFromIntl from './buildLocaleFromIntl.js';
|
|
2
1
|
import parse from './parse.js';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
*
|
|
6
|
-
* - If `formats` is provided, it will try those formats in order and return
|
|
7
|
-
* the first one that successfully parses.
|
|
8
|
-
* - If `formats` is not provided, it will try a set of built-in common formats
|
|
9
|
-
* (MySQL, ISO/JS, EU/US, full-text using bbn.dt.locales).
|
|
10
|
-
* - Returns `null` if no format matches.
|
|
11
|
-
*
|
|
12
|
-
* NOTE: It relies on `this.parse(input, format)` NOT throwing when the format is correct.
|
|
13
|
-
*/
|
|
14
|
-
export default function guessFormat(input, formats) {
|
|
15
|
-
var _a;
|
|
2
|
+
import { getCommonFormatsForLocale } from './buildLocaleFromIntl.js';
|
|
3
|
+
export default function guessFormat(input, formats, lng) {
|
|
16
4
|
const str = input.trim();
|
|
17
5
|
if (!str) {
|
|
18
6
|
return null;
|
|
19
7
|
}
|
|
20
|
-
|
|
21
|
-
|
|
8
|
+
// helper: try a list of formats with your parse()
|
|
9
|
+
const tryFormats = (fmts) => {
|
|
10
|
+
for (const fmt of fmts) {
|
|
22
11
|
try {
|
|
23
|
-
|
|
24
|
-
parse(str, fmt);
|
|
12
|
+
parse(str, fmt); // will throw if not matching
|
|
25
13
|
return fmt;
|
|
26
14
|
}
|
|
27
15
|
catch (_a) {
|
|
28
|
-
// ignore
|
|
16
|
+
// ignore and continue
|
|
29
17
|
}
|
|
30
18
|
}
|
|
31
19
|
return null;
|
|
32
20
|
};
|
|
33
|
-
//
|
|
21
|
+
// if user provided formats, restrict to those
|
|
34
22
|
if (formats) {
|
|
35
23
|
const list = Array.isArray(formats) ? formats : [formats];
|
|
36
24
|
return tryFormats(list);
|
|
37
25
|
}
|
|
38
|
-
//
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
const
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
const looksMySQLDateTime = /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}(:\d{2}(\.\d+)?)?$/i.test(str);
|
|
57
|
-
const looksMySQLDate = /^\d{4}-\d{2}-\d{2}$/.test(str);
|
|
58
|
-
const looksTimeOnly = /^\d{2}:\d{2}(:\d{2}(\.\d+)?)?$/.test(str);
|
|
59
|
-
// Start building candidate formats (most specific first)
|
|
60
|
-
const candidates = [
|
|
61
|
-
...datetimeFormats.map(f => f.pattern),
|
|
62
|
-
];
|
|
63
|
-
// --- Full-text / locale-based formats ---
|
|
64
|
-
if (hasMonthName || hasWeekdayName) {
|
|
65
|
-
// e.g. "Monday 15 January 2024"
|
|
66
|
-
candidates.push('dddd, DD MMMM YYYY HH:II:SSZ', 'dddd, DD MMMM YYYY HH:II:SS', 'dddd, DD MMMM YYYY', 'DD MMMM YYYY HH:II:SSZ', 'DD MMMM YYYY HH:II:SS', 'DD MMMM YYYY', 'ddd, DD MMM YYYY HH:II:SSZ', 'ddd, DD MMM YYYY HH:II:SS', 'ddd, DD MMM YYYY');
|
|
67
|
-
// JS Date.toString() / toUTCString()-like
|
|
68
|
-
// "Tue Oct 29 2024 14:30:00 GMT+0200"
|
|
69
|
-
candidates.push('ddd MMM DD YYYY HH:II:SSZ', 'ddd, DD MMM YYYY HH:II:SS z');
|
|
70
|
-
}
|
|
71
|
-
// --- ISO / JS-like default formats ---
|
|
72
|
-
if (looksISO || str.includes('T')) {
|
|
73
|
-
candidates.push('YYYY-MM-DDTHH:II:SS.msZ', 'YYYY-MM-DDTHH:II:SSZ', 'YYYY-MM-DDTHH:II:SS.ms', 'YYYY-MM-DDTHH:II:SS', 'YYYY-MM-DDTHH:II:Z', 'YYYY-MM-DDTHH:II');
|
|
74
|
-
}
|
|
75
|
-
// --- MySQL classic formats ---
|
|
76
|
-
if (looksMySQLDateTime) {
|
|
77
|
-
candidates.push('YYYY-MM-DD HH:II:SS.msZ', 'YYYY-MM-DD HH:II:SSZ', 'YYYY-MM-DD HH:II:SS.ms', 'YYYY-MM-DD HH:II:SS', 'YYYY-MM-DD HH:II');
|
|
78
|
-
}
|
|
79
|
-
if (looksMySQLDate) {
|
|
80
|
-
candidates.push('YYYY-MM-DD');
|
|
81
|
-
}
|
|
82
|
-
// --- Time-only strings ---
|
|
83
|
-
if (looksTimeOnly) {
|
|
84
|
-
candidates.push(...timeFormats.map(f => f.pattern), 'HH:II:SS.msZ', 'HH:II:SS.ms', 'HH:II:SS', 'HH:II');
|
|
85
|
-
}
|
|
86
|
-
// --- Common EU / US formats ---
|
|
87
|
-
candidates.push(...dateFormats.map(f => f.pattern),
|
|
88
|
-
// European style
|
|
89
|
-
'DD/MM/YYYY HH:II:SSZ', 'DD/MM/YYYY HH:II:SS', 'DD/MM/YYYY HH:II', 'DD/MM/YYYY', 'DD-MM-YYYY HH:II:SSZ', 'DD-MM-YYYY HH:II:SS', 'DD-MM-YYYY HH:II', 'DD-MM-YYYY',
|
|
90
|
-
// US style
|
|
91
|
-
'MM/DD/YYYY HH:II:SSZ', 'MM/DD/YYYY HH:II:SS', 'MM/DD/YYYY HH:II', 'MM/DD/YYYY',
|
|
92
|
-
// Dot-separated
|
|
93
|
-
'YYYY.MM.DD HH:II:SSZ', 'YYYY.MM.DD HH:II:SS', 'YYYY.MM.DD',
|
|
94
|
-
// MySQL-ish (if we haven't already pushed them by detection)
|
|
95
|
-
'YYYY-MM-DD HH:II:SSZ', 'YYYY-MM-DD HH:II:SS', 'YYYY-MM-DD HH:II', 'YYYY-MM-DD');
|
|
96
|
-
// If we see clear timezone indicators, prioritize formats with Z / z
|
|
97
|
-
if (hasLetterTZ) {
|
|
98
|
-
const withTZ = candidates.filter(f => f.includes('Z') || f.includes('z'));
|
|
99
|
-
const withoutTZ = candidates.filter(f => !f.includes('Z') && !f.includes('z'));
|
|
100
|
-
const reordered = [...withTZ, ...withoutTZ];
|
|
101
|
-
const fmt = tryFormats(reordered);
|
|
102
|
-
if (fmt) {
|
|
103
|
-
return fmt;
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
else {
|
|
107
|
-
const fmt = tryFormats(candidates);
|
|
108
|
-
if (fmt) {
|
|
109
|
-
return fmt;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
// --- Last resort: native JS parsing ---
|
|
113
|
-
const jsDate = new Date(str);
|
|
114
|
-
if (!isNaN(jsDate.getTime())) {
|
|
115
|
-
// You can treat "native" as a special keyword meaning:
|
|
116
|
-
// "use Date/Temporal to parse directly".
|
|
117
|
-
return 'native';
|
|
118
|
-
}
|
|
26
|
+
// autodetect via Intl-derived formats
|
|
27
|
+
const resolvedLocale = lng ||
|
|
28
|
+
(typeof navigator !== 'undefined'
|
|
29
|
+
? navigator.language
|
|
30
|
+
: Intl.DateTimeFormat().resolvedOptions().locale);
|
|
31
|
+
const common = getCommonFormatsForLocale(resolvedLocale);
|
|
32
|
+
const candidates = [];
|
|
33
|
+
// prioritize datetime patterns first, then date, then time
|
|
34
|
+
candidates.push(...common.datetime.map(f => f.pattern), ...common.date.map(f => f.pattern), ...common.time.map(f => f.pattern));
|
|
35
|
+
const fmt = tryFormats(candidates);
|
|
36
|
+
if (fmt) {
|
|
37
|
+
return fmt;
|
|
38
|
+
}
|
|
39
|
+
// last resort: if you *really* want a "native" fallback, do it here
|
|
40
|
+
// const d = new Date(str);
|
|
41
|
+
// if (!Number.isNaN(d.getTime())) {
|
|
42
|
+
// return 'native';
|
|
43
|
+
// }
|
|
119
44
|
return null;
|
|
120
45
|
}
|