@bbn/bbn 2.0.61 → 2.0.63
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/dist/bbn.js +1 -1
- package/dist/bbn.js.map +1 -1
- package/dist/dt/classes/date.d.ts +5 -1
- package/dist/dt/classes/date.js +8 -1
- package/dist/dt/classes/dateTime.d.ts +4 -1
- package/dist/dt/classes/dateTime.js +4 -1
- package/dist/dt/classes/dt.d.ts +59 -0
- package/dist/dt/classes/dt.js +409 -0
- package/dist/dt/classes/duration.d.ts +39 -0
- package/dist/dt/classes/duration.js +185 -0
- package/dist/dt/classes/monthDay.d.ts +4 -1
- package/dist/dt/classes/monthDay.js +4 -1
- package/dist/dt/classes/time.d.ts +3 -1
- package/dist/dt/classes/time.js +4 -1
- package/dist/dt/classes/yearMonth.d.ts +4 -1
- package/dist/dt/classes/yearMonth.js +4 -1
- package/dist/dt/classes/zoned.d.ts +4 -1
- package/dist/dt/classes/zoned.js +4 -1
- package/dist/dt/functions/buildLocaleFromIntl.js +37 -32
- package/dist/dt/functions/getWeekday.d.ts +3 -0
- package/dist/dt/functions/getWeekday.js +58 -0
- package/dist/dt/functions/guessFormat.js +1 -62
- package/dist/dt/vars/types.d.ts +3 -0
- package/dist/dt/vars/types.js +1 -0
- package/dist/dt/vars/units.d.ts +11 -0
- package/dist/dt/vars/units.js +109 -0
- package/package.json +1 -1
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
2
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
3
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
4
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
5
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
6
|
+
};
|
|
7
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
8
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
9
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
10
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
11
|
+
};
|
|
12
|
+
var _bbnDtDuration_instances, _bbnDtDuration_value, _bbnDtDuration_unit, _bbnDtDuration_getUnitValue;
|
|
13
|
+
import { Temporal } from 'temporal-polyfill';
|
|
14
|
+
import { units, unitsCorrespondence } from '../vars/units.js';
|
|
15
|
+
import getRow from '../../fn/object/getRow.js';
|
|
16
|
+
const DURATION_RELATIVE_TO = Temporal.ZonedDateTime.from('1970-01-01T00:00Z[UTC]');
|
|
17
|
+
class bbnDtDuration {
|
|
18
|
+
static fromUnit(value, unit) {
|
|
19
|
+
const realUnit = unitsCorrespondence[unit] || 'ms';
|
|
20
|
+
if (!realUnit) {
|
|
21
|
+
throw new Error('Invalid unit for duration: ' + unit);
|
|
22
|
+
}
|
|
23
|
+
const ctx = [
|
|
24
|
+
realUnit === 'y' ? value : 0,
|
|
25
|
+
realUnit === 'm' ? value : 0,
|
|
26
|
+
realUnit === 'd' ? value : 0,
|
|
27
|
+
realUnit === 'h' ? value : 0,
|
|
28
|
+
realUnit === 'i' ? value : 0,
|
|
29
|
+
realUnit === 's' ? value : 0,
|
|
30
|
+
['y', 'm', 'd', 'h', 'i', 's'].includes(realUnit) ? 0 : value
|
|
31
|
+
];
|
|
32
|
+
const dur = new Temporal.Duration(...ctx);
|
|
33
|
+
return new bbnDtDuration(dur, 0, 0, 0, 0, 0, 0, realUnit);
|
|
34
|
+
}
|
|
35
|
+
constructor(y, m, d, h, i, s, ms, unit) {
|
|
36
|
+
_bbnDtDuration_instances.add(this);
|
|
37
|
+
_bbnDtDuration_value.set(this, void 0);
|
|
38
|
+
_bbnDtDuration_unit.set(this, void 0);
|
|
39
|
+
if (y instanceof Temporal.Duration) {
|
|
40
|
+
__classPrivateFieldSet(this, _bbnDtDuration_value, y, "f");
|
|
41
|
+
}
|
|
42
|
+
else if (typeof y === 'object') {
|
|
43
|
+
__classPrivateFieldSet(this, _bbnDtDuration_value, new Temporal.Duration(y.years || 0, y.months || 0, y.weeks || 0, y.days || 0, y.hours || 0, y.minutes || 0, y.seconds || 0, y.milliseconds || 0, 0, 0), "f");
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
__classPrivateFieldSet(this, _bbnDtDuration_value, new Temporal.Duration(y || 0, m || 0, d || 0, h || 0, i || 0, s || 0, ms || 0, 0, 0), "f");
|
|
47
|
+
}
|
|
48
|
+
const realUnit = unitsCorrespondence[unit || ''] || unit;
|
|
49
|
+
__classPrivateFieldSet(this, _bbnDtDuration_unit, realUnit || 'ms', "f");
|
|
50
|
+
const row = getRow(units, (a) => a[0] === realUnit);
|
|
51
|
+
if (!row) {
|
|
52
|
+
throw new Error('Invalid unit for duration: ' + realUnit);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
get value() {
|
|
56
|
+
return __classPrivateFieldGet(this, _bbnDtDuration_value, "f");
|
|
57
|
+
}
|
|
58
|
+
// -----------------------
|
|
59
|
+
// Public getters
|
|
60
|
+
// -----------------------
|
|
61
|
+
years(remaining = false) { return __classPrivateFieldGet(this, _bbnDtDuration_instances, "m", _bbnDtDuration_getUnitValue).call(this, 'year', remaining); }
|
|
62
|
+
months(remaining = false) { return __classPrivateFieldGet(this, _bbnDtDuration_instances, "m", _bbnDtDuration_getUnitValue).call(this, 'month', remaining); }
|
|
63
|
+
weeks(remaining = false) { return __classPrivateFieldGet(this, _bbnDtDuration_instances, "m", _bbnDtDuration_getUnitValue).call(this, 'week', remaining); }
|
|
64
|
+
days(remaining = false) { return __classPrivateFieldGet(this, _bbnDtDuration_instances, "m", _bbnDtDuration_getUnitValue).call(this, 'day', remaining); }
|
|
65
|
+
hours(remaining = false) { return __classPrivateFieldGet(this, _bbnDtDuration_instances, "m", _bbnDtDuration_getUnitValue).call(this, 'hour', remaining); }
|
|
66
|
+
minutes(remaining = false) { return __classPrivateFieldGet(this, _bbnDtDuration_instances, "m", _bbnDtDuration_getUnitValue).call(this, 'minute', remaining); }
|
|
67
|
+
seconds(remaining = false) { return __classPrivateFieldGet(this, _bbnDtDuration_instances, "m", _bbnDtDuration_getUnitValue).call(this, 'second', remaining); }
|
|
68
|
+
// -----------------------
|
|
69
|
+
// Day.js style
|
|
70
|
+
// "asX" conversions
|
|
71
|
+
// -----------------------
|
|
72
|
+
toJSON() {
|
|
73
|
+
return {
|
|
74
|
+
years: this.years(true),
|
|
75
|
+
months: this.months(true),
|
|
76
|
+
days: this.days(true),
|
|
77
|
+
hours: this.hours(true),
|
|
78
|
+
minutes: this.minutes(true),
|
|
79
|
+
seconds: this.seconds(true),
|
|
80
|
+
milliseconds: this.toMilliseconds()
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Returns the full duration expressed as X (float), like Day.js.
|
|
85
|
+
*/
|
|
86
|
+
asYears() {
|
|
87
|
+
return __classPrivateFieldGet(this, _bbnDtDuration_value, "f").total({
|
|
88
|
+
unit: 'year',
|
|
89
|
+
relativeTo: DURATION_RELATIVE_TO
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
asMonths() {
|
|
93
|
+
return __classPrivateFieldGet(this, _bbnDtDuration_value, "f").total({
|
|
94
|
+
unit: 'month',
|
|
95
|
+
relativeTo: DURATION_RELATIVE_TO
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
asWeeks() {
|
|
99
|
+
return __classPrivateFieldGet(this, _bbnDtDuration_value, "f").total({
|
|
100
|
+
unit: 'week',
|
|
101
|
+
relativeTo: DURATION_RELATIVE_TO
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
asDays() {
|
|
105
|
+
return __classPrivateFieldGet(this, _bbnDtDuration_value, "f").total({
|
|
106
|
+
unit: 'day',
|
|
107
|
+
relativeTo: DURATION_RELATIVE_TO
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
asHours() {
|
|
111
|
+
return __classPrivateFieldGet(this, _bbnDtDuration_value, "f").total({
|
|
112
|
+
unit: 'hour',
|
|
113
|
+
relativeTo: DURATION_RELATIVE_TO
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
asMinutes() {
|
|
117
|
+
return __classPrivateFieldGet(this, _bbnDtDuration_value, "f").total({
|
|
118
|
+
unit: 'minute',
|
|
119
|
+
relativeTo: DURATION_RELATIVE_TO
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
asSeconds() {
|
|
123
|
+
return __classPrivateFieldGet(this, _bbnDtDuration_value, "f").total({
|
|
124
|
+
unit: 'second',
|
|
125
|
+
relativeTo: DURATION_RELATIVE_TO
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Add any unit (or instance default).
|
|
130
|
+
*/
|
|
131
|
+
add(value, unit) {
|
|
132
|
+
const targetUnit = unit
|
|
133
|
+
? (unitsCorrespondence[unit] || unit)
|
|
134
|
+
: __classPrivateFieldGet(this, _bbnDtDuration_unit, "f");
|
|
135
|
+
// Map to Temporal.DurationLike field name, e.g. 'year' → 'years'
|
|
136
|
+
const field = (targetUnit + 's');
|
|
137
|
+
if (!['years', 'months', 'weeks', 'days', 'hours', 'minutes', 'seconds', 'milliseconds'].includes(field)) {
|
|
138
|
+
throw new Error('Invalid unit for duration: ' + (unit !== null && unit !== void 0 ? unit : targetUnit));
|
|
139
|
+
}
|
|
140
|
+
const delta = { [field]: value };
|
|
141
|
+
const newDuration = __classPrivateFieldGet(this, _bbnDtDuration_value, "f").add(delta);
|
|
142
|
+
// Adapt this constructor call to however you now construct your duration:
|
|
143
|
+
return new bbnDtDuration(newDuration, undefined, undefined, undefined, undefined, undefined, undefined, __classPrivateFieldGet(this, _bbnDtDuration_unit, "f"));
|
|
144
|
+
}
|
|
145
|
+
subtract(value, unit) {
|
|
146
|
+
return this.add(-value, unit);
|
|
147
|
+
}
|
|
148
|
+
toMilliseconds() {
|
|
149
|
+
const d = __classPrivateFieldGet(this, _bbnDtDuration_value, "f");
|
|
150
|
+
// If there are no calendar units, we can let Temporal do it directly:
|
|
151
|
+
if (!d.years && !d.months && !d.weeks && !d.days) {
|
|
152
|
+
return d.total({ unit: 'millisecond' });
|
|
153
|
+
}
|
|
154
|
+
// Otherwise we must supply a relativeTo (same as in asX)
|
|
155
|
+
return d.total({
|
|
156
|
+
unit: 'millisecond',
|
|
157
|
+
relativeTo: DURATION_RELATIVE_TO
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
_bbnDtDuration_value = new WeakMap(), _bbnDtDuration_unit = new WeakMap(), _bbnDtDuration_instances = new WeakSet(), _bbnDtDuration_getUnitValue = function _bbnDtDuration_getUnitValue(name, remaining) {
|
|
162
|
+
const d = __classPrivateFieldGet(this, _bbnDtDuration_value, "f"); // Temporal.Duration
|
|
163
|
+
if (remaining) {
|
|
164
|
+
switch (name) {
|
|
165
|
+
case 'year': return d.years;
|
|
166
|
+
case 'month': return d.months;
|
|
167
|
+
case 'week': return d.weeks;
|
|
168
|
+
case 'day': return d.days;
|
|
169
|
+
case 'hour': return d.hours;
|
|
170
|
+
case 'minute': return d.minutes;
|
|
171
|
+
case 'second':
|
|
172
|
+
// seconds component only; sub-second parts go to milliseconds in toJSON()
|
|
173
|
+
return d.seconds;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
// Total units: use Duration.total()
|
|
177
|
+
const total = d.total({
|
|
178
|
+
unit: name,
|
|
179
|
+
relativeTo: DURATION_RELATIVE_TO
|
|
180
|
+
});
|
|
181
|
+
// Keep same semantics as old code (Math.floor on totals)
|
|
182
|
+
return Math.floor(total);
|
|
183
|
+
};
|
|
184
|
+
export default bbnDtDuration;
|
|
185
|
+
;
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { Temporal } from 'temporal-polyfill';
|
|
2
|
-
|
|
2
|
+
import { BbnDtKind } from '../vars/types.js';
|
|
3
|
+
import bbnDt from './dt.js';
|
|
4
|
+
export default class bbnDtMonthDay extends bbnDt<Temporal.PlainMonthDay> {
|
|
3
5
|
#private;
|
|
6
|
+
readonly kind: BbnDtKind;
|
|
4
7
|
constructor(m?: any, d?: number);
|
|
5
8
|
get value(): Temporal.PlainMonthDay;
|
|
6
9
|
}
|
|
@@ -11,9 +11,12 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
11
11
|
};
|
|
12
12
|
var _bbnDtMonthDay_value;
|
|
13
13
|
import { Temporal } from 'temporal-polyfill';
|
|
14
|
-
|
|
14
|
+
import bbnDt from './dt.js';
|
|
15
|
+
class bbnDtMonthDay extends bbnDt {
|
|
15
16
|
constructor(m, d) {
|
|
17
|
+
super();
|
|
16
18
|
_bbnDtMonthDay_value.set(this, void 0);
|
|
19
|
+
this.kind = 'month-day';
|
|
17
20
|
if (!m) {
|
|
18
21
|
const d = new Date();
|
|
19
22
|
__classPrivateFieldSet(this, _bbnDtMonthDay_value, new Temporal.PlainMonthDay(d.getMonth() + 1, d.getDate()), "f");
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { Temporal } from 'temporal-polyfill';
|
|
2
|
-
|
|
2
|
+
import bbnDt from './dt.js';
|
|
3
|
+
export default class bbnDtTime extends bbnDt<Temporal.PlainTime> {
|
|
3
4
|
#private;
|
|
5
|
+
readonly kind: 'time';
|
|
4
6
|
constructor(h?: any, i?: number, s?: number, ms?: number);
|
|
5
7
|
get value(): Temporal.PlainTime;
|
|
6
8
|
}
|
package/dist/dt/classes/time.js
CHANGED
|
@@ -11,9 +11,12 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
11
11
|
};
|
|
12
12
|
var _bbnDtTime_value;
|
|
13
13
|
import { Temporal } from 'temporal-polyfill';
|
|
14
|
-
|
|
14
|
+
import bbnDt from './dt.js';
|
|
15
|
+
class bbnDtTime extends bbnDt {
|
|
15
16
|
constructor(h, i, s, ms) {
|
|
17
|
+
super();
|
|
16
18
|
_bbnDtTime_value.set(this, void 0);
|
|
19
|
+
this.kind = 'time';
|
|
17
20
|
if (!h) {
|
|
18
21
|
const d = new Date();
|
|
19
22
|
__classPrivateFieldSet(this, _bbnDtTime_value, new Temporal.PlainTime(d.getHours(), d.getMinutes(), d.getSeconds(), d.getMilliseconds() * 1000000), "f");
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { Temporal } from 'temporal-polyfill';
|
|
2
|
-
|
|
2
|
+
import { BbnDtKind } from '../vars/types.js';
|
|
3
|
+
import { bbnDt } from './dt.js';
|
|
4
|
+
export default class bbnDtYearMonth extends bbnDt<Temporal.PlainYearMonth> {
|
|
3
5
|
#private;
|
|
6
|
+
readonly kind: BbnDtKind;
|
|
4
7
|
constructor(y?: any, m?: number);
|
|
5
8
|
get value(): Temporal.PlainYearMonth;
|
|
6
9
|
}
|
|
@@ -11,9 +11,12 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
11
11
|
};
|
|
12
12
|
var _bbnDtYearMonth_value;
|
|
13
13
|
import { Temporal } from 'temporal-polyfill';
|
|
14
|
-
|
|
14
|
+
import { bbnDt } from './dt.js';
|
|
15
|
+
class bbnDtYearMonth extends bbnDt {
|
|
15
16
|
constructor(y, m) {
|
|
17
|
+
super();
|
|
16
18
|
_bbnDtYearMonth_value.set(this, void 0);
|
|
19
|
+
this.kind = 'year-month';
|
|
17
20
|
if (!y) {
|
|
18
21
|
const d = new Date();
|
|
19
22
|
__classPrivateFieldSet(this, _bbnDtYearMonth_value, new Temporal.PlainYearMonth(d.getFullYear(), d.getMonth() + 1), "f");
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { Temporal } from 'temporal-polyfill';
|
|
2
|
-
|
|
2
|
+
import { BbnDtKind } from '../vars/types.js';
|
|
3
|
+
import bbnDt from './dt.js';
|
|
4
|
+
export default class bbnDtZoned extends bbnDt<Temporal.ZonedDateTime> {
|
|
3
5
|
#private;
|
|
6
|
+
readonly kind: BbnDtKind;
|
|
4
7
|
constructor(z?: any, y?: any, m?: number, d?: number, h?: number, i?: number, s?: number, ms?: number);
|
|
5
8
|
get value(): Temporal.ZonedDateTime;
|
|
6
9
|
}
|
package/dist/dt/classes/zoned.js
CHANGED
|
@@ -12,9 +12,12 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
12
12
|
var _bbnDtZoned_value;
|
|
13
13
|
import { Temporal } from 'temporal-polyfill';
|
|
14
14
|
import fromJsDate from '../functions/fromJsDate.js';
|
|
15
|
-
|
|
15
|
+
import bbnDt from './dt.js';
|
|
16
|
+
class bbnDtZoned extends bbnDt {
|
|
16
17
|
constructor(z, y, m, d, h, i, s, ms) {
|
|
18
|
+
super();
|
|
17
19
|
_bbnDtZoned_value.set(this, void 0);
|
|
20
|
+
this.kind = 'zoned';
|
|
18
21
|
if (!z) {
|
|
19
22
|
const date = new Date();
|
|
20
23
|
__classPrivateFieldSet(this, _bbnDtZoned_value, new Temporal.ZonedDateTime(BigInt(date.getTime() * 1000000), Intl.DateTimeFormat().resolvedOptions().timeZone), "f");
|
|
@@ -3,23 +3,27 @@ import extend from "../../fn/object/extend.js";
|
|
|
3
3
|
* Build a token pattern (YYYY, MM, DD, dddd, HH, II, SS, A, z) from Intl parts.
|
|
4
4
|
* Uses Intl options to distinguish MMM vs MMMM, ddd vs dddd, etc.
|
|
5
5
|
*/
|
|
6
|
-
|
|
6
|
+
function partsToPattern(parts, hourCycle, opts) {
|
|
7
7
|
let pattern = '';
|
|
8
|
-
const hourCycle = resolved.hourCycle;
|
|
9
8
|
const hasDayPeriod = parts.some(p => p.type === 'dayPeriod');
|
|
10
9
|
const is12h = hasDayPeriod || hourCycle === 'h12' || hourCycle === 'h11';
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
10
|
+
const hasWeekday = !!opts.weekday;
|
|
11
|
+
const hasTextMonth = opts.month === 'short' || opts.month === 'long';
|
|
12
|
+
// when we *request* year/month/day in "numeric" (not 2-digit, not short),
|
|
13
|
+
// and all three are present, then we want D/M/YYYY in our mask,
|
|
14
|
+
// in the locale's order, even if the sample shows "02" / "01".
|
|
15
|
+
const requestedPureNumericYMD = opts.year === 'numeric' &&
|
|
16
|
+
opts.month === 'numeric' &&
|
|
17
|
+
opts.day === 'numeric' &&
|
|
18
|
+
!hasWeekday &&
|
|
19
|
+
!hasTextMonth;
|
|
18
20
|
for (const p of parts) {
|
|
19
21
|
switch (p.type) {
|
|
20
22
|
case 'year': {
|
|
21
|
-
//
|
|
22
|
-
|
|
23
|
+
// If you want YY vs YYYY disambiguation you can still
|
|
24
|
+
// look at opts.year here; I’ll keep it simple:
|
|
25
|
+
// numeric → YYYY, '2-digit' → YY
|
|
26
|
+
if (opts.year === '2-digit') {
|
|
23
27
|
pattern += 'YY';
|
|
24
28
|
}
|
|
25
29
|
else {
|
|
@@ -28,28 +32,33 @@ const partsToPattern = (parts, resolved, requestedOpts) => {
|
|
|
28
32
|
break;
|
|
29
33
|
}
|
|
30
34
|
case 'month': {
|
|
31
|
-
//
|
|
32
|
-
if (
|
|
33
|
-
pattern +=
|
|
35
|
+
// Textual month first
|
|
36
|
+
if (opts.month === 'short') {
|
|
37
|
+
pattern += 'MMM';
|
|
34
38
|
break;
|
|
35
39
|
}
|
|
36
|
-
if (
|
|
37
|
-
|
|
40
|
+
if (opts.month === 'long') {
|
|
41
|
+
pattern += 'MMMM';
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
// 👉 Pure numeric Y-M-D requested: always M
|
|
45
|
+
if (requestedPureNumericYMD) {
|
|
38
46
|
pattern += 'M';
|
|
39
47
|
break;
|
|
40
48
|
}
|
|
41
|
-
//
|
|
49
|
+
// Other numeric month cases (year-month, month-day, or 2-digit)
|
|
42
50
|
if (/^\d+$/.test(p.value)) {
|
|
43
51
|
pattern += p.value.length === 2 ? 'MM' : 'M';
|
|
44
52
|
}
|
|
45
53
|
else {
|
|
54
|
+
// should not happen, but be defensive
|
|
46
55
|
pattern += p.value.length > 3 ? 'MMMM' : 'MMM';
|
|
47
56
|
}
|
|
48
57
|
break;
|
|
49
58
|
}
|
|
50
59
|
case 'day': {
|
|
51
|
-
|
|
52
|
-
|
|
60
|
+
// 👉 Pure numeric Y-M-D requested: always D
|
|
61
|
+
if (requestedPureNumericYMD) {
|
|
53
62
|
pattern += 'D';
|
|
54
63
|
break;
|
|
55
64
|
}
|
|
@@ -57,10 +66,10 @@ const partsToPattern = (parts, resolved, requestedOpts) => {
|
|
|
57
66
|
break;
|
|
58
67
|
}
|
|
59
68
|
case 'weekday': {
|
|
60
|
-
if (
|
|
69
|
+
if (opts.weekday === 'short' || opts.weekday === 'narrow') {
|
|
61
70
|
pattern += 'ddd';
|
|
62
71
|
}
|
|
63
|
-
else if (
|
|
72
|
+
else if (opts.weekday === 'long') {
|
|
64
73
|
pattern += 'dddd';
|
|
65
74
|
}
|
|
66
75
|
else {
|
|
@@ -90,20 +99,15 @@ const partsToPattern = (parts, resolved, requestedOpts) => {
|
|
|
90
99
|
pattern += 'z';
|
|
91
100
|
break;
|
|
92
101
|
case 'literal': {
|
|
93
|
-
if (!p.value)
|
|
102
|
+
if (!p.value)
|
|
94
103
|
break;
|
|
95
|
-
|
|
96
|
-
// If the literal contains any letter (ASCII or basic Latin-1),
|
|
97
|
-
// wrap it in [ ... ] so it can't be confused with tokens.
|
|
98
|
-
// Otherwise (spaces, /, -, :, commas, etc.) keep it raw.
|
|
104
|
+
// Only wrap *text* literals in [ ... ], not separators like /, -, spaces, etc.
|
|
99
105
|
const hasLetter = /[A-Za-zÀ-ÖØ-öø-ÿ]/.test(p.value);
|
|
100
106
|
if (hasLetter) {
|
|
101
|
-
// Escape ']' inside the bracketed literal
|
|
102
107
|
const v = p.value.replace(/]/g, '\\]');
|
|
103
108
|
pattern += `[${v}]`;
|
|
104
109
|
}
|
|
105
110
|
else {
|
|
106
|
-
// Non-problematic punctuation/whitespace: just append as-is
|
|
107
111
|
pattern += p.value;
|
|
108
112
|
}
|
|
109
113
|
break;
|
|
@@ -114,7 +118,8 @@ const partsToPattern = (parts, resolved, requestedOpts) => {
|
|
|
114
118
|
}
|
|
115
119
|
}
|
|
116
120
|
return pattern;
|
|
117
|
-
}
|
|
121
|
+
}
|
|
122
|
+
;
|
|
118
123
|
/**
|
|
119
124
|
* Get a curated set of *common* date, time and datetime formats
|
|
120
125
|
* for the given locale, without exploding into thousands of combos.
|
|
@@ -162,7 +167,7 @@ const getCommonFormatsForLocale = (lng) => {
|
|
|
162
167
|
const fmt = new Intl.DateTimeFormat(lng, opts);
|
|
163
168
|
const parts = fmt.formatToParts(sample);
|
|
164
169
|
const resolved = fmt.resolvedOptions();
|
|
165
|
-
const pattern = partsToPattern(parts, resolved, opts);
|
|
170
|
+
const pattern = partsToPattern(parts, resolved.hourCycle, opts);
|
|
166
171
|
if (!seenDatePatterns.has(pattern)) {
|
|
167
172
|
seenDatePatterns.add(pattern);
|
|
168
173
|
date.push({
|
|
@@ -189,7 +194,7 @@ const getCommonFormatsForLocale = (lng) => {
|
|
|
189
194
|
const fmt = new Intl.DateTimeFormat(lng, opts);
|
|
190
195
|
const parts = fmt.formatToParts(sample);
|
|
191
196
|
const resolved = fmt.resolvedOptions();
|
|
192
|
-
const pattern = partsToPattern(parts, resolved, opts);
|
|
197
|
+
const pattern = partsToPattern(parts, resolved.hourCycle, opts);
|
|
193
198
|
if (!seenTimePatterns.has(pattern)) {
|
|
194
199
|
seenTimePatterns.add(pattern);
|
|
195
200
|
time.push({
|
|
@@ -206,7 +211,7 @@ const getCommonFormatsForLocale = (lng) => {
|
|
|
206
211
|
const fmt = new Intl.DateTimeFormat(lng, opts);
|
|
207
212
|
const parts = fmt.formatToParts(sample);
|
|
208
213
|
const resolved = fmt.resolvedOptions();
|
|
209
|
-
const pattern = partsToPattern(parts, resolved, opts);
|
|
214
|
+
const pattern = partsToPattern(parts, resolved.hourCycle, opts);
|
|
210
215
|
if (!seenDateTimePatterns.has(pattern)) {
|
|
211
216
|
seenDateTimePatterns.add(pattern);
|
|
212
217
|
datetime.push({
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
const getWeekday = (n, mode = 'long', locale) => {
|
|
2
|
+
if (!mode) {
|
|
3
|
+
const letter = getWeekday(n, 'narrow', locale);
|
|
4
|
+
const abbr = getWeekday(n, 'short', locale);
|
|
5
|
+
const full = getWeekday(n, 'long', locale);
|
|
6
|
+
return {
|
|
7
|
+
letter,
|
|
8
|
+
abbr,
|
|
9
|
+
full,
|
|
10
|
+
long: full,
|
|
11
|
+
short: abbr,
|
|
12
|
+
narrow: letter
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
let m;
|
|
16
|
+
if (mode === 'letter') {
|
|
17
|
+
m = 'narrow';
|
|
18
|
+
}
|
|
19
|
+
else if (mode === 'abbr') {
|
|
20
|
+
m = 'short';
|
|
21
|
+
}
|
|
22
|
+
else if (mode === 'full') {
|
|
23
|
+
m = 'long';
|
|
24
|
+
}
|
|
25
|
+
else if (!['long', 'short', 'narrow'].includes(mode)) {
|
|
26
|
+
throw new Error('Invalid mode for getWeekDay: ' + mode + '. Allowed values are "long", "short", "narrow", "letter", "abbr", "full".');
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
m = mode;
|
|
30
|
+
}
|
|
31
|
+
// Create a date with the right weekday
|
|
32
|
+
// 2023-01-01 was a Sunday → base for offset
|
|
33
|
+
const base = new Date(2023, 0, 1 + n);
|
|
34
|
+
return base.toLocaleDateString([locale || bbn.env.lang, ...navigator.languages], { weekday: m });
|
|
35
|
+
};
|
|
36
|
+
const getWeekdayIndex = (name, locale) => {
|
|
37
|
+
const loc = locale || bbn.env.lang;
|
|
38
|
+
const input = name.trim().toLowerCase();
|
|
39
|
+
// Build a localized map only once per locale (optional optimization)
|
|
40
|
+
const langs = [loc, ...navigator.languages];
|
|
41
|
+
for (let i = 0; i < langs.length; i++) {
|
|
42
|
+
if (!langs[i]) {
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
const formatter = new Intl.DateTimeFormat(langs[i], { weekday: "long" });
|
|
46
|
+
// Generate localized weekday names for Sun → Sat
|
|
47
|
+
for (let i = 0; i < 7; i++) {
|
|
48
|
+
// 2023-01-01 was Sunday
|
|
49
|
+
const date = new Date(2023, 0, 1 + i);
|
|
50
|
+
const localized = formatter.format(date).toLowerCase();
|
|
51
|
+
if (localized === input) {
|
|
52
|
+
return i; // JS weekday number
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
throw new Error(`Unknown weekday name '${name}' for locale '${loc}'`);
|
|
57
|
+
};
|
|
58
|
+
export { getWeekday, getWeekdayIndex };
|
|
@@ -30,54 +30,6 @@ const MYSQL_AND_NATIVE_FORMATS = [
|
|
|
30
30
|
// Tue Oct 29 2024 14:30:00
|
|
31
31
|
'ddd MMM DD YYYY HH:II:SS'
|
|
32
32
|
];
|
|
33
|
-
const isPureNumericDateFormat = (fmt) => {
|
|
34
|
-
// Only Y/M/D tokens and literal separators, no time or AM/PM tokens
|
|
35
|
-
if (/[HhI SAz]/.test(fmt)) {
|
|
36
|
-
return false;
|
|
37
|
-
}
|
|
38
|
-
// Must have year and month and day tokens
|
|
39
|
-
if (!/[Y]/.test(fmt) || !/[M]/.test(fmt) || !/[D]/.test(fmt)) {
|
|
40
|
-
return false;
|
|
41
|
-
}
|
|
42
|
-
return true;
|
|
43
|
-
};
|
|
44
|
-
const makeRelaxedNumericFormat = (fmt) => {
|
|
45
|
-
// Relax DD -> D and MM -> M, but don't touch other tokens
|
|
46
|
-
return fmt.replace(/DD/g, 'D').replace(/MM/g, 'M');
|
|
47
|
-
};
|
|
48
|
-
/**
|
|
49
|
-
* If the format is a pure numeric date like D/M/YYYY or DD/MM/YYYY,
|
|
50
|
-
* and the input clearly uses 2-digit day and 2-digit month (22/11/2022),
|
|
51
|
-
* upgrade to DD/MM/YYYY.
|
|
52
|
-
*/
|
|
53
|
-
const normalizeNumericDM = (fmt, input) => {
|
|
54
|
-
// Only touch "pure numeric date" patterns: D/M/YYYY, DD-MM-YY, etc.
|
|
55
|
-
// No time tokens, no text months, no weekdays.
|
|
56
|
-
if (/[HhI SAzM]{2,}|[A-Za-z]/.test(fmt.replace(/[DMY]/g, ''))) {
|
|
57
|
-
// If there are other letters than D/M/Y (like MMM, ddd), don't touch.
|
|
58
|
-
// (We only want simple numeric dates)
|
|
59
|
-
return fmt;
|
|
60
|
-
}
|
|
61
|
-
// Quick check: must contain D and M and Y
|
|
62
|
-
if (!fmt.includes('D') || !fmt.includes('M') || !fmt.includes('Y')) {
|
|
63
|
-
return fmt;
|
|
64
|
-
}
|
|
65
|
-
// Extract numeric chunks from the input: ["22", "11", "2022"] for "22/11/2022"
|
|
66
|
-
const nums = input.split(/\D+/).filter(Boolean);
|
|
67
|
-
if (nums.length < 3) {
|
|
68
|
-
return fmt;
|
|
69
|
-
}
|
|
70
|
-
const [dayStr, monthStr] = nums;
|
|
71
|
-
// Only upgrade if both day and month are exactly 2-digit
|
|
72
|
-
if (dayStr.length === 2 && monthStr.length === 2) {
|
|
73
|
-
// Upgrade first D-group to DD and first M-group to MM
|
|
74
|
-
let out = fmt;
|
|
75
|
-
out = out.replace(/D+/, 'DD');
|
|
76
|
-
out = out.replace(/M+/, 'MM');
|
|
77
|
-
return out;
|
|
78
|
-
}
|
|
79
|
-
return fmt;
|
|
80
|
-
};
|
|
81
33
|
export default function guessFormat(input, formats, lng) {
|
|
82
34
|
const str = input.trim();
|
|
83
35
|
if (!str) {
|
|
@@ -89,24 +41,11 @@ export default function guessFormat(input, formats, lng) {
|
|
|
89
41
|
// 1) Try strict format first
|
|
90
42
|
try {
|
|
91
43
|
parse(str, fmt);
|
|
92
|
-
return
|
|
44
|
+
return fmt;
|
|
93
45
|
}
|
|
94
46
|
catch (_a) {
|
|
95
47
|
// ignore, we'll maybe try a relaxed version
|
|
96
48
|
}
|
|
97
|
-
// 2) If it's a pure numeric date pattern, try a relaxed version too
|
|
98
|
-
if (isPureNumericDateFormat(fmt)) {
|
|
99
|
-
const relaxed = makeRelaxedNumericFormat(fmt);
|
|
100
|
-
if (relaxed !== fmt) {
|
|
101
|
-
try {
|
|
102
|
-
parse(str, relaxed);
|
|
103
|
-
return relaxed;
|
|
104
|
-
}
|
|
105
|
-
catch (_b) {
|
|
106
|
-
// still nothing, move on
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
49
|
}
|
|
111
50
|
return null;
|
|
112
51
|
};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { Temporal } from 'temporal-polyfill';
|
|
2
|
+
export type BbnDtKind = 'datetime' | 'date' | 'time' | 'year-month' | 'month-day' | 'zoned';
|
|
3
|
+
export type BbnDtTemporal = Temporal.PlainDateTime | Temporal.PlainDate | Temporal.PlainTime | Temporal.PlainYearMonth | Temporal.PlainMonthDay | Temporal.ZonedDateTime;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
declare const units: [string, Intl.RelativeTimeFormatUnit, number][];
|
|
2
|
+
declare const unitsCorrespondence: {
|
|
3
|
+
[key: string]: string;
|
|
4
|
+
};
|
|
5
|
+
declare const unitsMap: {
|
|
6
|
+
[key: string]: string;
|
|
7
|
+
};
|
|
8
|
+
declare const formatsMap: {
|
|
9
|
+
[key: string]: string;
|
|
10
|
+
};
|
|
11
|
+
export { units, unitsCorrespondence, unitsMap, formatsMap };
|