@aemforms/af-formatters 0.22.26 → 0.22.29
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/cjs/index.cjs +62 -239
- package/lib/esm/date/DateParser.js +52 -189
- package/lib/esm/date/SkeletonParser.js +39 -100
- package/lib/esm/date/index.js +20 -18
- package/lib/esm/index.js +34 -13
- package/lib/esm/number/NumberParser.js +34 -15
- package/lib/esm/number/SkeletonParser.js +75 -74
- package/lib/esm/number/currencies.js +24 -6
- package/package.json +11 -1
- package/lib/browser/afb-formatters.js +0 -950
|
@@ -1,34 +1,26 @@
|
|
|
1
1
|
/*************************************************************************
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
2
|
+
* ADOBE CONFIDENTIAL
|
|
3
|
+
* ___________________
|
|
4
|
+
*
|
|
5
|
+
* Copyright 2022 Adobe
|
|
6
|
+
* All Rights Reserved.
|
|
7
|
+
*
|
|
8
|
+
* NOTICE: All information contained herein is, and remains
|
|
9
|
+
* the property of Adobe and its suppliers, if any. The intellectual
|
|
10
|
+
* and technical concepts contained herein are proprietary to Adobe
|
|
11
|
+
* and its suppliers and are protected by all applicable intellectual
|
|
12
|
+
* property laws, including trade secret and copyright laws.
|
|
13
|
+
* Dissemination of this information or reproduction of this material
|
|
14
|
+
* is strictly forbidden unless prior written permission is obtained
|
|
15
|
+
* from Adobe.
|
|
16
|
+
|
|
17
|
+
* Adobe permits you to use and modify this file solely in accordance with
|
|
18
|
+
* the terms of the Adobe license agreement accompanying it.
|
|
19
|
+
*************************************************************************/
|
|
20
|
+
|
|
21
|
+
import { ShorthandStyles, parseDateTimeSkeleton } from './SkeletonParser.js';
|
|
21
22
|
|
|
22
|
-
import {parseDateTimeSkeleton, ShorthandStyles} from './SkeletonParser.js';
|
|
23
|
-
|
|
24
|
-
// get the localized month names resulting from a given pattern
|
|
25
23
|
const twelveMonths = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11].map(m => new Date(2000, m, 1));
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* returns the name of all the months for a given locale and given Date Format Settings
|
|
29
|
-
* @param locale {string}
|
|
30
|
-
* @param options {string} instance of Intl.DateTimeFormatOptions
|
|
31
|
-
*/
|
|
32
24
|
function monthNames(locale, options) {
|
|
33
25
|
return twelveMonths.map(month => {
|
|
34
26
|
const parts = new Intl.DateTimeFormat(locale, options).formatToParts(month);
|
|
@@ -36,32 +28,17 @@ function monthNames(locale, options) {
|
|
|
36
28
|
return m && m.value;
|
|
37
29
|
});
|
|
38
30
|
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* return an array of digits used by a given locale
|
|
42
|
-
* @param locale {string}
|
|
43
|
-
*/
|
|
44
31
|
function digitChars(locale) {
|
|
45
32
|
return new Intl.NumberFormat(locale, {style:'decimal', useGrouping:false})
|
|
46
33
|
.format(9876543210)
|
|
47
34
|
.split('')
|
|
48
35
|
.reverse();
|
|
49
36
|
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* returns the calendar name used in a given locale
|
|
53
|
-
* @param locale {string}
|
|
54
|
-
*/
|
|
55
37
|
function calendarName(locale) {
|
|
56
38
|
const parts = new Intl.DateTimeFormat(locale, {era:'short'}).formatToParts(new Date());
|
|
57
39
|
const era = parts.find(p => p.type === 'era')?.value;
|
|
58
40
|
return era === 'هـ' ? 'islamic' : 'gregory';
|
|
59
41
|
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* returns the representation of the time of day for a given language
|
|
63
|
-
* @param language {string}
|
|
64
|
-
*/
|
|
65
42
|
function getDayPeriod(language) {
|
|
66
43
|
const morning = new Date(2000, 1, 1, 1, 1, 1);
|
|
67
44
|
const afternoon = new Date(2000, 1, 1, 16, 1, 1);
|
|
@@ -74,13 +51,7 @@ function getDayPeriod(language) {
|
|
|
74
51
|
fn: (period, obj) => obj.hour += (period === pm.value) ? 12 : 0
|
|
75
52
|
};
|
|
76
53
|
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* get the offset in MS, given a date and timezone
|
|
80
|
-
* @param dateObj {Date}
|
|
81
|
-
* @param timeZone {string}
|
|
82
|
-
*/
|
|
83
|
-
export function offsetMS(dateObj, timeZone) {
|
|
54
|
+
function offsetMS(dateObj, timeZone) {
|
|
84
55
|
let tzOffset;
|
|
85
56
|
try {
|
|
86
57
|
tzOffset = new Intl.DateTimeFormat('en-US', {timeZone, timeZoneName: 'longOffset'}).format(dateObj);
|
|
@@ -89,13 +60,12 @@ export function offsetMS(dateObj, timeZone) {
|
|
|
89
60
|
}
|
|
90
61
|
const offset = /GMT([+\-−])?(\d{1,2}):?(\d{0,2})?/.exec(tzOffset);
|
|
91
62
|
if (!offset) return 0;
|
|
92
|
-
const [sign, hours, minutes] = offset.slice(1)
|
|
93
|
-
const nHours = isNaN(parseInt(hours)) ? 0 : parseInt(hours)
|
|
94
|
-
const nMinutes = isNaN(parseInt(minutes)) ? 0 : parseInt(minutes)
|
|
63
|
+
const [sign, hours, minutes] = offset.slice(1);
|
|
64
|
+
const nHours = isNaN(parseInt(hours)) ? 0 : parseInt(hours);
|
|
65
|
+
const nMinutes = isNaN(parseInt(minutes)) ? 0 : parseInt(minutes);
|
|
95
66
|
const result = ((nHours * 60) + nMinutes) * 60 * 1000;
|
|
96
67
|
return sign === '-' ? - result : result;
|
|
97
68
|
}
|
|
98
|
-
|
|
99
69
|
function getTimezoneOffsetFrom(otherTimezone) {
|
|
100
70
|
var date = new Date();
|
|
101
71
|
function objFromStr(str) {
|
|
@@ -110,65 +80,29 @@ function getTimezoneOffsetFrom(otherTimezone) {
|
|
|
110
80
|
var other = objFromStr(str);
|
|
111
81
|
str = date.toLocaleString('en-US', { day: 'numeric', hour: 'numeric', minute: 'numeric', hourCycle: 'h23' });
|
|
112
82
|
var myLocale = objFromStr(str);
|
|
113
|
-
var otherOffset = (other.day * 24 * 60) + (other.hour * 60) + (other.minute);
|
|
114
|
-
var myLocaleOffset = (myLocale.day * 24 * 60) + (myLocale.hour * 60) + (myLocale.minute);
|
|
115
|
-
// (utc date + otherZoneDifference) - (utc date + myZoneDifference) - (-1 * myTimeZoneDifference)
|
|
83
|
+
var otherOffset = (other.day * 24 * 60) + (other.hour * 60) + (other.minute);
|
|
84
|
+
var myLocaleOffset = (myLocale.day * 24 * 60) + (myLocale.hour * 60) + (myLocale.minute);
|
|
116
85
|
return otherOffset - myLocaleOffset - date.getTimezoneOffset();
|
|
117
86
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
//const defaultOffset = dateObj.getTimezoneOffset();
|
|
121
|
-
const timezoneOffset = getTimezoneOffsetFrom(timezone)
|
|
87
|
+
function offsetMSFallback(dateObj, timezone) {
|
|
88
|
+
const timezoneOffset = getTimezoneOffsetFrom(timezone);
|
|
122
89
|
return timezoneOffset * 60 * 1000;
|
|
123
90
|
}
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* adjust from the default JavaScript timezone to the default timezone
|
|
127
|
-
* @param dateObj {Date}
|
|
128
|
-
* @param timeZone {string}
|
|
129
|
-
*/
|
|
130
|
-
export function adjustTimeZone(dateObj, timeZone) {
|
|
91
|
+
function adjustTimeZone(dateObj, timeZone) {
|
|
131
92
|
if (dateObj === null) return null;
|
|
132
|
-
// const defaultOffset = new Intl.DateTimeFormat('en-US', { timeZoneName: 'longOffset'}).format(dateObj);
|
|
133
93
|
let baseDate = dateObj.getTime() - dateObj.getTimezoneOffset() * 60 * 1000;
|
|
134
94
|
const offset = offsetMS(dateObj, timeZone);
|
|
135
|
-
|
|
95
|
+
offsetMSFallback(dateObj, timeZone);
|
|
136
96
|
baseDate += - offset;
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
// get the offset for the default JS environment
|
|
140
|
-
// return days since the epoch
|
|
141
97
|
return new Date(baseDate);
|
|
142
98
|
}
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* Our script object model treats dates as numbers where the integer portion is days since the epoch,
|
|
146
|
-
* the fractional portion is the number hours in the day
|
|
147
|
-
* @param dateObj {Date}
|
|
148
|
-
* @returns {number}
|
|
149
|
-
*/
|
|
150
|
-
export function datetimeToNumber(dateObj) {
|
|
99
|
+
function datetimeToNumber(dateObj) {
|
|
151
100
|
if (dateObj === null) return 0;
|
|
152
|
-
// return days since the epoch
|
|
153
101
|
return dateObj.getTime() / ( 1000 * 60 * 60 * 24 );
|
|
154
102
|
}
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* Our script object model treats dates as numbers where the integer portion is days since the epoch,
|
|
158
|
-
* the fractional portion is the number hours in the day
|
|
159
|
-
* @param num
|
|
160
|
-
* @returns {Date}
|
|
161
|
-
*/
|
|
162
|
-
export function numberToDatetime(num) {
|
|
103
|
+
function numberToDatetime(num) {
|
|
163
104
|
return new Date(Math.round(num * 1000 * 60 * 60 * 24));
|
|
164
105
|
}
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* in some cases, DateTimeFormat doesn't respect the 'numeric' vs. '2-digit' setting
|
|
168
|
-
* for time values. The function corrects that
|
|
169
|
-
* @param formattedParts instance of Intl.DateTimeFormatPart[]
|
|
170
|
-
* @param parsed
|
|
171
|
-
*/
|
|
172
106
|
function fixDigits(formattedParts, parsed) {
|
|
173
107
|
['hour', 'minute', 'second'].forEach(type => {
|
|
174
108
|
const defn = formattedParts.find(f => f.type === type);
|
|
@@ -178,55 +112,29 @@ function fixDigits(formattedParts, parsed) {
|
|
|
178
112
|
if (fmt === 'numeric' && defn.value.length === 2 && defn.value.charAt(0) === '0') defn.value = defn.value.slice(1);
|
|
179
113
|
});
|
|
180
114
|
}
|
|
181
|
-
|
|
182
115
|
function fixYear(formattedParts, parsed) {
|
|
183
|
-
// two digit years are handled differently in DateTimeFormat. 00 becomes 1900
|
|
184
|
-
// providing a two digit year 0010 gets formatted to 10 and when parsed becomes 1910
|
|
185
|
-
// Hence we need to pad the year with 0 as required by the skeleton and mentioned in
|
|
186
|
-
// unicode. https://www.unicode.org/reports/tr35/tr35-dates.html#dfst-year
|
|
187
116
|
const defn = formattedParts.find(f => f.type === 'year');
|
|
188
117
|
if (!defn) return;
|
|
189
|
-
// eslint-disable-next-line no-unused-vars
|
|
190
118
|
const chars = parsed.find(pair => pair[0] === 'year')[2];
|
|
191
119
|
while(defn.value.length < chars) {
|
|
192
120
|
defn.value = `0${defn.value}`;
|
|
193
121
|
}
|
|
194
122
|
}
|
|
195
|
-
|
|
196
|
-
/**
|
|
197
|
-
*
|
|
198
|
-
* @param dateValue {Date}
|
|
199
|
-
* @param language {string}
|
|
200
|
-
* @param skeleton {string}
|
|
201
|
-
* @param timeZone {string}
|
|
202
|
-
* @returns {T}
|
|
203
|
-
*/
|
|
204
123
|
function formatDateToParts(dateValue, language, skeleton, timeZone) {
|
|
205
|
-
// DateTimeFormat renames some of the options in its formatted output
|
|
206
|
-
//@ts-ignore
|
|
207
124
|
const mappings = key => ({
|
|
208
125
|
hour12: 'dayPeriod',
|
|
209
126
|
fractionalSecondDigits: 'fractionalSecond',
|
|
210
127
|
})[key] || key;
|
|
211
|
-
|
|
212
|
-
// produces an array of name/value pairs of skeleton parts
|
|
213
128
|
const allParameters = parseDateTimeSkeleton(skeleton, language);
|
|
214
129
|
allParameters.push(['timeZone', timeZone]);
|
|
215
|
-
|
|
216
130
|
const parsed = allParameters.filter(p => !p[0].startsWith('x-'));
|
|
217
131
|
const nonStandard = allParameters.filter(p => p[0].startsWith('x-'));
|
|
218
|
-
// reduce to a set of options that can be used to format
|
|
219
132
|
const options = Object.fromEntries(parsed);
|
|
220
133
|
delete options.literal;
|
|
221
|
-
|
|
222
134
|
const df = new Intl.DateTimeFormat(language, options);
|
|
223
|
-
// formattedParts will have all the pieces we need for our date -- but not in the correct order
|
|
224
135
|
const formattedParts = df.formatToParts(dateValue);
|
|
225
|
-
|
|
226
136
|
fixDigits(formattedParts, allParameters);
|
|
227
137
|
fixYear(formattedParts, parsed);
|
|
228
|
-
// iterate through the original parsed components and use its ordering and literals,
|
|
229
|
-
// and add the formatted pieces
|
|
230
138
|
return parsed.reduce((result, cur) => {
|
|
231
139
|
if (cur[0] === 'literal') result.push(cur);
|
|
232
140
|
else {
|
|
@@ -236,37 +144,25 @@ function formatDateToParts(dateValue, language, skeleton, timeZone) {
|
|
|
236
144
|
const category = tz[0];
|
|
237
145
|
if (category === 'Z') {
|
|
238
146
|
if (tz.length < 4) {
|
|
239
|
-
// handle 'Z', 'ZZ', 'ZZZ' Time Zone: ISO8601 basic hms? / RFC 822
|
|
240
147
|
v.value = v.value.replace(/(GMT|:)/g, '');
|
|
241
148
|
if (v.value === '') v.value = '+0000';
|
|
242
149
|
} else if (tz.length === 5) {
|
|
243
|
-
// 'ZZZZZ' Time Zone: ISO8601 extended hms?
|
|
244
150
|
if (v.value === 'GMT') v.value = 'Z';
|
|
245
151
|
else v.value = v.value.replace(/GMT/, '');
|
|
246
152
|
}
|
|
247
153
|
}
|
|
248
154
|
if (category === 'X' || category === 'x') {
|
|
249
155
|
if (tz.length === 1) {
|
|
250
|
-
// 'X' ISO8601 basic hm?, with Z for 0
|
|
251
|
-
// -08, +0530, Z
|
|
252
|
-
// 'x' ISO8601 basic hm?, without Z for 0
|
|
253
156
|
v.value = v.value.replace(/(GMT|:(00)?)/g, '');
|
|
254
157
|
}
|
|
255
158
|
if (tz.length === 2) {
|
|
256
|
-
// 'XX' ISO8601 basic hm, with Z
|
|
257
|
-
// -0800, Z
|
|
258
|
-
// 'xx' ISO8601 basic hm, without Z
|
|
259
159
|
v.value = v.value.replace(/(GMT|:)/g, '');
|
|
260
160
|
}
|
|
261
161
|
if (tz.length === 3) {
|
|
262
|
-
// 'XXX' ISO8601 extended hm, with Z
|
|
263
|
-
// -08:00, Z
|
|
264
|
-
// 'xxx' ISO8601 extended hm, without Z
|
|
265
162
|
v.value = v.value.replace(/GMT/g, '');
|
|
266
163
|
}
|
|
267
164
|
if (category === 'X' && v.value === '') v.value = 'Z';
|
|
268
165
|
} else if (tz === 'O') {
|
|
269
|
-
// eliminate 'GMT', leading and trailing zeros
|
|
270
166
|
v.value = v.value.replace(/GMT/g, '').replace(/0(\d+):/, '$1:').replace(/:00/, '');
|
|
271
167
|
if (v.value === '') v.value = '+0';
|
|
272
168
|
}
|
|
@@ -276,41 +172,28 @@ function formatDateToParts(dateValue, language, skeleton, timeZone) {
|
|
|
276
172
|
return result;
|
|
277
173
|
}, []);
|
|
278
174
|
}
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
* @param language {string}
|
|
284
|
-
* @param skeleton {string}
|
|
285
|
-
* @param timeZone {string}
|
|
286
|
-
*/
|
|
287
|
-
export function formatDate(dateValue, language, skeleton, timeZone) {
|
|
175
|
+
function formatDate(dateValue, language, skeleton, timeZone) {
|
|
176
|
+
if (skeleton.startsWith('date|')) {
|
|
177
|
+
skeleton = skeleton.split('|')[1];
|
|
178
|
+
}
|
|
288
179
|
if (ShorthandStyles.find(type => skeleton.includes(type))) {
|
|
289
180
|
const options = {timeZone};
|
|
290
|
-
// the skeleton could have two keywords -- one for date, one for time
|
|
291
181
|
const parts = skeleton.split(/\s/).filter(s => s.length);
|
|
292
182
|
if (ShorthandStyles.indexOf(parts[0]) > -1) {
|
|
293
|
-
options.dateStyle = parts[0]
|
|
183
|
+
options.dateStyle = parts[0];
|
|
294
184
|
}
|
|
295
185
|
if (parts.length > 1 && ShorthandStyles.indexOf(parts[1]) > -1) {
|
|
296
|
-
options.timeStyle = parts[1]
|
|
186
|
+
options.timeStyle = parts[1];
|
|
297
187
|
}
|
|
298
188
|
return new Intl.DateTimeFormat(language, options).format(dateValue);
|
|
299
189
|
}
|
|
300
190
|
const parts = formatDateToParts(dateValue, language, skeleton, timeZone);
|
|
301
191
|
return parts.map(p => p[1]).join('');
|
|
302
192
|
}
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
* @param language {string}
|
|
308
|
-
* @param skeleton {string}
|
|
309
|
-
* @param timeZone {string}
|
|
310
|
-
*/
|
|
311
|
-
export function parseDate(dateString, language, skeleton, timeZone, bUseUTC = false) {
|
|
312
|
-
// start by getting all the localized parts of a date/time picture:
|
|
313
|
-
// digits, calendar name
|
|
193
|
+
function parseDate(dateString, language, skeleton, timeZone, bUseUTC = false) {
|
|
194
|
+
if (skeleton.startsWith('date|')) {
|
|
195
|
+
skeleton = skeleton.split('|')[1];
|
|
196
|
+
}
|
|
314
197
|
const lookups = [];
|
|
315
198
|
const regexParts = [];
|
|
316
199
|
const calendar = calendarName(language);
|
|
@@ -321,13 +204,11 @@ export function parseDate(dateString, language, skeleton, timeZone, bUseUTC = fa
|
|
|
321
204
|
let hourCycle = 'h12';
|
|
322
205
|
let _bUseUTC = bUseUTC;
|
|
323
206
|
let _setFullYear = false;
|
|
324
|
-
// functions to process the results of the regex match
|
|
325
207
|
const isSeparator = str => str.length === 1 && ':-/.'.includes(str);
|
|
326
208
|
const monthNumber = str => getNumber(str) - 1;
|
|
327
209
|
const getNumber = str => str.split('').reduce((total, digit) => (total * 10) + digits.indexOf(digit), 0);
|
|
328
210
|
const yearNumber = templateDigits => str => {
|
|
329
211
|
let year = getNumber(str);
|
|
330
|
-
//todo: align with AF
|
|
331
212
|
year = year < 100 && templateDigits === 2 ? year + 2000 : year;
|
|
332
213
|
if (calendar === 'islamic') year = Math.ceil(year * 0.97 + 622);
|
|
333
214
|
if (templateDigits > 2 && year < 100) {
|
|
@@ -336,67 +217,51 @@ export function parseDate(dateString, language, skeleton, timeZone, bUseUTC = fa
|
|
|
336
217
|
return year;
|
|
337
218
|
};
|
|
338
219
|
const monthLookup = list => month => list.indexOf(month);
|
|
339
|
-
|
|
340
220
|
const parsed = parseDateTimeSkeleton(skeleton, language);
|
|
341
221
|
const months = monthNames(language, Object.fromEntries(parsed));
|
|
342
|
-
// build up a regex expression that identifies each option in the skeleton
|
|
343
|
-
// We build two parallel structures:
|
|
344
|
-
// 1. the regex expression that will extract parts of the date/time
|
|
345
|
-
// 2. a lookup array that will convert the matched results into date/time values
|
|
346
222
|
parsed.forEach(([option, value, len]) => {
|
|
347
|
-
// use a generic regex pattern for all single-character separator literals.
|
|
348
|
-
// Then we'll be forgiving when it comes to separators: / vs - vs : etc
|
|
349
223
|
if (option === 'literal') {
|
|
350
224
|
if (isSeparator(value)) regexParts.push(`[^${digits[0]}-${digits[9]}]`);
|
|
351
225
|
else regexParts.push(value);
|
|
352
|
-
|
|
353
226
|
} else if (option === 'month' && ['numeric', '2-digit'].includes(value)) {
|
|
354
227
|
regexParts.push(twoDigit);
|
|
355
228
|
lookups.push(['month', monthNumber]);
|
|
356
|
-
|
|
357
229
|
} else if (option === 'month' && ['formatted', 'long', 'short', 'narrow'].includes(value)) {
|
|
358
230
|
regexParts.push(`(${months.join('|')})`);
|
|
359
231
|
lookups.push(['month', monthLookup(months)]);
|
|
360
|
-
|
|
361
232
|
} else if (['day', 'minute', 'second'].includes(option)) {
|
|
362
233
|
if (option === 'minute' || option === 'second') {
|
|
363
|
-
_bUseUTC = false
|
|
234
|
+
_bUseUTC = false;
|
|
364
235
|
}
|
|
365
236
|
regexParts.push(twoDigit);
|
|
366
237
|
lookups.push([option, getNumber]);
|
|
367
|
-
|
|
368
238
|
} else if (option === 'fractionalSecondDigits') {
|
|
369
|
-
_bUseUTC = false
|
|
239
|
+
_bUseUTC = false;
|
|
370
240
|
regexParts.push(threeDigit);
|
|
371
241
|
lookups.push([option, (v, obj) => obj.fractionalSecondDigits + getNumber(v)]);
|
|
372
|
-
|
|
373
242
|
} else if (option === 'hour') {
|
|
374
|
-
_bUseUTC = false
|
|
243
|
+
_bUseUTC = false;
|
|
375
244
|
regexParts.push(twoDigit);
|
|
376
245
|
lookups.push([option, (v, obj) => obj.hour + getNumber(v)]);
|
|
377
246
|
} else if (option === 'year') {
|
|
378
247
|
regexParts.push('numeric' === value ? fourDigit : twoDigit);
|
|
379
248
|
lookups.push(['year', yearNumber(len)]);
|
|
380
249
|
} else if (option === 'dayPeriod') {
|
|
381
|
-
_bUseUTC = false
|
|
250
|
+
_bUseUTC = false;
|
|
382
251
|
const dayPeriod = getDayPeriod(language);
|
|
383
252
|
if (dayPeriod) {
|
|
384
253
|
regexParts.push(dayPeriod.regex);
|
|
385
254
|
lookups.push(['hour', dayPeriod.fn]);
|
|
386
255
|
}
|
|
387
|
-
// Any other part that we don't need, we'll just add a non-greedy consumption
|
|
388
256
|
} else if (option === 'hourCycle') {
|
|
389
|
-
_bUseUTC = false
|
|
257
|
+
_bUseUTC = false;
|
|
390
258
|
hourCycle = value;
|
|
391
259
|
} else if (option === 'x-timeZoneName') {
|
|
392
|
-
_bUseUTC = false
|
|
393
|
-
// we handle only the GMT offset picture
|
|
260
|
+
_bUseUTC = false;
|
|
394
261
|
regexParts.push('(?:GMT|UTC|Z)?([+\\-−0-9]{0,3}:?[0-9]{0,2})');
|
|
395
262
|
lookups.push([option, (v, obj) => {
|
|
396
263
|
_bUseUTC = true;
|
|
397
|
-
// v could be undefined if we're on GMT time
|
|
398
264
|
if (!v) return;
|
|
399
|
-
// replace the unicode minus, then extract hours [and minutes]
|
|
400
265
|
const timeParts = v.replace(/−/, '-').match(/([+\-\d]{2,3}):?(\d{0,2})/);
|
|
401
266
|
const hours = timeParts[1] * 1;
|
|
402
267
|
obj.hour -= hours;
|
|
@@ -404,17 +269,14 @@ export function parseDate(dateString, language, skeleton, timeZone, bUseUTC = fa
|
|
|
404
269
|
obj.minute -= (hours < 0) ? - mins : mins;
|
|
405
270
|
}]);
|
|
406
271
|
} else if (option !== 'timeZoneName') {
|
|
407
|
-
_bUseUTC = false
|
|
272
|
+
_bUseUTC = false;
|
|
408
273
|
regexParts.push('.+?');
|
|
409
274
|
}
|
|
410
|
-
|
|
411
275
|
return regexParts;
|
|
412
276
|
}, []);
|
|
413
277
|
const regex = new RegExp(regexParts.join(''));
|
|
414
278
|
const match = dateString.match(regex);
|
|
415
279
|
if (match === null) return dateString;
|
|
416
|
-
|
|
417
|
-
// now loop through all the matched pieces and build up an object we'll use to create a Date object
|
|
418
280
|
const dateObj = {year: 1972, month: 0, day: 1, hour: 0, minute: 0, second: 0, fractionalSecondDigits: 0};
|
|
419
281
|
match.slice(1).forEach((m, index) => {
|
|
420
282
|
const [element, func] = lookups[index];
|
|
@@ -451,7 +313,8 @@ export function parseDate(dateString, language, skeleton, timeZone, bUseUTC = fa
|
|
|
451
313
|
}
|
|
452
314
|
return timeZone == null ? jsDate : adjustTimeZone(jsDate, timeZone);
|
|
453
315
|
}
|
|
454
|
-
|
|
455
|
-
export function parseDefaultDate(dateString, language, bUseUTC) {
|
|
316
|
+
function parseDefaultDate(dateString, language, bUseUTC) {
|
|
456
317
|
return parseDate(dateString, language, 'short', null, false);
|
|
457
318
|
}
|
|
319
|
+
|
|
320
|
+
export { adjustTimeZone, datetimeToNumber, formatDate, numberToDatetime, offsetMS, offsetMSFallback, parseDate, parseDefaultDate };
|