@webority-technologies/mobile-core 0.0.4 → 0.0.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/lib/commonjs/formatters/dateMath.js +310 -0
- package/lib/commonjs/formatters/index.js +73 -0
- package/lib/commonjs/index.js +72 -0
- package/lib/module/formatters/dateMath.js +294 -0
- package/lib/module/formatters/index.js +1 -0
- package/lib/module/index.js +1 -1
- package/lib/typescript/commonjs/formatters/dateMath.d.ts +88 -0
- package/lib/typescript/commonjs/formatters/index.d.ts +1 -0
- package/lib/typescript/commonjs/index.d.ts +1 -1
- package/lib/typescript/module/formatters/dateMath.d.ts +88 -0
- package/lib/typescript/module/formatters/index.d.ts +1 -0
- package/lib/typescript/module/index.d.ts +1 -1
- package/package.json +3 -2
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.startOfDay = exports.isSameDay = exports.isDateBefore = exports.isDateAfter = exports.formatTimeInZone = exports.formatTimeInWindowsZone = exports.formatTime12h = exports.formatDatePattern = exports.formatDateISO = exports.formatDateDDMMMYYYY = exports.diffMs = exports.addDays = void 0;
|
|
7
|
+
var _windowsIana = require("windows-iana");
|
|
8
|
+
const toDate = value => {
|
|
9
|
+
if (value instanceof Date) {
|
|
10
|
+
return Number.isNaN(value.getTime()) ? null : value;
|
|
11
|
+
}
|
|
12
|
+
const d = new Date(value);
|
|
13
|
+
return Number.isNaN(d.getTime()) ? null : d;
|
|
14
|
+
};
|
|
15
|
+
const PAD = n => n < 10 ? `0${n}` : `${n}`;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Whether two values fall on the same calendar day in the device's local
|
|
19
|
+
* timezone. Invalid input on either side returns false rather than throwing.
|
|
20
|
+
*/
|
|
21
|
+
const isSameDay = (a, b) => {
|
|
22
|
+
const da = toDate(a);
|
|
23
|
+
const db = toDate(b);
|
|
24
|
+
if (!da || !db) {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
return da.getFullYear() === db.getFullYear() && da.getMonth() === db.getMonth() && da.getDate() === db.getDate();
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/** `a` is strictly before `b`. Invalid input on either side returns false. */
|
|
31
|
+
exports.isSameDay = isSameDay;
|
|
32
|
+
const isDateBefore = (a, b) => {
|
|
33
|
+
const da = toDate(a);
|
|
34
|
+
const db = toDate(b);
|
|
35
|
+
return da !== null && db !== null && da.getTime() < db.getTime();
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/** `a` is strictly after `b`. Invalid input on either side returns false. */
|
|
39
|
+
exports.isDateBefore = isDateBefore;
|
|
40
|
+
const isDateAfter = (a, b) => {
|
|
41
|
+
const da = toDate(a);
|
|
42
|
+
const db = toDate(b);
|
|
43
|
+
return da !== null && db !== null && da.getTime() > db.getTime();
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* `a - b` in milliseconds, matching dayjs's `a.diff(b)` sign convention
|
|
48
|
+
* (positive when `a` is later than `b`). Returns `NaN` if either side fails
|
|
49
|
+
* to parse, the same way subtracting two invalid dayjs objects would.
|
|
50
|
+
*/
|
|
51
|
+
exports.isDateAfter = isDateAfter;
|
|
52
|
+
const diffMs = (a, b) => {
|
|
53
|
+
const da = toDate(a);
|
|
54
|
+
const db = toDate(b);
|
|
55
|
+
if (!da || !db) {
|
|
56
|
+
return Number.NaN;
|
|
57
|
+
}
|
|
58
|
+
return da.getTime() - db.getTime();
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Midnight of the given date, in the device's local timezone. Returns null
|
|
63
|
+
* for unparseable input.
|
|
64
|
+
*/
|
|
65
|
+
exports.diffMs = diffMs;
|
|
66
|
+
const startOfDay = value => {
|
|
67
|
+
const d = toDate(value);
|
|
68
|
+
if (!d) {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
const start = new Date(d);
|
|
72
|
+
start.setHours(0, 0, 0, 0);
|
|
73
|
+
return start;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Adds (or, with a negative count, subtracts) whole calendar days in the
|
|
78
|
+
* device's local timezone. Returns null for unparseable input.
|
|
79
|
+
*/
|
|
80
|
+
exports.startOfDay = startOfDay;
|
|
81
|
+
const addDays = (value, count) => {
|
|
82
|
+
const d = toDate(value);
|
|
83
|
+
if (!d) {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
const next = new Date(d);
|
|
87
|
+
next.setDate(next.getDate() + count);
|
|
88
|
+
return next;
|
|
89
|
+
};
|
|
90
|
+
exports.addDays = addDays;
|
|
91
|
+
const WEEKDAY_SHORT = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
|
|
92
|
+
const WEEKDAY_LONG = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
|
|
93
|
+
const MONTH_LONG = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
|
|
94
|
+
|
|
95
|
+
// Longest-first so 'YYYY' is tried before 'YY', 'DD' before 'D', etc. — a
|
|
96
|
+
// greedy single pass over the pattern, not a regex, so a literal character
|
|
97
|
+
// (a comma, a colon, a digit) can never accidentally match a token.
|
|
98
|
+
const TOKENS = ['YYYY', 'YY', 'MMMM', 'MMM', 'MM', 'M', 'DD', 'D', 'dddd', 'ddd', 'HH', 'H', 'hh', 'h', 'mm', 'm', 'ss', 's', 'A', 'a'];
|
|
99
|
+
const tokenizePattern = pattern => {
|
|
100
|
+
const result = [];
|
|
101
|
+
let i = 0;
|
|
102
|
+
outer: while (i < pattern.length) {
|
|
103
|
+
for (const token of TOKENS) {
|
|
104
|
+
if (pattern.startsWith(token, i)) {
|
|
105
|
+
result.push(token);
|
|
106
|
+
i += token.length;
|
|
107
|
+
continue outer;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
result.push(pattern[i]);
|
|
111
|
+
i += 1;
|
|
112
|
+
}
|
|
113
|
+
return result;
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Small dayjs/moment-style token formatter — YYYY/YY, MMMM/MMM/MM/M,
|
|
118
|
+
* DD/D, dddd/ddd, HH/H (24h), hh/h (12h), mm/m, ss/s, A/a (upper/lower AM/PM).
|
|
119
|
+
* Everything else in the pattern (spaces, commas, colons) passes through
|
|
120
|
+
* literally. Hand-rolled rather than a dependency because this fleet's date
|
|
121
|
+
* formatting needs are a small, closed token set, not general i18n — for
|
|
122
|
+
* genuinely locale-aware output, `formatDate`/`formatTime` (Intl-backed, in
|
|
123
|
+
* `./date`) are the ones to reach for; this is for matching an exact
|
|
124
|
+
* existing pattern (a legacy display string, an API's expected shape).
|
|
125
|
+
*
|
|
126
|
+
* `utc: true` reads every field from the UTC calendar/clock instead of the
|
|
127
|
+
* device's local one — see `formatDateDDMMMYYYY`'s note on why this isn't
|
|
128
|
+
* cosmetic.
|
|
129
|
+
*/
|
|
130
|
+
const formatDatePattern = (value, pattern, options) => {
|
|
131
|
+
const d = toDate(value);
|
|
132
|
+
if (!d) {
|
|
133
|
+
return '';
|
|
134
|
+
}
|
|
135
|
+
const utc = options?.utc ?? false;
|
|
136
|
+
const year = utc ? d.getUTCFullYear() : d.getFullYear();
|
|
137
|
+
const month = utc ? d.getUTCMonth() : d.getMonth();
|
|
138
|
+
const day = utc ? d.getUTCDate() : d.getDate();
|
|
139
|
+
const weekday = utc ? d.getUTCDay() : d.getDay();
|
|
140
|
+
const hours24 = utc ? d.getUTCHours() : d.getHours();
|
|
141
|
+
const minutes = utc ? d.getUTCMinutes() : d.getMinutes();
|
|
142
|
+
const seconds = utc ? d.getUTCSeconds() : d.getSeconds();
|
|
143
|
+
const {
|
|
144
|
+
hour12,
|
|
145
|
+
period
|
|
146
|
+
} = to12Hour(hours24);
|
|
147
|
+
return tokenizePattern(pattern).map(t => {
|
|
148
|
+
switch (t) {
|
|
149
|
+
case 'YYYY':
|
|
150
|
+
return String(year);
|
|
151
|
+
case 'YY':
|
|
152
|
+
return String(year).slice(-2);
|
|
153
|
+
case 'MMMM':
|
|
154
|
+
return MONTH_LONG[month];
|
|
155
|
+
case 'MMM':
|
|
156
|
+
return MONTH_SHORT[month];
|
|
157
|
+
case 'MM':
|
|
158
|
+
return PAD(month + 1);
|
|
159
|
+
case 'M':
|
|
160
|
+
return String(month + 1);
|
|
161
|
+
case 'DD':
|
|
162
|
+
return PAD(day);
|
|
163
|
+
case 'D':
|
|
164
|
+
return String(day);
|
|
165
|
+
case 'dddd':
|
|
166
|
+
return WEEKDAY_LONG[weekday];
|
|
167
|
+
case 'ddd':
|
|
168
|
+
return WEEKDAY_SHORT[weekday];
|
|
169
|
+
case 'HH':
|
|
170
|
+
return PAD(hours24);
|
|
171
|
+
case 'H':
|
|
172
|
+
return String(hours24);
|
|
173
|
+
case 'hh':
|
|
174
|
+
return PAD(hour12);
|
|
175
|
+
case 'h':
|
|
176
|
+
return String(hour12);
|
|
177
|
+
case 'mm':
|
|
178
|
+
return PAD(minutes);
|
|
179
|
+
case 'm':
|
|
180
|
+
return String(minutes);
|
|
181
|
+
case 'ss':
|
|
182
|
+
return PAD(seconds);
|
|
183
|
+
case 's':
|
|
184
|
+
return String(seconds);
|
|
185
|
+
case 'A':
|
|
186
|
+
return period;
|
|
187
|
+
case 'a':
|
|
188
|
+
return period.toLowerCase();
|
|
189
|
+
default:
|
|
190
|
+
return t;
|
|
191
|
+
}
|
|
192
|
+
}).join('');
|
|
193
|
+
};
|
|
194
|
+
exports.formatDatePattern = formatDatePattern;
|
|
195
|
+
const MONTH_SHORT = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* `DD MMM, YYYY` — zero-padded day, short month, comma, year (e.g.
|
|
199
|
+
* `05 Sep, 2025`). A specific legacy pattern some apps already display,
|
|
200
|
+
* not the fleet's own product convention: `formatDate` (the Intl `style`-based
|
|
201
|
+
* formatter in `./date`) is the one to reach for in new code. This exists so
|
|
202
|
+
* an app already showing this exact pattern can move off a date library
|
|
203
|
+
* without a visible change.
|
|
204
|
+
*
|
|
205
|
+
* `utc: true` reads the calendar day from the UTC fields instead of the
|
|
206
|
+
* device's local ones — matching `dayjs.utc(x).format(...)`, not
|
|
207
|
+
* `dayjs(x).format(...)`. The two disagree whenever local time has crossed a
|
|
208
|
+
* day boundary UTC hasn't yet (or vice versa), so this is not a cosmetic
|
|
209
|
+
* option; pass it only to match a call site that was genuinely UTC-explicit.
|
|
210
|
+
*/
|
|
211
|
+
const formatDateDDMMMYYYY = (value, options) => {
|
|
212
|
+
const d = toDate(value);
|
|
213
|
+
if (!d) {
|
|
214
|
+
return '';
|
|
215
|
+
}
|
|
216
|
+
if (options?.utc) {
|
|
217
|
+
return `${PAD(d.getUTCDate())} ${MONTH_SHORT[d.getUTCMonth()]}, ${d.getUTCFullYear()}`;
|
|
218
|
+
}
|
|
219
|
+
return `${PAD(d.getDate())} ${MONTH_SHORT[d.getMonth()]}, ${d.getFullYear()}`;
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
/** `YYYY-MM-DD`, in the device's local timezone. */
|
|
223
|
+
exports.formatDateDDMMMYYYY = formatDateDDMMMYYYY;
|
|
224
|
+
const formatDateISO = value => {
|
|
225
|
+
const d = toDate(value);
|
|
226
|
+
if (!d) {
|
|
227
|
+
return '';
|
|
228
|
+
}
|
|
229
|
+
return `${d.getFullYear()}-${PAD(d.getMonth() + 1)}-${PAD(d.getDate())}`;
|
|
230
|
+
};
|
|
231
|
+
exports.formatDateISO = formatDateISO;
|
|
232
|
+
const to12Hour = hours => {
|
|
233
|
+
const period = hours >= 12 ? 'PM' : 'AM';
|
|
234
|
+
const hour12 = hours % 12 || 12;
|
|
235
|
+
return {
|
|
236
|
+
hour12,
|
|
237
|
+
period
|
|
238
|
+
};
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* `hh:mm A` in the device's local timezone — zero-padded 12-hour clock,
|
|
243
|
+
* uppercase AM/PM (e.g. `09:30 PM`).
|
|
244
|
+
*/
|
|
245
|
+
const formatTime12h = value => {
|
|
246
|
+
const d = toDate(value);
|
|
247
|
+
if (!d) {
|
|
248
|
+
return '';
|
|
249
|
+
}
|
|
250
|
+
const {
|
|
251
|
+
hour12,
|
|
252
|
+
period
|
|
253
|
+
} = to12Hour(d.getHours());
|
|
254
|
+
return `${PAD(hour12)}:${PAD(d.getMinutes())} ${period}`;
|
|
255
|
+
};
|
|
256
|
+
exports.formatTime12h = formatTime12h;
|
|
257
|
+
const hasIntl = () => typeof Intl !== 'undefined' && typeof Intl.DateTimeFormat === 'function';
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* `hh:mm a` (zero-padded 12-hour, lowercase am/pm) of the given instant as
|
|
261
|
+
* seen in `ianaTimeZone` (e.g. `Asia/Kolkata`) — not the device's own
|
|
262
|
+
* timezone. Reads the hour/minute/period through `Intl.DateTimeFormat`'s
|
|
263
|
+
* `formatToParts` rather than its assembled string, because the assembled
|
|
264
|
+
* string's spacing before AM/PM varies by JS engine (some insert a narrow
|
|
265
|
+
* no-break space, U+202F, instead of a plain space) and isn't reliably
|
|
266
|
+
* zero-padded either. Throws if `ianaTimeZone` isn't a timezone Intl
|
|
267
|
+
* recognises — the same failure mode as handing dayjs.tz() a bad zone name.
|
|
268
|
+
*/
|
|
269
|
+
const formatTimeInZone = (value, ianaTimeZone) => {
|
|
270
|
+
const d = toDate(value);
|
|
271
|
+
if (!d) {
|
|
272
|
+
return '';
|
|
273
|
+
}
|
|
274
|
+
if (!hasIntl()) {
|
|
275
|
+
// No Intl.DateTimeFormat means no reliable IANA timezone database to
|
|
276
|
+
// convert against; the device-local fallback below is the least-wrong
|
|
277
|
+
// answer available, not a genuine timezone conversion.
|
|
278
|
+
return formatTime12h(d);
|
|
279
|
+
}
|
|
280
|
+
const parts = new Intl.DateTimeFormat('en-US', {
|
|
281
|
+
timeZone: ianaTimeZone,
|
|
282
|
+
hour: 'numeric',
|
|
283
|
+
minute: '2-digit',
|
|
284
|
+
hour12: true
|
|
285
|
+
}).formatToParts(d);
|
|
286
|
+
const get = type => parts.find(p => p.type === type)?.value ?? '';
|
|
287
|
+
const hour = Number.parseInt(get('hour'), 10);
|
|
288
|
+
const minute = get('minute');
|
|
289
|
+
const period = get('dayPeriod').toLowerCase();
|
|
290
|
+
return `${PAD(hour)}:${minute} ${period}`;
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Same as {@link formatTimeInZone}, but for a .NET-style Windows timezone ID
|
|
295
|
+
* (e.g. `"India Standard Time"`) rather than an IANA one. .NET's own
|
|
296
|
+
* `TimeZoneInfo` API only knows Windows IDs, so a backend built on it hands
|
|
297
|
+
* these to clients directly — `Intl`, by contrast, only recognises IANA
|
|
298
|
+
* names, so the ID has to be translated before it can be used here. Throws
|
|
299
|
+
* if `windowsTimeZoneId` has no known IANA mapping.
|
|
300
|
+
*/
|
|
301
|
+
exports.formatTimeInZone = formatTimeInZone;
|
|
302
|
+
const formatTimeInWindowsZone = (value, windowsTimeZoneId) => {
|
|
303
|
+
const ianaTimeZones = (0, _windowsIana.findIana)(windowsTimeZoneId);
|
|
304
|
+
if (!ianaTimeZones || ianaTimeZones.length === 0) {
|
|
305
|
+
throw new Error(`Mapping for Windows time zone '${windowsTimeZoneId}' not found.`);
|
|
306
|
+
}
|
|
307
|
+
return formatTimeInZone(value, ianaTimeZones[0]);
|
|
308
|
+
};
|
|
309
|
+
exports.formatTimeInWindowsZone = formatTimeInWindowsZone;
|
|
310
|
+
//# sourceMappingURL=dateMath.js.map
|
|
@@ -3,12 +3,24 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
+
Object.defineProperty(exports, "addDays", {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: function () {
|
|
9
|
+
return _dateMath.addDays;
|
|
10
|
+
}
|
|
11
|
+
});
|
|
6
12
|
Object.defineProperty(exports, "detectPhoneCountry", {
|
|
7
13
|
enumerable: true,
|
|
8
14
|
get: function () {
|
|
9
15
|
return _phone.detectPhoneCountry;
|
|
10
16
|
}
|
|
11
17
|
});
|
|
18
|
+
Object.defineProperty(exports, "diffMs", {
|
|
19
|
+
enumerable: true,
|
|
20
|
+
get: function () {
|
|
21
|
+
return _dateMath.diffMs;
|
|
22
|
+
}
|
|
23
|
+
});
|
|
12
24
|
Object.defineProperty(exports, "formatCompactNumber", {
|
|
13
25
|
enumerable: true,
|
|
14
26
|
get: function () {
|
|
@@ -27,6 +39,24 @@ Object.defineProperty(exports, "formatDate", {
|
|
|
27
39
|
return _date.formatDate;
|
|
28
40
|
}
|
|
29
41
|
});
|
|
42
|
+
Object.defineProperty(exports, "formatDateDDMMMYYYY", {
|
|
43
|
+
enumerable: true,
|
|
44
|
+
get: function () {
|
|
45
|
+
return _dateMath.formatDateDDMMMYYYY;
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
Object.defineProperty(exports, "formatDateISO", {
|
|
49
|
+
enumerable: true,
|
|
50
|
+
get: function () {
|
|
51
|
+
return _dateMath.formatDateISO;
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
Object.defineProperty(exports, "formatDatePattern", {
|
|
55
|
+
enumerable: true,
|
|
56
|
+
get: function () {
|
|
57
|
+
return _dateMath.formatDatePattern;
|
|
58
|
+
}
|
|
59
|
+
});
|
|
30
60
|
Object.defineProperty(exports, "formatDateTime", {
|
|
31
61
|
enumerable: true,
|
|
32
62
|
get: function () {
|
|
@@ -63,12 +93,48 @@ Object.defineProperty(exports, "formatTime", {
|
|
|
63
93
|
return _date.formatTime;
|
|
64
94
|
}
|
|
65
95
|
});
|
|
96
|
+
Object.defineProperty(exports, "formatTime12h", {
|
|
97
|
+
enumerable: true,
|
|
98
|
+
get: function () {
|
|
99
|
+
return _dateMath.formatTime12h;
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
Object.defineProperty(exports, "formatTimeInWindowsZone", {
|
|
103
|
+
enumerable: true,
|
|
104
|
+
get: function () {
|
|
105
|
+
return _dateMath.formatTimeInWindowsZone;
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
Object.defineProperty(exports, "formatTimeInZone", {
|
|
109
|
+
enumerable: true,
|
|
110
|
+
get: function () {
|
|
111
|
+
return _dateMath.formatTimeInZone;
|
|
112
|
+
}
|
|
113
|
+
});
|
|
66
114
|
Object.defineProperty(exports, "getInitials", {
|
|
67
115
|
enumerable: true,
|
|
68
116
|
get: function () {
|
|
69
117
|
return _initials.getInitials;
|
|
70
118
|
}
|
|
71
119
|
});
|
|
120
|
+
Object.defineProperty(exports, "isDateAfter", {
|
|
121
|
+
enumerable: true,
|
|
122
|
+
get: function () {
|
|
123
|
+
return _dateMath.isDateAfter;
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
Object.defineProperty(exports, "isDateBefore", {
|
|
127
|
+
enumerable: true,
|
|
128
|
+
get: function () {
|
|
129
|
+
return _dateMath.isDateBefore;
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
Object.defineProperty(exports, "isSameDay", {
|
|
133
|
+
enumerable: true,
|
|
134
|
+
get: function () {
|
|
135
|
+
return _dateMath.isSameDay;
|
|
136
|
+
}
|
|
137
|
+
});
|
|
72
138
|
Object.defineProperty(exports, "isValidPhoneNumber", {
|
|
73
139
|
enumerable: true,
|
|
74
140
|
get: function () {
|
|
@@ -93,8 +159,15 @@ Object.defineProperty(exports, "parsePhoneNumberFromString", {
|
|
|
93
159
|
return _phone.parsePhoneNumberFromString;
|
|
94
160
|
}
|
|
95
161
|
});
|
|
162
|
+
Object.defineProperty(exports, "startOfDay", {
|
|
163
|
+
enumerable: true,
|
|
164
|
+
get: function () {
|
|
165
|
+
return _dateMath.startOfDay;
|
|
166
|
+
}
|
|
167
|
+
});
|
|
96
168
|
var _currency = require("./currency.js");
|
|
97
169
|
var _date = require("./date.js");
|
|
170
|
+
var _dateMath = require("./dateMath.js");
|
|
98
171
|
var _initials = require("./initials.js");
|
|
99
172
|
var _number = require("./number.js");
|
|
100
173
|
var _phone = require("./phone.js");
|
package/lib/commonjs/index.js
CHANGED
|
@@ -51,6 +51,12 @@ Object.defineProperty(exports, "VersionCheck", {
|
|
|
51
51
|
return _index8.VersionCheck;
|
|
52
52
|
}
|
|
53
53
|
});
|
|
54
|
+
Object.defineProperty(exports, "addDays", {
|
|
55
|
+
enumerable: true,
|
|
56
|
+
get: function () {
|
|
57
|
+
return _index3.addDays;
|
|
58
|
+
}
|
|
59
|
+
});
|
|
54
60
|
Object.defineProperty(exports, "addNetworkStatusListener", {
|
|
55
61
|
enumerable: true,
|
|
56
62
|
get: function () {
|
|
@@ -87,6 +93,12 @@ Object.defineProperty(exports, "detectPhoneCountry", {
|
|
|
87
93
|
return _index3.detectPhoneCountry;
|
|
88
94
|
}
|
|
89
95
|
});
|
|
96
|
+
Object.defineProperty(exports, "diffMs", {
|
|
97
|
+
enumerable: true,
|
|
98
|
+
get: function () {
|
|
99
|
+
return _index3.diffMs;
|
|
100
|
+
}
|
|
101
|
+
});
|
|
90
102
|
Object.defineProperty(exports, "formatCompactNumber", {
|
|
91
103
|
enumerable: true,
|
|
92
104
|
get: function () {
|
|
@@ -105,6 +117,24 @@ Object.defineProperty(exports, "formatDate", {
|
|
|
105
117
|
return _index3.formatDate;
|
|
106
118
|
}
|
|
107
119
|
});
|
|
120
|
+
Object.defineProperty(exports, "formatDateDDMMMYYYY", {
|
|
121
|
+
enumerable: true,
|
|
122
|
+
get: function () {
|
|
123
|
+
return _index3.formatDateDDMMMYYYY;
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
Object.defineProperty(exports, "formatDateISO", {
|
|
127
|
+
enumerable: true,
|
|
128
|
+
get: function () {
|
|
129
|
+
return _index3.formatDateISO;
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
Object.defineProperty(exports, "formatDatePattern", {
|
|
133
|
+
enumerable: true,
|
|
134
|
+
get: function () {
|
|
135
|
+
return _index3.formatDatePattern;
|
|
136
|
+
}
|
|
137
|
+
});
|
|
108
138
|
Object.defineProperty(exports, "formatDateTime", {
|
|
109
139
|
enumerable: true,
|
|
110
140
|
get: function () {
|
|
@@ -141,6 +171,24 @@ Object.defineProperty(exports, "formatTime", {
|
|
|
141
171
|
return _index3.formatTime;
|
|
142
172
|
}
|
|
143
173
|
});
|
|
174
|
+
Object.defineProperty(exports, "formatTime12h", {
|
|
175
|
+
enumerable: true,
|
|
176
|
+
get: function () {
|
|
177
|
+
return _index3.formatTime12h;
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
Object.defineProperty(exports, "formatTimeInWindowsZone", {
|
|
181
|
+
enumerable: true,
|
|
182
|
+
get: function () {
|
|
183
|
+
return _index3.formatTimeInWindowsZone;
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
Object.defineProperty(exports, "formatTimeInZone", {
|
|
187
|
+
enumerable: true,
|
|
188
|
+
get: function () {
|
|
189
|
+
return _index3.formatTimeInZone;
|
|
190
|
+
}
|
|
191
|
+
});
|
|
144
192
|
Object.defineProperty(exports, "getConfig", {
|
|
145
193
|
enumerable: true,
|
|
146
194
|
get: function () {
|
|
@@ -225,6 +273,18 @@ Object.defineProperty(exports, "isBetween", {
|
|
|
225
273
|
return _index7.isBetween;
|
|
226
274
|
}
|
|
227
275
|
});
|
|
276
|
+
Object.defineProperty(exports, "isDateAfter", {
|
|
277
|
+
enumerable: true,
|
|
278
|
+
get: function () {
|
|
279
|
+
return _index3.isDateAfter;
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
Object.defineProperty(exports, "isDateBefore", {
|
|
283
|
+
enumerable: true,
|
|
284
|
+
get: function () {
|
|
285
|
+
return _index3.isDateBefore;
|
|
286
|
+
}
|
|
287
|
+
});
|
|
228
288
|
Object.defineProperty(exports, "isEmail", {
|
|
229
289
|
enumerable: true,
|
|
230
290
|
get: function () {
|
|
@@ -303,6 +363,12 @@ Object.defineProperty(exports, "isRetryableStatus", {
|
|
|
303
363
|
return _retry.isRetryableStatus;
|
|
304
364
|
}
|
|
305
365
|
});
|
|
366
|
+
Object.defineProperty(exports, "isSameDay", {
|
|
367
|
+
enumerable: true,
|
|
368
|
+
get: function () {
|
|
369
|
+
return _index3.isSameDay;
|
|
370
|
+
}
|
|
371
|
+
});
|
|
306
372
|
Object.defineProperty(exports, "isStorageAvailable", {
|
|
307
373
|
enumerable: true,
|
|
308
374
|
get: function () {
|
|
@@ -435,6 +501,12 @@ Object.defineProperty(exports, "setStorageImplementation", {
|
|
|
435
501
|
return _index6.setStorageImplementation;
|
|
436
502
|
}
|
|
437
503
|
});
|
|
504
|
+
Object.defineProperty(exports, "startOfDay", {
|
|
505
|
+
enumerable: true,
|
|
506
|
+
get: function () {
|
|
507
|
+
return _index3.startOfDay;
|
|
508
|
+
}
|
|
509
|
+
});
|
|
438
510
|
Object.defineProperty(exports, "storeToken", {
|
|
439
511
|
enumerable: true,
|
|
440
512
|
get: function () {
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { findIana } from 'windows-iana';
|
|
4
|
+
const toDate = value => {
|
|
5
|
+
if (value instanceof Date) {
|
|
6
|
+
return Number.isNaN(value.getTime()) ? null : value;
|
|
7
|
+
}
|
|
8
|
+
const d = new Date(value);
|
|
9
|
+
return Number.isNaN(d.getTime()) ? null : d;
|
|
10
|
+
};
|
|
11
|
+
const PAD = n => n < 10 ? `0${n}` : `${n}`;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Whether two values fall on the same calendar day in the device's local
|
|
15
|
+
* timezone. Invalid input on either side returns false rather than throwing.
|
|
16
|
+
*/
|
|
17
|
+
export const isSameDay = (a, b) => {
|
|
18
|
+
const da = toDate(a);
|
|
19
|
+
const db = toDate(b);
|
|
20
|
+
if (!da || !db) {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
return da.getFullYear() === db.getFullYear() && da.getMonth() === db.getMonth() && da.getDate() === db.getDate();
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/** `a` is strictly before `b`. Invalid input on either side returns false. */
|
|
27
|
+
export const isDateBefore = (a, b) => {
|
|
28
|
+
const da = toDate(a);
|
|
29
|
+
const db = toDate(b);
|
|
30
|
+
return da !== null && db !== null && da.getTime() < db.getTime();
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/** `a` is strictly after `b`. Invalid input on either side returns false. */
|
|
34
|
+
export const isDateAfter = (a, b) => {
|
|
35
|
+
const da = toDate(a);
|
|
36
|
+
const db = toDate(b);
|
|
37
|
+
return da !== null && db !== null && da.getTime() > db.getTime();
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* `a - b` in milliseconds, matching dayjs's `a.diff(b)` sign convention
|
|
42
|
+
* (positive when `a` is later than `b`). Returns `NaN` if either side fails
|
|
43
|
+
* to parse, the same way subtracting two invalid dayjs objects would.
|
|
44
|
+
*/
|
|
45
|
+
export const diffMs = (a, b) => {
|
|
46
|
+
const da = toDate(a);
|
|
47
|
+
const db = toDate(b);
|
|
48
|
+
if (!da || !db) {
|
|
49
|
+
return Number.NaN;
|
|
50
|
+
}
|
|
51
|
+
return da.getTime() - db.getTime();
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Midnight of the given date, in the device's local timezone. Returns null
|
|
56
|
+
* for unparseable input.
|
|
57
|
+
*/
|
|
58
|
+
export const startOfDay = value => {
|
|
59
|
+
const d = toDate(value);
|
|
60
|
+
if (!d) {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
const start = new Date(d);
|
|
64
|
+
start.setHours(0, 0, 0, 0);
|
|
65
|
+
return start;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Adds (or, with a negative count, subtracts) whole calendar days in the
|
|
70
|
+
* device's local timezone. Returns null for unparseable input.
|
|
71
|
+
*/
|
|
72
|
+
export const addDays = (value, count) => {
|
|
73
|
+
const d = toDate(value);
|
|
74
|
+
if (!d) {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
const next = new Date(d);
|
|
78
|
+
next.setDate(next.getDate() + count);
|
|
79
|
+
return next;
|
|
80
|
+
};
|
|
81
|
+
const WEEKDAY_SHORT = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
|
|
82
|
+
const WEEKDAY_LONG = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
|
|
83
|
+
const MONTH_LONG = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
|
|
84
|
+
|
|
85
|
+
// Longest-first so 'YYYY' is tried before 'YY', 'DD' before 'D', etc. — a
|
|
86
|
+
// greedy single pass over the pattern, not a regex, so a literal character
|
|
87
|
+
// (a comma, a colon, a digit) can never accidentally match a token.
|
|
88
|
+
const TOKENS = ['YYYY', 'YY', 'MMMM', 'MMM', 'MM', 'M', 'DD', 'D', 'dddd', 'ddd', 'HH', 'H', 'hh', 'h', 'mm', 'm', 'ss', 's', 'A', 'a'];
|
|
89
|
+
const tokenizePattern = pattern => {
|
|
90
|
+
const result = [];
|
|
91
|
+
let i = 0;
|
|
92
|
+
outer: while (i < pattern.length) {
|
|
93
|
+
for (const token of TOKENS) {
|
|
94
|
+
if (pattern.startsWith(token, i)) {
|
|
95
|
+
result.push(token);
|
|
96
|
+
i += token.length;
|
|
97
|
+
continue outer;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
result.push(pattern[i]);
|
|
101
|
+
i += 1;
|
|
102
|
+
}
|
|
103
|
+
return result;
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Small dayjs/moment-style token formatter — YYYY/YY, MMMM/MMM/MM/M,
|
|
108
|
+
* DD/D, dddd/ddd, HH/H (24h), hh/h (12h), mm/m, ss/s, A/a (upper/lower AM/PM).
|
|
109
|
+
* Everything else in the pattern (spaces, commas, colons) passes through
|
|
110
|
+
* literally. Hand-rolled rather than a dependency because this fleet's date
|
|
111
|
+
* formatting needs are a small, closed token set, not general i18n — for
|
|
112
|
+
* genuinely locale-aware output, `formatDate`/`formatTime` (Intl-backed, in
|
|
113
|
+
* `./date`) are the ones to reach for; this is for matching an exact
|
|
114
|
+
* existing pattern (a legacy display string, an API's expected shape).
|
|
115
|
+
*
|
|
116
|
+
* `utc: true` reads every field from the UTC calendar/clock instead of the
|
|
117
|
+
* device's local one — see `formatDateDDMMMYYYY`'s note on why this isn't
|
|
118
|
+
* cosmetic.
|
|
119
|
+
*/
|
|
120
|
+
export const formatDatePattern = (value, pattern, options) => {
|
|
121
|
+
const d = toDate(value);
|
|
122
|
+
if (!d) {
|
|
123
|
+
return '';
|
|
124
|
+
}
|
|
125
|
+
const utc = options?.utc ?? false;
|
|
126
|
+
const year = utc ? d.getUTCFullYear() : d.getFullYear();
|
|
127
|
+
const month = utc ? d.getUTCMonth() : d.getMonth();
|
|
128
|
+
const day = utc ? d.getUTCDate() : d.getDate();
|
|
129
|
+
const weekday = utc ? d.getUTCDay() : d.getDay();
|
|
130
|
+
const hours24 = utc ? d.getUTCHours() : d.getHours();
|
|
131
|
+
const minutes = utc ? d.getUTCMinutes() : d.getMinutes();
|
|
132
|
+
const seconds = utc ? d.getUTCSeconds() : d.getSeconds();
|
|
133
|
+
const {
|
|
134
|
+
hour12,
|
|
135
|
+
period
|
|
136
|
+
} = to12Hour(hours24);
|
|
137
|
+
return tokenizePattern(pattern).map(t => {
|
|
138
|
+
switch (t) {
|
|
139
|
+
case 'YYYY':
|
|
140
|
+
return String(year);
|
|
141
|
+
case 'YY':
|
|
142
|
+
return String(year).slice(-2);
|
|
143
|
+
case 'MMMM':
|
|
144
|
+
return MONTH_LONG[month];
|
|
145
|
+
case 'MMM':
|
|
146
|
+
return MONTH_SHORT[month];
|
|
147
|
+
case 'MM':
|
|
148
|
+
return PAD(month + 1);
|
|
149
|
+
case 'M':
|
|
150
|
+
return String(month + 1);
|
|
151
|
+
case 'DD':
|
|
152
|
+
return PAD(day);
|
|
153
|
+
case 'D':
|
|
154
|
+
return String(day);
|
|
155
|
+
case 'dddd':
|
|
156
|
+
return WEEKDAY_LONG[weekday];
|
|
157
|
+
case 'ddd':
|
|
158
|
+
return WEEKDAY_SHORT[weekday];
|
|
159
|
+
case 'HH':
|
|
160
|
+
return PAD(hours24);
|
|
161
|
+
case 'H':
|
|
162
|
+
return String(hours24);
|
|
163
|
+
case 'hh':
|
|
164
|
+
return PAD(hour12);
|
|
165
|
+
case 'h':
|
|
166
|
+
return String(hour12);
|
|
167
|
+
case 'mm':
|
|
168
|
+
return PAD(minutes);
|
|
169
|
+
case 'm':
|
|
170
|
+
return String(minutes);
|
|
171
|
+
case 'ss':
|
|
172
|
+
return PAD(seconds);
|
|
173
|
+
case 's':
|
|
174
|
+
return String(seconds);
|
|
175
|
+
case 'A':
|
|
176
|
+
return period;
|
|
177
|
+
case 'a':
|
|
178
|
+
return period.toLowerCase();
|
|
179
|
+
default:
|
|
180
|
+
return t;
|
|
181
|
+
}
|
|
182
|
+
}).join('');
|
|
183
|
+
};
|
|
184
|
+
const MONTH_SHORT = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* `DD MMM, YYYY` — zero-padded day, short month, comma, year (e.g.
|
|
188
|
+
* `05 Sep, 2025`). A specific legacy pattern some apps already display,
|
|
189
|
+
* not the fleet's own product convention: `formatDate` (the Intl `style`-based
|
|
190
|
+
* formatter in `./date`) is the one to reach for in new code. This exists so
|
|
191
|
+
* an app already showing this exact pattern can move off a date library
|
|
192
|
+
* without a visible change.
|
|
193
|
+
*
|
|
194
|
+
* `utc: true` reads the calendar day from the UTC fields instead of the
|
|
195
|
+
* device's local ones — matching `dayjs.utc(x).format(...)`, not
|
|
196
|
+
* `dayjs(x).format(...)`. The two disagree whenever local time has crossed a
|
|
197
|
+
* day boundary UTC hasn't yet (or vice versa), so this is not a cosmetic
|
|
198
|
+
* option; pass it only to match a call site that was genuinely UTC-explicit.
|
|
199
|
+
*/
|
|
200
|
+
export const formatDateDDMMMYYYY = (value, options) => {
|
|
201
|
+
const d = toDate(value);
|
|
202
|
+
if (!d) {
|
|
203
|
+
return '';
|
|
204
|
+
}
|
|
205
|
+
if (options?.utc) {
|
|
206
|
+
return `${PAD(d.getUTCDate())} ${MONTH_SHORT[d.getUTCMonth()]}, ${d.getUTCFullYear()}`;
|
|
207
|
+
}
|
|
208
|
+
return `${PAD(d.getDate())} ${MONTH_SHORT[d.getMonth()]}, ${d.getFullYear()}`;
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
/** `YYYY-MM-DD`, in the device's local timezone. */
|
|
212
|
+
export const formatDateISO = value => {
|
|
213
|
+
const d = toDate(value);
|
|
214
|
+
if (!d) {
|
|
215
|
+
return '';
|
|
216
|
+
}
|
|
217
|
+
return `${d.getFullYear()}-${PAD(d.getMonth() + 1)}-${PAD(d.getDate())}`;
|
|
218
|
+
};
|
|
219
|
+
const to12Hour = hours => {
|
|
220
|
+
const period = hours >= 12 ? 'PM' : 'AM';
|
|
221
|
+
const hour12 = hours % 12 || 12;
|
|
222
|
+
return {
|
|
223
|
+
hour12,
|
|
224
|
+
period
|
|
225
|
+
};
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* `hh:mm A` in the device's local timezone — zero-padded 12-hour clock,
|
|
230
|
+
* uppercase AM/PM (e.g. `09:30 PM`).
|
|
231
|
+
*/
|
|
232
|
+
export const formatTime12h = value => {
|
|
233
|
+
const d = toDate(value);
|
|
234
|
+
if (!d) {
|
|
235
|
+
return '';
|
|
236
|
+
}
|
|
237
|
+
const {
|
|
238
|
+
hour12,
|
|
239
|
+
period
|
|
240
|
+
} = to12Hour(d.getHours());
|
|
241
|
+
return `${PAD(hour12)}:${PAD(d.getMinutes())} ${period}`;
|
|
242
|
+
};
|
|
243
|
+
const hasIntl = () => typeof Intl !== 'undefined' && typeof Intl.DateTimeFormat === 'function';
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* `hh:mm a` (zero-padded 12-hour, lowercase am/pm) of the given instant as
|
|
247
|
+
* seen in `ianaTimeZone` (e.g. `Asia/Kolkata`) — not the device's own
|
|
248
|
+
* timezone. Reads the hour/minute/period through `Intl.DateTimeFormat`'s
|
|
249
|
+
* `formatToParts` rather than its assembled string, because the assembled
|
|
250
|
+
* string's spacing before AM/PM varies by JS engine (some insert a narrow
|
|
251
|
+
* no-break space, U+202F, instead of a plain space) and isn't reliably
|
|
252
|
+
* zero-padded either. Throws if `ianaTimeZone` isn't a timezone Intl
|
|
253
|
+
* recognises — the same failure mode as handing dayjs.tz() a bad zone name.
|
|
254
|
+
*/
|
|
255
|
+
export const formatTimeInZone = (value, ianaTimeZone) => {
|
|
256
|
+
const d = toDate(value);
|
|
257
|
+
if (!d) {
|
|
258
|
+
return '';
|
|
259
|
+
}
|
|
260
|
+
if (!hasIntl()) {
|
|
261
|
+
// No Intl.DateTimeFormat means no reliable IANA timezone database to
|
|
262
|
+
// convert against; the device-local fallback below is the least-wrong
|
|
263
|
+
// answer available, not a genuine timezone conversion.
|
|
264
|
+
return formatTime12h(d);
|
|
265
|
+
}
|
|
266
|
+
const parts = new Intl.DateTimeFormat('en-US', {
|
|
267
|
+
timeZone: ianaTimeZone,
|
|
268
|
+
hour: 'numeric',
|
|
269
|
+
minute: '2-digit',
|
|
270
|
+
hour12: true
|
|
271
|
+
}).formatToParts(d);
|
|
272
|
+
const get = type => parts.find(p => p.type === type)?.value ?? '';
|
|
273
|
+
const hour = Number.parseInt(get('hour'), 10);
|
|
274
|
+
const minute = get('minute');
|
|
275
|
+
const period = get('dayPeriod').toLowerCase();
|
|
276
|
+
return `${PAD(hour)}:${minute} ${period}`;
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Same as {@link formatTimeInZone}, but for a .NET-style Windows timezone ID
|
|
281
|
+
* (e.g. `"India Standard Time"`) rather than an IANA one. .NET's own
|
|
282
|
+
* `TimeZoneInfo` API only knows Windows IDs, so a backend built on it hands
|
|
283
|
+
* these to clients directly — `Intl`, by contrast, only recognises IANA
|
|
284
|
+
* names, so the ID has to be translated before it can be used here. Throws
|
|
285
|
+
* if `windowsTimeZoneId` has no known IANA mapping.
|
|
286
|
+
*/
|
|
287
|
+
export const formatTimeInWindowsZone = (value, windowsTimeZoneId) => {
|
|
288
|
+
const ianaTimeZones = findIana(windowsTimeZoneId);
|
|
289
|
+
if (!ianaTimeZones || ianaTimeZones.length === 0) {
|
|
290
|
+
throw new Error(`Mapping for Windows time zone '${windowsTimeZoneId}' not found.`);
|
|
291
|
+
}
|
|
292
|
+
return formatTimeInZone(value, ianaTimeZones[0]);
|
|
293
|
+
};
|
|
294
|
+
//# sourceMappingURL=dateMath.js.map
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
export { formatCurrency } from "./currency.js";
|
|
4
4
|
export { formatDate, formatDateTime, formatRelativeTime, formatTime } from "./date.js";
|
|
5
|
+
export { addDays, diffMs, formatDateDDMMMYYYY, formatDateISO, formatDatePattern, formatTime12h, formatTimeInWindowsZone, formatTimeInZone, isDateAfter, isDateBefore, isSameDay, startOfDay } from "./dateMath.js";
|
|
5
6
|
export { getInitials } from "./initials.js";
|
|
6
7
|
export { formatCompactNumber, formatNumber, formatPercent } from "./number.js";
|
|
7
8
|
export { detectPhoneCountry, formatPhone, isValidPhoneNumber, normalizePhone, parsePhoneNumber, parsePhoneNumberFromString } from "./phone.js";
|
package/lib/module/index.js
CHANGED
|
@@ -29,7 +29,7 @@ export { getConfig, getConfigValue, resetConfig, setConfig } from "./config/inde
|
|
|
29
29
|
// Deep links
|
|
30
30
|
export { DeepLink, parseDeepLink, useDeepLink } from "./deepLink/index.js";
|
|
31
31
|
// Formatters
|
|
32
|
-
export { detectPhoneCountry, formatCompactNumber, formatCurrency, formatDate, formatDateTime, formatNumber, formatPercent, formatPhone, formatRelativeTime, formatTime, getInitials, isValidPhoneNumber, normalizePhone, parsePhoneNumber, parsePhoneNumberFromString } from "./formatters/index.js";
|
|
32
|
+
export { addDays, detectPhoneCountry, diffMs, formatCompactNumber, formatCurrency, formatDate, formatDateDDMMMYYYY, formatDateISO, formatDatePattern, formatDateTime, formatNumber, formatPercent, formatPhone, formatRelativeTime, formatTime, formatTime12h, formatTimeInWindowsZone, formatTimeInZone, getInitials, isDateAfter, isDateBefore, isSameDay, isValidPhoneNumber, normalizePhone, parsePhoneNumber, parsePhoneNumberFromString, startOfDay } from "./formatters/index.js";
|
|
33
33
|
// Initialization
|
|
34
34
|
export { initWebority } from "./initSDK.js";
|
|
35
35
|
export { initUserAuth } from "./initUserAuth.js";
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type { DateInput } from './date';
|
|
2
|
+
/**
|
|
3
|
+
* Whether two values fall on the same calendar day in the device's local
|
|
4
|
+
* timezone. Invalid input on either side returns false rather than throwing.
|
|
5
|
+
*/
|
|
6
|
+
export declare const isSameDay: (a: DateInput, b: DateInput) => boolean;
|
|
7
|
+
/** `a` is strictly before `b`. Invalid input on either side returns false. */
|
|
8
|
+
export declare const isDateBefore: (a: DateInput, b: DateInput) => boolean;
|
|
9
|
+
/** `a` is strictly after `b`. Invalid input on either side returns false. */
|
|
10
|
+
export declare const isDateAfter: (a: DateInput, b: DateInput) => boolean;
|
|
11
|
+
/**
|
|
12
|
+
* `a - b` in milliseconds, matching dayjs's `a.diff(b)` sign convention
|
|
13
|
+
* (positive when `a` is later than `b`). Returns `NaN` if either side fails
|
|
14
|
+
* to parse, the same way subtracting two invalid dayjs objects would.
|
|
15
|
+
*/
|
|
16
|
+
export declare const diffMs: (a: DateInput, b: DateInput) => number;
|
|
17
|
+
/**
|
|
18
|
+
* Midnight of the given date, in the device's local timezone. Returns null
|
|
19
|
+
* for unparseable input.
|
|
20
|
+
*/
|
|
21
|
+
export declare const startOfDay: (value: DateInput) => Date | null;
|
|
22
|
+
/**
|
|
23
|
+
* Adds (or, with a negative count, subtracts) whole calendar days in the
|
|
24
|
+
* device's local timezone. Returns null for unparseable input.
|
|
25
|
+
*/
|
|
26
|
+
export declare const addDays: (value: DateInput, count: number) => Date | null;
|
|
27
|
+
/**
|
|
28
|
+
* Small dayjs/moment-style token formatter — YYYY/YY, MMMM/MMM/MM/M,
|
|
29
|
+
* DD/D, dddd/ddd, HH/H (24h), hh/h (12h), mm/m, ss/s, A/a (upper/lower AM/PM).
|
|
30
|
+
* Everything else in the pattern (spaces, commas, colons) passes through
|
|
31
|
+
* literally. Hand-rolled rather than a dependency because this fleet's date
|
|
32
|
+
* formatting needs are a small, closed token set, not general i18n — for
|
|
33
|
+
* genuinely locale-aware output, `formatDate`/`formatTime` (Intl-backed, in
|
|
34
|
+
* `./date`) are the ones to reach for; this is for matching an exact
|
|
35
|
+
* existing pattern (a legacy display string, an API's expected shape).
|
|
36
|
+
*
|
|
37
|
+
* `utc: true` reads every field from the UTC calendar/clock instead of the
|
|
38
|
+
* device's local one — see `formatDateDDMMMYYYY`'s note on why this isn't
|
|
39
|
+
* cosmetic.
|
|
40
|
+
*/
|
|
41
|
+
export declare const formatDatePattern: (value: DateInput, pattern: string, options?: {
|
|
42
|
+
utc?: boolean;
|
|
43
|
+
}) => string;
|
|
44
|
+
/**
|
|
45
|
+
* `DD MMM, YYYY` — zero-padded day, short month, comma, year (e.g.
|
|
46
|
+
* `05 Sep, 2025`). A specific legacy pattern some apps already display,
|
|
47
|
+
* not the fleet's own product convention: `formatDate` (the Intl `style`-based
|
|
48
|
+
* formatter in `./date`) is the one to reach for in new code. This exists so
|
|
49
|
+
* an app already showing this exact pattern can move off a date library
|
|
50
|
+
* without a visible change.
|
|
51
|
+
*
|
|
52
|
+
* `utc: true` reads the calendar day from the UTC fields instead of the
|
|
53
|
+
* device's local ones — matching `dayjs.utc(x).format(...)`, not
|
|
54
|
+
* `dayjs(x).format(...)`. The two disagree whenever local time has crossed a
|
|
55
|
+
* day boundary UTC hasn't yet (or vice versa), so this is not a cosmetic
|
|
56
|
+
* option; pass it only to match a call site that was genuinely UTC-explicit.
|
|
57
|
+
*/
|
|
58
|
+
export declare const formatDateDDMMMYYYY: (value: DateInput, options?: {
|
|
59
|
+
utc?: boolean;
|
|
60
|
+
}) => string;
|
|
61
|
+
/** `YYYY-MM-DD`, in the device's local timezone. */
|
|
62
|
+
export declare const formatDateISO: (value: DateInput) => string;
|
|
63
|
+
/**
|
|
64
|
+
* `hh:mm A` in the device's local timezone — zero-padded 12-hour clock,
|
|
65
|
+
* uppercase AM/PM (e.g. `09:30 PM`).
|
|
66
|
+
*/
|
|
67
|
+
export declare const formatTime12h: (value: DateInput) => string;
|
|
68
|
+
/**
|
|
69
|
+
* `hh:mm a` (zero-padded 12-hour, lowercase am/pm) of the given instant as
|
|
70
|
+
* seen in `ianaTimeZone` (e.g. `Asia/Kolkata`) — not the device's own
|
|
71
|
+
* timezone. Reads the hour/minute/period through `Intl.DateTimeFormat`'s
|
|
72
|
+
* `formatToParts` rather than its assembled string, because the assembled
|
|
73
|
+
* string's spacing before AM/PM varies by JS engine (some insert a narrow
|
|
74
|
+
* no-break space, U+202F, instead of a plain space) and isn't reliably
|
|
75
|
+
* zero-padded either. Throws if `ianaTimeZone` isn't a timezone Intl
|
|
76
|
+
* recognises — the same failure mode as handing dayjs.tz() a bad zone name.
|
|
77
|
+
*/
|
|
78
|
+
export declare const formatTimeInZone: (value: DateInput, ianaTimeZone: string) => string;
|
|
79
|
+
/**
|
|
80
|
+
* Same as {@link formatTimeInZone}, but for a .NET-style Windows timezone ID
|
|
81
|
+
* (e.g. `"India Standard Time"`) rather than an IANA one. .NET's own
|
|
82
|
+
* `TimeZoneInfo` API only knows Windows IDs, so a backend built on it hands
|
|
83
|
+
* these to clients directly — `Intl`, by contrast, only recognises IANA
|
|
84
|
+
* names, so the ID has to be translated before it can be used here. Throws
|
|
85
|
+
* if `windowsTimeZoneId` has no known IANA mapping.
|
|
86
|
+
*/
|
|
87
|
+
export declare const formatTimeInWindowsZone: (value: DateInput, windowsTimeZoneId: string) => string;
|
|
88
|
+
//# sourceMappingURL=dateMath.d.ts.map
|
|
@@ -2,6 +2,7 @@ export type { FormatCurrencyOptions } from './currency';
|
|
|
2
2
|
export { formatCurrency } from './currency';
|
|
3
3
|
export type { DateInput, DateStyle, TimeStyle } from './date';
|
|
4
4
|
export { formatDate, formatDateTime, formatRelativeTime, formatTime } from './date';
|
|
5
|
+
export { addDays, diffMs, formatDateDDMMMYYYY, formatDateISO, formatDatePattern, formatTime12h, formatTimeInWindowsZone, formatTimeInZone, isDateAfter, isDateBefore, isSameDay, startOfDay } from './dateMath';
|
|
5
6
|
export { getInitials } from './initials';
|
|
6
7
|
export { formatCompactNumber, formatNumber, formatPercent } from './number';
|
|
7
8
|
export type { FormatPhoneOptions, PhoneCountry, PhoneNumber } from './phone';
|
|
@@ -29,7 +29,7 @@ export { getConfig, getConfigValue, resetConfig, setConfig } from './config';
|
|
|
29
29
|
export type { DeepLinkConfig, DeepLinkRoute, ParsedLink } from './deepLink';
|
|
30
30
|
export { DeepLink, parseDeepLink, useDeepLink } from './deepLink';
|
|
31
31
|
export type { DateInput, DateStyle, FormatCurrencyOptions, FormatPhoneOptions, PhoneCountry, PhoneNumber, TimeStyle } from './formatters';
|
|
32
|
-
export { detectPhoneCountry, formatCompactNumber, formatCurrency, formatDate, formatDateTime, formatNumber, formatPercent, formatPhone, formatRelativeTime, formatTime, getInitials, isValidPhoneNumber, normalizePhone, parsePhoneNumber, parsePhoneNumberFromString } from './formatters';
|
|
32
|
+
export { addDays, detectPhoneCountry, diffMs, formatCompactNumber, formatCurrency, formatDate, formatDateDDMMMYYYY, formatDateISO, formatDatePattern, formatDateTime, formatNumber, formatPercent, formatPhone, formatRelativeTime, formatTime, formatTime12h, formatTimeInWindowsZone, formatTimeInZone, getInitials, isDateAfter, isDateBefore, isSameDay, isValidPhoneNumber, normalizePhone, parsePhoneNumber, parsePhoneNumberFromString, startOfDay } from './formatters';
|
|
33
33
|
export type { InitConfig } from './initSDK';
|
|
34
34
|
export { initWebority } from './initSDK';
|
|
35
35
|
export type { AuthActions } from './initUserAuth';
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type { DateInput } from './date.js';
|
|
2
|
+
/**
|
|
3
|
+
* Whether two values fall on the same calendar day in the device's local
|
|
4
|
+
* timezone. Invalid input on either side returns false rather than throwing.
|
|
5
|
+
*/
|
|
6
|
+
export declare const isSameDay: (a: DateInput, b: DateInput) => boolean;
|
|
7
|
+
/** `a` is strictly before `b`. Invalid input on either side returns false. */
|
|
8
|
+
export declare const isDateBefore: (a: DateInput, b: DateInput) => boolean;
|
|
9
|
+
/** `a` is strictly after `b`. Invalid input on either side returns false. */
|
|
10
|
+
export declare const isDateAfter: (a: DateInput, b: DateInput) => boolean;
|
|
11
|
+
/**
|
|
12
|
+
* `a - b` in milliseconds, matching dayjs's `a.diff(b)` sign convention
|
|
13
|
+
* (positive when `a` is later than `b`). Returns `NaN` if either side fails
|
|
14
|
+
* to parse, the same way subtracting two invalid dayjs objects would.
|
|
15
|
+
*/
|
|
16
|
+
export declare const diffMs: (a: DateInput, b: DateInput) => number;
|
|
17
|
+
/**
|
|
18
|
+
* Midnight of the given date, in the device's local timezone. Returns null
|
|
19
|
+
* for unparseable input.
|
|
20
|
+
*/
|
|
21
|
+
export declare const startOfDay: (value: DateInput) => Date | null;
|
|
22
|
+
/**
|
|
23
|
+
* Adds (or, with a negative count, subtracts) whole calendar days in the
|
|
24
|
+
* device's local timezone. Returns null for unparseable input.
|
|
25
|
+
*/
|
|
26
|
+
export declare const addDays: (value: DateInput, count: number) => Date | null;
|
|
27
|
+
/**
|
|
28
|
+
* Small dayjs/moment-style token formatter — YYYY/YY, MMMM/MMM/MM/M,
|
|
29
|
+
* DD/D, dddd/ddd, HH/H (24h), hh/h (12h), mm/m, ss/s, A/a (upper/lower AM/PM).
|
|
30
|
+
* Everything else in the pattern (spaces, commas, colons) passes through
|
|
31
|
+
* literally. Hand-rolled rather than a dependency because this fleet's date
|
|
32
|
+
* formatting needs are a small, closed token set, not general i18n — for
|
|
33
|
+
* genuinely locale-aware output, `formatDate`/`formatTime` (Intl-backed, in
|
|
34
|
+
* `./date`) are the ones to reach for; this is for matching an exact
|
|
35
|
+
* existing pattern (a legacy display string, an API's expected shape).
|
|
36
|
+
*
|
|
37
|
+
* `utc: true` reads every field from the UTC calendar/clock instead of the
|
|
38
|
+
* device's local one — see `formatDateDDMMMYYYY`'s note on why this isn't
|
|
39
|
+
* cosmetic.
|
|
40
|
+
*/
|
|
41
|
+
export declare const formatDatePattern: (value: DateInput, pattern: string, options?: {
|
|
42
|
+
utc?: boolean;
|
|
43
|
+
}) => string;
|
|
44
|
+
/**
|
|
45
|
+
* `DD MMM, YYYY` — zero-padded day, short month, comma, year (e.g.
|
|
46
|
+
* `05 Sep, 2025`). A specific legacy pattern some apps already display,
|
|
47
|
+
* not the fleet's own product convention: `formatDate` (the Intl `style`-based
|
|
48
|
+
* formatter in `./date`) is the one to reach for in new code. This exists so
|
|
49
|
+
* an app already showing this exact pattern can move off a date library
|
|
50
|
+
* without a visible change.
|
|
51
|
+
*
|
|
52
|
+
* `utc: true` reads the calendar day from the UTC fields instead of the
|
|
53
|
+
* device's local ones — matching `dayjs.utc(x).format(...)`, not
|
|
54
|
+
* `dayjs(x).format(...)`. The two disagree whenever local time has crossed a
|
|
55
|
+
* day boundary UTC hasn't yet (or vice versa), so this is not a cosmetic
|
|
56
|
+
* option; pass it only to match a call site that was genuinely UTC-explicit.
|
|
57
|
+
*/
|
|
58
|
+
export declare const formatDateDDMMMYYYY: (value: DateInput, options?: {
|
|
59
|
+
utc?: boolean;
|
|
60
|
+
}) => string;
|
|
61
|
+
/** `YYYY-MM-DD`, in the device's local timezone. */
|
|
62
|
+
export declare const formatDateISO: (value: DateInput) => string;
|
|
63
|
+
/**
|
|
64
|
+
* `hh:mm A` in the device's local timezone — zero-padded 12-hour clock,
|
|
65
|
+
* uppercase AM/PM (e.g. `09:30 PM`).
|
|
66
|
+
*/
|
|
67
|
+
export declare const formatTime12h: (value: DateInput) => string;
|
|
68
|
+
/**
|
|
69
|
+
* `hh:mm a` (zero-padded 12-hour, lowercase am/pm) of the given instant as
|
|
70
|
+
* seen in `ianaTimeZone` (e.g. `Asia/Kolkata`) — not the device's own
|
|
71
|
+
* timezone. Reads the hour/minute/period through `Intl.DateTimeFormat`'s
|
|
72
|
+
* `formatToParts` rather than its assembled string, because the assembled
|
|
73
|
+
* string's spacing before AM/PM varies by JS engine (some insert a narrow
|
|
74
|
+
* no-break space, U+202F, instead of a plain space) and isn't reliably
|
|
75
|
+
* zero-padded either. Throws if `ianaTimeZone` isn't a timezone Intl
|
|
76
|
+
* recognises — the same failure mode as handing dayjs.tz() a bad zone name.
|
|
77
|
+
*/
|
|
78
|
+
export declare const formatTimeInZone: (value: DateInput, ianaTimeZone: string) => string;
|
|
79
|
+
/**
|
|
80
|
+
* Same as {@link formatTimeInZone}, but for a .NET-style Windows timezone ID
|
|
81
|
+
* (e.g. `"India Standard Time"`) rather than an IANA one. .NET's own
|
|
82
|
+
* `TimeZoneInfo` API only knows Windows IDs, so a backend built on it hands
|
|
83
|
+
* these to clients directly — `Intl`, by contrast, only recognises IANA
|
|
84
|
+
* names, so the ID has to be translated before it can be used here. Throws
|
|
85
|
+
* if `windowsTimeZoneId` has no known IANA mapping.
|
|
86
|
+
*/
|
|
87
|
+
export declare const formatTimeInWindowsZone: (value: DateInput, windowsTimeZoneId: string) => string;
|
|
88
|
+
//# sourceMappingURL=dateMath.d.ts.map
|
|
@@ -2,6 +2,7 @@ export type { FormatCurrencyOptions } from './currency.js';
|
|
|
2
2
|
export { formatCurrency } from './currency.js';
|
|
3
3
|
export type { DateInput, DateStyle, TimeStyle } from './date.js';
|
|
4
4
|
export { formatDate, formatDateTime, formatRelativeTime, formatTime } from './date.js';
|
|
5
|
+
export { addDays, diffMs, formatDateDDMMMYYYY, formatDateISO, formatDatePattern, formatTime12h, formatTimeInWindowsZone, formatTimeInZone, isDateAfter, isDateBefore, isSameDay, startOfDay } from './dateMath.js';
|
|
5
6
|
export { getInitials } from './initials.js';
|
|
6
7
|
export { formatCompactNumber, formatNumber, formatPercent } from './number.js';
|
|
7
8
|
export type { FormatPhoneOptions, PhoneCountry, PhoneNumber } from './phone.js';
|
|
@@ -29,7 +29,7 @@ export { getConfig, getConfigValue, resetConfig, setConfig } from './config/inde
|
|
|
29
29
|
export type { DeepLinkConfig, DeepLinkRoute, ParsedLink } from './deepLink/index.js';
|
|
30
30
|
export { DeepLink, parseDeepLink, useDeepLink } from './deepLink/index.js';
|
|
31
31
|
export type { DateInput, DateStyle, FormatCurrencyOptions, FormatPhoneOptions, PhoneCountry, PhoneNumber, TimeStyle } from './formatters/index.js';
|
|
32
|
-
export { detectPhoneCountry, formatCompactNumber, formatCurrency, formatDate, formatDateTime, formatNumber, formatPercent, formatPhone, formatRelativeTime, formatTime, getInitials, isValidPhoneNumber, normalizePhone, parsePhoneNumber, parsePhoneNumberFromString } from './formatters/index.js';
|
|
32
|
+
export { addDays, detectPhoneCountry, diffMs, formatCompactNumber, formatCurrency, formatDate, formatDateDDMMMYYYY, formatDateISO, formatDatePattern, formatDateTime, formatNumber, formatPercent, formatPhone, formatRelativeTime, formatTime, formatTime12h, formatTimeInWindowsZone, formatTimeInZone, getInitials, isDateAfter, isDateBefore, isSameDay, isValidPhoneNumber, normalizePhone, parsePhoneNumber, parsePhoneNumberFromString, startOfDay } from './formatters/index.js';
|
|
33
33
|
export type { InitConfig } from './initSDK.js';
|
|
34
34
|
export { initWebority } from './initSDK.js';
|
|
35
35
|
export type { AuthActions } from './initUserAuth.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webority-technologies/mobile-core",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.6",
|
|
4
4
|
"description": "Platform layer for Webority React Native apps: HTTP clients, auth/token storage, config, logging, formatters, validators, network status, permissions, storage and version checks. No UI.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react-native",
|
|
@@ -134,7 +134,8 @@
|
|
|
134
134
|
},
|
|
135
135
|
"dependencies": {
|
|
136
136
|
"axios": "^1.19.0",
|
|
137
|
-
"libphonenumber-js": "^1.12.41"
|
|
137
|
+
"libphonenumber-js": "^1.12.41",
|
|
138
|
+
"windows-iana": "^5.1.0"
|
|
138
139
|
},
|
|
139
140
|
"peerDependencies": {
|
|
140
141
|
"@op-engineering/op-sqlite": "*",
|