@aemforms/af-formatters 0.22.91 → 0.22.93
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/esm/afb-formatters.js +104 -130
- package/lib/date/DateParser.js +144 -174
- package/package.json +1 -1
package/esm/afb-formatters.js
CHANGED
|
@@ -347,136 +347,99 @@ function formatDate(dateValue, language, skeleton, timeZone) {
|
|
|
347
347
|
return parts.map(p => p[1]).join('');
|
|
348
348
|
}
|
|
349
349
|
function parseDate(dateString, language, skeleton, timeZone, bUseUTC = false) {
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
350
|
+
if (skeleton.startsWith('date|')) {
|
|
351
|
+
skeleton = skeleton.split('|')[1];
|
|
352
|
+
}
|
|
353
|
+
const lookups = [];
|
|
354
|
+
const regexParts = [];
|
|
355
|
+
const calendar = calendarName(language);
|
|
356
|
+
const digits = digitChars(language);
|
|
357
|
+
const twoDigit = `([${digits[0]}-${digits[9]}]{1,2})`;
|
|
358
|
+
const threeDigit = `([${digits[0]}-${digits[9]}]{1,3})`;
|
|
359
|
+
const fourDigit = `([${digits[0]}-${digits[9]}]{1,4})`;
|
|
360
|
+
let hourCycle = 'h12';
|
|
361
|
+
let _bUseUTC = bUseUTC;
|
|
362
|
+
let _setFullYear = false;
|
|
363
|
+
const monthNumber = str => getNumber(str) - 1;
|
|
364
|
+
const getNumber = str => str.split('').reduce((total, digit) => (total * 10) + digits.indexOf(digit), 0);
|
|
365
|
+
const yearNumber = templateDigits => str => {
|
|
366
|
+
let year = getNumber(str);
|
|
367
|
+
year = year < 100 && templateDigits === 2 ? year + 2000 : year;
|
|
368
|
+
if (calendar === 'islamic') year = Math.ceil(year * 0.97 + 622);
|
|
369
|
+
if (templateDigits > 2 && year < 100) {
|
|
370
|
+
_setFullYear = true;
|
|
353
371
|
}
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
if (calendar === 'islamic') year = Math.ceil(year * 0.97 + 622);
|
|
371
|
-
if (templateDigits > 2 && year < 100) {
|
|
372
|
-
_setFullYear = true;
|
|
373
|
-
}
|
|
374
|
-
return year;
|
|
375
|
-
};
|
|
376
|
-
const monthLookup = list => month => list.indexOf(month);
|
|
377
|
-
const parsed = parseDateTimeSkeleton(skeleton, language);
|
|
378
|
-
const months = monthNames(language, Object.fromEntries(parsed));
|
|
379
|
-
parsed.forEach(([option, value, len]) => {
|
|
380
|
-
if (option === 'literal') {
|
|
381
|
-
if (value === '/') {
|
|
382
|
-
regexParts.push('/');
|
|
383
|
-
} else if (value === '-') {
|
|
384
|
-
regexParts.push('-');
|
|
385
|
-
} else if (value === ':') {
|
|
386
|
-
regexParts.push(':');
|
|
387
|
-
} else if (isSeparator(value)) {
|
|
388
|
-
regexParts.push(`[^${digits[0]}-${digits[9]}]`);
|
|
389
|
-
} else {
|
|
390
|
-
regexParts.push(value);
|
|
391
|
-
}
|
|
392
|
-
} else if (option === 'month' && ['numeric', '2-digit'].includes(value)) {
|
|
393
|
-
regexParts.push(twoDigit);
|
|
394
|
-
lookups.push(['month', monthNumber]);
|
|
395
|
-
} else if (option === 'month' && ['formatted', 'long', 'short', 'narrow'].includes(value)) {
|
|
396
|
-
regexParts.push(`(${months.join('|')})`);
|
|
397
|
-
lookups.push(['month', monthLookup(months)]);
|
|
398
|
-
} else if (['day', 'minute', 'second'].includes(option)) {
|
|
399
|
-
if (option === 'minute' || option === 'second') {
|
|
400
|
-
_bUseUTC = false;
|
|
401
|
-
}
|
|
402
|
-
regexParts.push(twoDigit);
|
|
403
|
-
lookups.push([option, getNumber]);
|
|
404
|
-
} else if (option === 'fractionalSecondDigits') {
|
|
405
|
-
_bUseUTC = false;
|
|
406
|
-
regexParts.push(threeDigit);
|
|
407
|
-
lookups.push([option, (v, obj) => obj.fractionalSecondDigits + getNumber(v)]);
|
|
408
|
-
} else if (option === 'hour') {
|
|
409
|
-
_bUseUTC = false;
|
|
410
|
-
regexParts.push(twoDigit);
|
|
411
|
-
lookups.push([option, (v, obj) => obj.hour + getNumber(v)]);
|
|
412
|
-
} else if (option === 'year') {
|
|
413
|
-
regexParts.push('numeric' === value ? fourDigit : twoDigit);
|
|
414
|
-
lookups.push(['year', yearNumber(len)]);
|
|
415
|
-
} else if (option === 'dayPeriod') {
|
|
416
|
-
_bUseUTC = false;
|
|
417
|
-
const dayPeriod = getDayPeriod(language);
|
|
418
|
-
if (dayPeriod) {
|
|
419
|
-
regexParts.push(dayPeriod.regex);
|
|
420
|
-
lookups.push(['hour', dayPeriod.fn]);
|
|
421
|
-
}
|
|
422
|
-
} else if (option === 'hourCycle') {
|
|
423
|
-
_bUseUTC = false;
|
|
424
|
-
hourCycle = value;
|
|
425
|
-
} else if (option === 'x-timeZoneName') {
|
|
426
|
-
_bUseUTC = false;
|
|
427
|
-
regexParts.push('(?:GMT|UTC|Z)?([+\\-−0-9]{0,3}:?[0-9]{0,2})');
|
|
428
|
-
lookups.push([option, (v, obj) => {
|
|
429
|
-
_bUseUTC = true;
|
|
430
|
-
if (!v) return;
|
|
431
|
-
const timeParts = v.replace(/−/, '-').match(/([+\-\d]{2,3}):?(\d{0,2})/);
|
|
432
|
-
const hours = timeParts[1] * 1;
|
|
433
|
-
obj.hour -= hours;
|
|
434
|
-
const mins = timeParts.length > 2 ? timeParts[2] * 1 : 0;
|
|
435
|
-
obj.minute -= (hours < 0) ? -mins : mins;
|
|
436
|
-
}]);
|
|
437
|
-
} else if (option !== 'timeZoneName') {
|
|
372
|
+
return year;
|
|
373
|
+
};
|
|
374
|
+
const monthLookup = list => month => list.indexOf(month);
|
|
375
|
+
const parsed = parseDateTimeSkeleton(skeleton, language);
|
|
376
|
+
const months = monthNames(language, Object.fromEntries(parsed));
|
|
377
|
+
parsed.forEach(([option, value, len]) => {
|
|
378
|
+
if (option === 'literal') {
|
|
379
|
+
regexParts.push(value);
|
|
380
|
+
} else if (option === 'month' && ['numeric', '2-digit'].includes(value)) {
|
|
381
|
+
regexParts.push(twoDigit);
|
|
382
|
+
lookups.push(['month', monthNumber]);
|
|
383
|
+
} else if (option === 'month' && ['formatted', 'long', 'short', 'narrow'].includes(value)) {
|
|
384
|
+
regexParts.push(`(${months.join('|')})`);
|
|
385
|
+
lookups.push(['month', monthLookup(months)]);
|
|
386
|
+
} else if (['day', 'minute', 'second'].includes(option)) {
|
|
387
|
+
if (option === 'minute' || option === 'second') {
|
|
438
388
|
_bUseUTC = false;
|
|
439
|
-
regexParts.push('.+?');
|
|
440
|
-
}
|
|
441
|
-
return regexParts;
|
|
442
|
-
}, []);
|
|
443
|
-
const regex = new RegExp(regexParts.join(''));
|
|
444
|
-
const match = dateString.match(regex);
|
|
445
|
-
if (match === null) {
|
|
446
|
-
if (skeleton.toLowerCase() === 'yyyy-MM-dd'.toLowerCase()) {
|
|
447
|
-
return null;
|
|
448
|
-
} else {
|
|
449
|
-
const parsedDate = parseDate(dateString, language, 'yyyy-MM-dd', timeZone, bUseUTC);
|
|
450
|
-
if (parsedDate instanceof Date) {
|
|
451
|
-
return parsedDate;
|
|
452
|
-
} else {
|
|
453
|
-
return null;
|
|
454
|
-
}
|
|
455
389
|
}
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
if (
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
utcDate.setUTCFullYear(dateObj.year);
|
|
390
|
+
regexParts.push(twoDigit);
|
|
391
|
+
lookups.push([option, getNumber]);
|
|
392
|
+
} else if (option === 'fractionalSecondDigits') {
|
|
393
|
+
_bUseUTC = false;
|
|
394
|
+
regexParts.push(threeDigit);
|
|
395
|
+
lookups.push([option, (v, obj) => obj.fractionalSecondDigits + getNumber(v)]);
|
|
396
|
+
} else if (option === 'hour') {
|
|
397
|
+
_bUseUTC = false;
|
|
398
|
+
regexParts.push(twoDigit);
|
|
399
|
+
lookups.push([option, (v, obj) => obj.hour + getNumber(v)]);
|
|
400
|
+
} else if (option === 'year') {
|
|
401
|
+
regexParts.push('numeric' === value ? fourDigit : twoDigit);
|
|
402
|
+
lookups.push(['year', yearNumber(len)]);
|
|
403
|
+
} else if (option === 'dayPeriod') {
|
|
404
|
+
_bUseUTC = false;
|
|
405
|
+
const dayPeriod = getDayPeriod(language);
|
|
406
|
+
if (dayPeriod) {
|
|
407
|
+
regexParts.push(dayPeriod.regex);
|
|
408
|
+
lookups.push(['hour', dayPeriod.fn]);
|
|
476
409
|
}
|
|
477
|
-
|
|
410
|
+
} else if (option === 'hourCycle') {
|
|
411
|
+
_bUseUTC = false;
|
|
412
|
+
hourCycle = value;
|
|
413
|
+
} else if (option === 'x-timeZoneName') {
|
|
414
|
+
_bUseUTC = false;
|
|
415
|
+
regexParts.push('(?:GMT|UTC|Z)?([+\\-−0-9]{0,3}:?[0-9]{0,2})');
|
|
416
|
+
lookups.push([option, (v, obj) => {
|
|
417
|
+
_bUseUTC = true;
|
|
418
|
+
if (!v) return;
|
|
419
|
+
const timeParts = v.replace(/−/, '-').match(/([+\-\d]{2,3}):?(\d{0,2})/);
|
|
420
|
+
const hours = timeParts[1] * 1;
|
|
421
|
+
obj.hour -= hours;
|
|
422
|
+
const mins = timeParts.length > 2 ? timeParts[2] * 1 : 0;
|
|
423
|
+
obj.minute -= (hours < 0) ? - mins : mins;
|
|
424
|
+
}]);
|
|
425
|
+
} else if (option !== 'timeZoneName') {
|
|
426
|
+
_bUseUTC = false;
|
|
427
|
+
regexParts.push('.+?');
|
|
478
428
|
}
|
|
479
|
-
|
|
429
|
+
return regexParts;
|
|
430
|
+
}, []);
|
|
431
|
+
const regex = new RegExp(`^${regexParts.join('')}$`);
|
|
432
|
+
const match = dateString.match(regex);
|
|
433
|
+
if (match === null) return null;
|
|
434
|
+
const dateObj = {year: 1972, month: 0, day: 1, hour: 0, minute: 0, second: 0, fractionalSecondDigits: 0};
|
|
435
|
+
match.slice(1).forEach((m, index) => {
|
|
436
|
+
const [element, func] = lookups[index];
|
|
437
|
+
dateObj[element] = func(m, dateObj);
|
|
438
|
+
});
|
|
439
|
+
if (hourCycle === 'h24' && dateObj.hour === 24) dateObj.hour = 0;
|
|
440
|
+
if (hourCycle === 'h12' && dateObj.hour === 12) dateObj.hour = 0;
|
|
441
|
+
if (_bUseUTC) {
|
|
442
|
+
const utcDate = new Date(Date.UTC(
|
|
480
443
|
dateObj.year,
|
|
481
444
|
dateObj.month,
|
|
482
445
|
dateObj.day,
|
|
@@ -484,14 +447,25 @@ function parseDate(dateString, language, skeleton, timeZone, bUseUTC = false) {
|
|
|
484
447
|
dateObj.minute,
|
|
485
448
|
dateObj.second,
|
|
486
449
|
dateObj.fractionalSecondDigits,
|
|
487
|
-
);
|
|
450
|
+
));
|
|
488
451
|
if (_setFullYear) {
|
|
489
|
-
|
|
452
|
+
utcDate.setUTCFullYear(dateObj.year);
|
|
490
453
|
}
|
|
491
|
-
return
|
|
492
|
-
}
|
|
493
|
-
|
|
454
|
+
return utcDate;
|
|
455
|
+
}
|
|
456
|
+
const jsDate = new Date(
|
|
457
|
+
dateObj.year,
|
|
458
|
+
dateObj.month,
|
|
459
|
+
dateObj.day,
|
|
460
|
+
dateObj.hour,
|
|
461
|
+
dateObj.minute,
|
|
462
|
+
dateObj.second,
|
|
463
|
+
dateObj.fractionalSecondDigits,
|
|
464
|
+
);
|
|
465
|
+
if (_setFullYear) {
|
|
466
|
+
jsDate.setFullYear(dateObj.year);
|
|
494
467
|
}
|
|
468
|
+
return timeZone == null ? jsDate : adjustTimeZone(jsDate, timeZone);
|
|
495
469
|
}
|
|
496
470
|
function parseDefaultDate(dateString, language, bUseUTC) {
|
|
497
471
|
return parseDate(dateString, language, 'yyyy-MM-dd', null, bUseUTC);
|
package/lib/date/DateParser.js
CHANGED
|
@@ -15,24 +15,24 @@ exports.parseDefaultDate = parseDefaultDate;
|
|
|
15
15
|
var _SkeletonParser = require("./SkeletonParser.js");
|
|
16
16
|
|
|
17
17
|
/*************************************************************************
|
|
18
|
-
* ADOBE CONFIDENTIAL
|
|
19
|
-
* ___________________
|
|
20
|
-
*
|
|
21
|
-
* Copyright 2022 Adobe
|
|
22
|
-
* All Rights Reserved.
|
|
23
|
-
*
|
|
24
|
-
* NOTICE: All information contained herein is, and remains
|
|
25
|
-
* the property of Adobe and its suppliers, if any. The intellectual
|
|
26
|
-
* and technical concepts contained herein are proprietary to Adobe
|
|
27
|
-
* and its suppliers and are protected by all applicable intellectual
|
|
28
|
-
* property laws, including trade secret and copyright laws.
|
|
29
|
-
* Dissemination of this information or reproduction of this material
|
|
30
|
-
* is strictly forbidden unless prior written permission is obtained
|
|
31
|
-
* from Adobe.
|
|
32
|
-
|
|
33
|
-
* Adobe permits you to use and modify this file solely in accordance with
|
|
34
|
-
* the terms of the Adobe license agreement accompanying it.
|
|
35
|
-
*************************************************************************/
|
|
18
|
+
* ADOBE CONFIDENTIAL
|
|
19
|
+
* ___________________
|
|
20
|
+
*
|
|
21
|
+
* Copyright 2022 Adobe
|
|
22
|
+
* All Rights Reserved.
|
|
23
|
+
*
|
|
24
|
+
* NOTICE: All information contained herein is, and remains
|
|
25
|
+
* the property of Adobe and its suppliers, if any. The intellectual
|
|
26
|
+
* and technical concepts contained herein are proprietary to Adobe
|
|
27
|
+
* and its suppliers and are protected by all applicable intellectual
|
|
28
|
+
* property laws, including trade secret and copyright laws.
|
|
29
|
+
* Dissemination of this information or reproduction of this material
|
|
30
|
+
* is strictly forbidden unless prior written permission is obtained
|
|
31
|
+
* from Adobe.
|
|
32
|
+
|
|
33
|
+
* Adobe permits you to use and modify this file solely in accordance with
|
|
34
|
+
* the terms of the Adobe license agreement accompanying it.
|
|
35
|
+
*************************************************************************/
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
38
|
* Credit: https://git.corp.adobe.com/dc/dfl/blob/master/src/patterns/dates.js
|
|
@@ -377,182 +377,152 @@ function formatDate(dateValue, language, skeleton, timeZone) {
|
|
|
377
377
|
function parseDate(dateString, language, skeleton, timeZone) {
|
|
378
378
|
let bUseUTC = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
|
|
379
379
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
const lookups = [];
|
|
388
|
-
const regexParts = [];
|
|
389
|
-
const calendar = calendarName(language);
|
|
390
|
-
const digits = digitChars(language);
|
|
391
|
-
const twoDigit = `\\b([${digits[0]}-${digits[9]}]{1,2})\\b`;
|
|
392
|
-
const threeDigit = `\\b([${digits[0]}-${digits[9]}]{1,3})\\b`;
|
|
393
|
-
const fourDigit = `\\b([${digits[0]}-${digits[9]}]{1,4})\\b`;
|
|
394
|
-
let hourCycle = 'h12';
|
|
395
|
-
let _bUseUTC = bUseUTC;
|
|
396
|
-
let _setFullYear = false; // functions to process the results of the regex match
|
|
397
|
-
|
|
398
|
-
const isSeparator = str => str.length === 1 && ':-/.'.includes(str);
|
|
399
|
-
|
|
400
|
-
const monthNumber = str => getNumber(str) - 1;
|
|
380
|
+
// start by getting all the localized parts of a date/time picture:
|
|
381
|
+
// digits, calendar name
|
|
382
|
+
if (skeleton.startsWith('date|')) {
|
|
383
|
+
skeleton = skeleton.split('|')[1];
|
|
384
|
+
}
|
|
401
385
|
|
|
402
|
-
|
|
386
|
+
const lookups = [];
|
|
387
|
+
const regexParts = [];
|
|
388
|
+
const calendar = calendarName(language);
|
|
389
|
+
const digits = digitChars(language);
|
|
390
|
+
const twoDigit = `([${digits[0]}-${digits[9]}]{1,2})`;
|
|
391
|
+
const threeDigit = `([${digits[0]}-${digits[9]}]{1,3})`;
|
|
392
|
+
const fourDigit = `([${digits[0]}-${digits[9]}]{1,4})`;
|
|
393
|
+
let hourCycle = 'h12';
|
|
394
|
+
let _bUseUTC = bUseUTC;
|
|
395
|
+
let _setFullYear = false; // functions to process the results of the regex match
|
|
403
396
|
|
|
404
|
-
|
|
405
|
-
let year = getNumber(str); //todo: align with AF
|
|
397
|
+
const isSeparator = str => str.length === 1 && ':-/.'.includes(str);
|
|
406
398
|
|
|
407
|
-
|
|
408
|
-
if (calendar === 'islamic') year = Math.ceil(year * 0.97 + 622);
|
|
399
|
+
const monthNumber = str => getNumber(str) - 1;
|
|
409
400
|
|
|
410
|
-
|
|
411
|
-
_setFullYear = true;
|
|
412
|
-
}
|
|
401
|
+
const getNumber = str => str.split('').reduce((total, digit) => total * 10 + digits.indexOf(digit), 0);
|
|
413
402
|
|
|
414
|
-
|
|
415
|
-
|
|
403
|
+
const yearNumber = templateDigits => str => {
|
|
404
|
+
let year = getNumber(str); //todo: align with AF
|
|
416
405
|
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
const parsed = (0, _SkeletonParser.parseDateTimeSkeleton)(skeleton, language);
|
|
420
|
-
const months = monthNames(language, Object.fromEntries(parsed)); // build up a regex expression that identifies each option in the skeleton
|
|
421
|
-
// We build two parallel structures:
|
|
422
|
-
// 1. the regex expression that will extract parts of the date/time
|
|
423
|
-
// 2. a lookup array that will convert the matched results into date/time values
|
|
424
|
-
|
|
425
|
-
parsed.forEach(_ref => {
|
|
426
|
-
let [option, value, len] = _ref;
|
|
427
|
-
|
|
428
|
-
// use a generic regex pattern for all single-character separator literals.
|
|
429
|
-
// We are treating this as separators: / vs - vs : etc
|
|
430
|
-
// other literals are treated as same
|
|
431
|
-
if (option === 'literal') {
|
|
432
|
-
if (value === '/') {
|
|
433
|
-
regexParts.push('/');
|
|
434
|
-
} else if (value === '-') {
|
|
435
|
-
regexParts.push('-');
|
|
436
|
-
} else if (value === ':') {
|
|
437
|
-
regexParts.push(':');
|
|
438
|
-
} else if (isSeparator(value)) {
|
|
439
|
-
regexParts.push(`[^${digits[0]}-${digits[9]}]`);
|
|
440
|
-
} else {
|
|
441
|
-
regexParts.push(value);
|
|
442
|
-
}
|
|
443
|
-
} else if (option === 'month' && ['numeric', '2-digit'].includes(value)) {
|
|
444
|
-
regexParts.push(twoDigit);
|
|
445
|
-
lookups.push(['month', monthNumber]);
|
|
446
|
-
} else if (option === 'month' && ['formatted', 'long', 'short', 'narrow'].includes(value)) {
|
|
447
|
-
regexParts.push(`(${months.join('|')})`);
|
|
448
|
-
lookups.push(['month', monthLookup(months)]);
|
|
449
|
-
} else if (['day', 'minute', 'second'].includes(option)) {
|
|
450
|
-
if (option === 'minute' || option === 'second') {
|
|
451
|
-
_bUseUTC = false;
|
|
452
|
-
}
|
|
406
|
+
year = year < 100 && templateDigits === 2 ? year + 2000 : year;
|
|
407
|
+
if (calendar === 'islamic') year = Math.ceil(year * 0.97 + 622);
|
|
453
408
|
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
_bUseUTC = false;
|
|
458
|
-
regexParts.push(threeDigit);
|
|
459
|
-
lookups.push([option, (v, obj) => obj.fractionalSecondDigits + getNumber(v)]);
|
|
460
|
-
} else if (option === 'hour') {
|
|
461
|
-
_bUseUTC = false;
|
|
462
|
-
regexParts.push(twoDigit);
|
|
463
|
-
lookups.push([option, (v, obj) => obj.hour + getNumber(v)]);
|
|
464
|
-
} else if (option === 'year') {
|
|
465
|
-
regexParts.push('numeric' === value ? fourDigit : twoDigit);
|
|
466
|
-
lookups.push(['year', yearNumber(len)]);
|
|
467
|
-
} else if (option === 'dayPeriod') {
|
|
468
|
-
_bUseUTC = false;
|
|
469
|
-
const dayPeriod = getDayPeriod(language);
|
|
409
|
+
if (templateDigits > 2 && year < 100) {
|
|
410
|
+
_setFullYear = true;
|
|
411
|
+
}
|
|
470
412
|
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
lookups.push(['hour', dayPeriod.fn]);
|
|
474
|
-
} // Any other part that we don't need, we'll just add a non-greedy consumption
|
|
413
|
+
return year;
|
|
414
|
+
};
|
|
475
415
|
|
|
476
|
-
|
|
416
|
+
const monthLookup = list => month => list.indexOf(month);
|
|
417
|
+
|
|
418
|
+
const parsed = (0, _SkeletonParser.parseDateTimeSkeleton)(skeleton, language);
|
|
419
|
+
const months = monthNames(language, Object.fromEntries(parsed)); // build up a regex expression that identifies each option in the skeleton
|
|
420
|
+
// We build two parallel structures:
|
|
421
|
+
// 1. the regex expression that will extract parts of the date/time
|
|
422
|
+
// 2. a lookup array that will convert the matched results into date/time values
|
|
423
|
+
|
|
424
|
+
parsed.forEach(_ref => {
|
|
425
|
+
let [option, value, len] = _ref;
|
|
426
|
+
|
|
427
|
+
// use a generic regex pattern for all single-character separator literals.
|
|
428
|
+
// Then we'll be forgiving when it comes to separators: / vs - vs : etc
|
|
429
|
+
if (option === 'literal') {
|
|
430
|
+
regexParts.push(value);
|
|
431
|
+
} else if (option === 'month' && ['numeric', '2-digit'].includes(value)) {
|
|
432
|
+
regexParts.push(twoDigit);
|
|
433
|
+
lookups.push(['month', monthNumber]);
|
|
434
|
+
} else if (option === 'month' && ['formatted', 'long', 'short', 'narrow'].includes(value)) {
|
|
435
|
+
regexParts.push(`(${months.join('|')})`);
|
|
436
|
+
lookups.push(['month', monthLookup(months)]);
|
|
437
|
+
} else if (['day', 'minute', 'second'].includes(option)) {
|
|
438
|
+
if (option === 'minute' || option === 'second') {
|
|
477
439
|
_bUseUTC = false;
|
|
478
|
-
hourCycle = value;
|
|
479
|
-
} else if (option === 'x-timeZoneName') {
|
|
480
|
-
_bUseUTC = false; // we handle only the GMT offset picture
|
|
481
|
-
|
|
482
|
-
regexParts.push('(?:GMT|UTC|Z)?([+\\-−0-9]{0,3}:?[0-9]{0,2})');
|
|
483
|
-
lookups.push([option, (v, obj) => {
|
|
484
|
-
_bUseUTC = true; // v could be undefined if we're on GMT time
|
|
485
|
-
|
|
486
|
-
if (!v) return; // replace the unicode minus, then extract hours [and minutes]
|
|
487
|
-
|
|
488
|
-
const timeParts = v.replace(/−/, '-').match(/([+\-\d]{2,3}):?(\d{0,2})/);
|
|
489
|
-
const hours = timeParts[1] * 1;
|
|
490
|
-
obj.hour -= hours;
|
|
491
|
-
const mins = timeParts.length > 2 ? timeParts[2] * 1 : 0;
|
|
492
|
-
obj.minute -= hours < 0 ? -mins : mins;
|
|
493
|
-
}]);
|
|
494
|
-
} else if (option !== 'timeZoneName') {
|
|
495
|
-
_bUseUTC = false;
|
|
496
|
-
regexParts.push('.+?');
|
|
497
440
|
}
|
|
498
441
|
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
442
|
+
regexParts.push(twoDigit);
|
|
443
|
+
lookups.push([option, getNumber]);
|
|
444
|
+
} else if (option === 'fractionalSecondDigits') {
|
|
445
|
+
_bUseUTC = false;
|
|
446
|
+
regexParts.push(threeDigit);
|
|
447
|
+
lookups.push([option, (v, obj) => obj.fractionalSecondDigits + getNumber(v)]);
|
|
448
|
+
} else if (option === 'hour') {
|
|
449
|
+
_bUseUTC = false;
|
|
450
|
+
regexParts.push(twoDigit);
|
|
451
|
+
lookups.push([option, (v, obj) => obj.hour + getNumber(v)]);
|
|
452
|
+
} else if (option === 'year') {
|
|
453
|
+
regexParts.push('numeric' === value ? fourDigit : twoDigit);
|
|
454
|
+
lookups.push(['year', yearNumber(len)]);
|
|
455
|
+
} else if (option === 'dayPeriod') {
|
|
456
|
+
_bUseUTC = false;
|
|
457
|
+
const dayPeriod = getDayPeriod(language);
|
|
458
|
+
|
|
459
|
+
if (dayPeriod) {
|
|
460
|
+
regexParts.push(dayPeriod.regex);
|
|
461
|
+
lookups.push(['hour', dayPeriod.fn]);
|
|
462
|
+
} // Any other part that we don't need, we'll just add a non-greedy consumption
|
|
463
|
+
|
|
464
|
+
} else if (option === 'hourCycle') {
|
|
465
|
+
_bUseUTC = false;
|
|
466
|
+
hourCycle = value;
|
|
467
|
+
} else if (option === 'x-timeZoneName') {
|
|
468
|
+
_bUseUTC = false; // we handle only the GMT offset picture
|
|
469
|
+
|
|
470
|
+
regexParts.push('(?:GMT|UTC|Z)?([+\\-−0-9]{0,3}:?[0-9]{0,2})');
|
|
471
|
+
lookups.push([option, (v, obj) => {
|
|
472
|
+
_bUseUTC = true; // v could be undefined if we're on GMT time
|
|
473
|
+
|
|
474
|
+
if (!v) return; // replace the unicode minus, then extract hours [and minutes]
|
|
475
|
+
|
|
476
|
+
const timeParts = v.replace(/−/, '-').match(/([+\-\d]{2,3}):?(\d{0,2})/);
|
|
477
|
+
const hours = timeParts[1] * 1;
|
|
478
|
+
obj.hour -= hours;
|
|
479
|
+
const mins = timeParts.length > 2 ? timeParts[2] * 1 : 0;
|
|
480
|
+
obj.minute -= hours < 0 ? -mins : mins;
|
|
481
|
+
}]);
|
|
482
|
+
} else if (option !== 'timeZoneName') {
|
|
483
|
+
_bUseUTC = false;
|
|
484
|
+
regexParts.push('.+?');
|
|
485
|
+
}
|
|
518
486
|
|
|
487
|
+
return regexParts;
|
|
488
|
+
}, []);
|
|
489
|
+
const regex = new RegExp(`^${regexParts.join('')}$`);
|
|
490
|
+
const match = dateString.match(regex);
|
|
491
|
+
if (match === null) return null; // now loop through all the matched pieces and build up an object we'll use to create a Date object
|
|
492
|
+
|
|
493
|
+
const dateObj = {
|
|
494
|
+
year: 1972,
|
|
495
|
+
month: 0,
|
|
496
|
+
day: 1,
|
|
497
|
+
hour: 0,
|
|
498
|
+
minute: 0,
|
|
499
|
+
second: 0,
|
|
500
|
+
fractionalSecondDigits: 0
|
|
501
|
+
};
|
|
502
|
+
match.slice(1).forEach((m, index) => {
|
|
503
|
+
const [element, func] = lookups[index];
|
|
504
|
+
dateObj[element] = func(m, dateObj);
|
|
505
|
+
});
|
|
506
|
+
if (hourCycle === 'h24' && dateObj.hour === 24) dateObj.hour = 0;
|
|
507
|
+
if (hourCycle === 'h12' && dateObj.hour === 12) dateObj.hour = 0;
|
|
519
508
|
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
month: 0,
|
|
523
|
-
day: 1,
|
|
524
|
-
hour: 0,
|
|
525
|
-
minute: 0,
|
|
526
|
-
second: 0,
|
|
527
|
-
fractionalSecondDigits: 0
|
|
528
|
-
};
|
|
529
|
-
match.slice(1).forEach((m, index) => {
|
|
530
|
-
const [element, func] = lookups[index];
|
|
531
|
-
dateObj[element] = func(m, dateObj);
|
|
532
|
-
});
|
|
533
|
-
if (hourCycle === 'h24' && dateObj.hour === 24) dateObj.hour = 0;
|
|
534
|
-
if (hourCycle === 'h12' && dateObj.hour === 12) dateObj.hour = 0;
|
|
535
|
-
|
|
536
|
-
if (_bUseUTC) {
|
|
537
|
-
const utcDate = new Date(Date.UTC(dateObj.year, dateObj.month, dateObj.day, dateObj.hour, dateObj.minute, dateObj.second, dateObj.fractionalSecondDigits));
|
|
538
|
-
|
|
539
|
-
if (_setFullYear) {
|
|
540
|
-
utcDate.setUTCFullYear(dateObj.year);
|
|
541
|
-
}
|
|
509
|
+
if (_bUseUTC) {
|
|
510
|
+
const utcDate = new Date(Date.UTC(dateObj.year, dateObj.month, dateObj.day, dateObj.hour, dateObj.minute, dateObj.second, dateObj.fractionalSecondDigits));
|
|
542
511
|
|
|
543
|
-
|
|
512
|
+
if (_setFullYear) {
|
|
513
|
+
utcDate.setUTCFullYear(dateObj.year);
|
|
544
514
|
}
|
|
545
515
|
|
|
546
|
-
|
|
516
|
+
return utcDate;
|
|
517
|
+
}
|
|
547
518
|
|
|
548
|
-
|
|
549
|
-
jsDate.setFullYear(dateObj.year);
|
|
550
|
-
}
|
|
519
|
+
const jsDate = new Date(dateObj.year, dateObj.month, dateObj.day, dateObj.hour, dateObj.minute, dateObj.second, dateObj.fractionalSecondDigits);
|
|
551
520
|
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
return null;
|
|
521
|
+
if (_setFullYear) {
|
|
522
|
+
jsDate.setFullYear(dateObj.year);
|
|
555
523
|
}
|
|
524
|
+
|
|
525
|
+
return timeZone == null ? jsDate : adjustTimeZone(jsDate, timeZone);
|
|
556
526
|
}
|
|
557
527
|
|
|
558
528
|
function parseDefaultDate(dateString, language, bUseUTC) {
|