@bbn/bbn 2.0.28 → 2.0.30

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.
@@ -155,12 +155,15 @@ export default function buildLocaleFromIntl() {
155
155
  weekdaysLong.push(fmtWeekLong.format(d));
156
156
  weekdaysShort.push(fmtWeekShort.format(d));
157
157
  }
158
- const { date, time } = getCommonFormatsForLocale(langs);
158
+ const { date, time, datetime } = getCommonFormatsForLocale(langs);
159
159
  extend(bbn.dt.locales, {
160
160
  monthsLong,
161
161
  monthsShort,
162
162
  weekdaysLong,
163
163
  weekdaysShort,
164
+ date,
165
+ time,
166
+ datetime
164
167
  });
165
168
  }
166
169
  ;
@@ -0,0 +1,12 @@
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;
@@ -0,0 +1,120 @@
1
+ import buildLocaleFromIntl from './buildLocaleFromIntl.js';
2
+ import parse from './parse.js';
3
+ /**
4
+ * Guess a date format string for the given input.
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;
16
+ const str = input.trim();
17
+ if (!str) {
18
+ return null;
19
+ }
20
+ const tryFormats = (formatsToTry) => {
21
+ for (const fmt of formatsToTry) {
22
+ try {
23
+ // We only care that it parses without throwing
24
+ parse(str, fmt);
25
+ return fmt;
26
+ }
27
+ catch (_a) {
28
+ // ignore
29
+ }
30
+ }
31
+ return null;
32
+ };
33
+ // If user provided formats, restrict to those only
34
+ if (formats) {
35
+ const list = Array.isArray(formats) ? formats : [formats];
36
+ return tryFormats(list);
37
+ }
38
+ // -------- Autodetection mode (no user-provided formats) --------
39
+ const lower = str.toLowerCase();
40
+ // Access locales for full-text formats (months / weekdays)
41
+ buildLocaleFromIntl();
42
+ const loc = ((_a = bbn === null || bbn === void 0 ? void 0 : bbn.dt) === null || _a === void 0 ? void 0 : _a.locales) || {};
43
+ const monthsLong = loc.monthsLong || [];
44
+ const monthsShort = loc.monthsShort || [];
45
+ const weekdaysLong = loc.weekdaysLong || [];
46
+ const weekdaysShort = loc.weekdaysShort || [];
47
+ const timeFormats = loc.time || [];
48
+ const dateFormats = loc.date || [];
49
+ const datetimeFormats = loc.datetime || [];
50
+ const hasMonthName = monthsLong.some(m => lower.includes(m.toLowerCase())) ||
51
+ monthsShort.some(m => lower.includes(m.toLowerCase()));
52
+ const hasWeekdayName = weekdaysLong.some(w => lower.includes(w.toLowerCase())) ||
53
+ weekdaysShort.some(w => lower.includes(w.toLowerCase()));
54
+ const hasLetterTZ = /gmt|utc|[+-]\d{2}:?\d{2}|z$/i.test(str);
55
+ const looksISO = /^\d{4}-\d{2}-\d{2}t\d{2}:\d{2}:\d{2}(\.\d+)?(z|[+\-]\d{2}:?\d{2})?$/i.test(str);
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
+ }
119
+ return null;
120
+ }
package/dist/dt.d.ts CHANGED
@@ -1,8 +1,10 @@
1
1
  import parse from './dt/functions/parse.js';
2
+ import guessFormat from './dt/functions/guessFormat.js';
2
3
  declare const dt: {
3
4
  (value: any, inputFormat?: null | String): void;
4
5
  locales: any;
5
6
  parse: typeof parse;
7
+ guessFormat: typeof guessFormat;
6
8
  time(): void;
7
9
  date(): void;
8
10
  dateTime(): void;
package/dist/dt.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import parse from './dt/functions/parse.js';
2
+ import guessFormat from './dt/functions/guessFormat.js';
2
3
  const patterns = [
3
4
  // MariaDB DATETIME "YYYY-MM-DD HH:MM:SS"
4
5
  {
@@ -191,6 +192,7 @@ const dt = (value, inputFormat = null) => {
191
192
  };
192
193
  dt.locales = Object.create(null);
193
194
  dt.parse = parse;
195
+ dt.guessFormat = guessFormat;
194
196
  dt.time = () => { };
195
197
  dt.date = () => { };
196
198
  dt.dateTime = () => { };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bbn/bbn",
3
- "version": "2.0.28",
3
+ "version": "2.0.30",
4
4
  "description": "Javascript toolkit",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",