@aemforms/af-formatters 0.22.90 → 0.22.91
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 +130 -106
- package/lib/date/DateParser.js +156 -126
- package/package.json +1 -1
package/esm/afb-formatters.js
CHANGED
|
@@ -347,101 +347,136 @@ 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
|
-
|
|
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 isSeparator = str => str.length === 1 && ':-/.'.includes(str);
|
|
364
|
-
const monthNumber = str => getNumber(str) - 1;
|
|
365
|
-
const getNumber = str => str.split('').reduce((total, digit) => (total * 10) + digits.indexOf(digit), 0);
|
|
366
|
-
const yearNumber = templateDigits => str => {
|
|
367
|
-
let year = getNumber(str);
|
|
368
|
-
year = year < 100 && templateDigits === 2 ? year + 2000 : year;
|
|
369
|
-
if (calendar === 'islamic') year = Math.ceil(year * 0.97 + 622);
|
|
370
|
-
if (templateDigits > 2 && year < 100) {
|
|
371
|
-
_setFullYear = true;
|
|
350
|
+
try {
|
|
351
|
+
if (skeleton.startsWith('date|')) {
|
|
352
|
+
skeleton = skeleton.split('|')[1];
|
|
372
353
|
}
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
if (
|
|
354
|
+
const lookups = [];
|
|
355
|
+
const regexParts = [];
|
|
356
|
+
const calendar = calendarName(language);
|
|
357
|
+
const digits = digitChars(language);
|
|
358
|
+
const twoDigit = `\\b([${digits[0]}-${digits[9]}]{1,2})\\b`;
|
|
359
|
+
const threeDigit = `\\b([${digits[0]}-${digits[9]}]{1,3})\\b`;
|
|
360
|
+
const fourDigit = `\\b([${digits[0]}-${digits[9]}]{1,4})\\b`;
|
|
361
|
+
let hourCycle = 'h12';
|
|
362
|
+
let _bUseUTC = bUseUTC;
|
|
363
|
+
let _setFullYear = false;
|
|
364
|
+
const isSeparator = str => str.length === 1 && ':-/.'.includes(str);
|
|
365
|
+
const monthNumber = str => getNumber(str) - 1;
|
|
366
|
+
const getNumber = str => str.split('').reduce((total, digit) => (total * 10) + digits.indexOf(digit), 0);
|
|
367
|
+
const yearNumber = templateDigits => str => {
|
|
368
|
+
let year = getNumber(str);
|
|
369
|
+
year = year < 100 && templateDigits === 2 ? year + 2000 : year;
|
|
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') {
|
|
390
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') {
|
|
438
|
+
_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
|
+
}
|
|
391
455
|
}
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
456
|
+
}
|
|
457
|
+
const dateObj = {year: 1972, month: 0, day: 1, hour: 0, minute: 0, second: 0, fractionalSecondDigits: 0};
|
|
458
|
+
match.slice(1).forEach((m, index) => {
|
|
459
|
+
const [element, func] = lookups[index];
|
|
460
|
+
dateObj[element] = func(m, dateObj);
|
|
461
|
+
});
|
|
462
|
+
if (hourCycle === 'h24' && dateObj.hour === 24) dateObj.hour = 0;
|
|
463
|
+
if (hourCycle === 'h12' && dateObj.hour === 12) dateObj.hour = 0;
|
|
464
|
+
if (_bUseUTC) {
|
|
465
|
+
const utcDate = new Date(Date.UTC(
|
|
466
|
+
dateObj.year,
|
|
467
|
+
dateObj.month,
|
|
468
|
+
dateObj.day,
|
|
469
|
+
dateObj.hour,
|
|
470
|
+
dateObj.minute,
|
|
471
|
+
dateObj.second,
|
|
472
|
+
dateObj.fractionalSecondDigits,
|
|
473
|
+
));
|
|
474
|
+
if (_setFullYear) {
|
|
475
|
+
utcDate.setUTCFullYear(dateObj.year);
|
|
411
476
|
}
|
|
412
|
-
|
|
413
|
-
_bUseUTC = false;
|
|
414
|
-
hourCycle = value;
|
|
415
|
-
} else if (option === 'x-timeZoneName') {
|
|
416
|
-
_bUseUTC = false;
|
|
417
|
-
regexParts.push('(?:GMT|UTC|Z)?([+\\-−0-9]{0,3}:?[0-9]{0,2})');
|
|
418
|
-
lookups.push([option, (v, obj) => {
|
|
419
|
-
_bUseUTC = true;
|
|
420
|
-
if (!v) return;
|
|
421
|
-
const timeParts = v.replace(/−/, '-').match(/([+\-\d]{2,3}):?(\d{0,2})/);
|
|
422
|
-
const hours = timeParts[1] * 1;
|
|
423
|
-
obj.hour -= hours;
|
|
424
|
-
const mins = timeParts.length > 2 ? timeParts[2] * 1 : 0;
|
|
425
|
-
obj.minute -= (hours < 0) ? - mins : mins;
|
|
426
|
-
}]);
|
|
427
|
-
} else if (option !== 'timeZoneName') {
|
|
428
|
-
_bUseUTC = false;
|
|
429
|
-
regexParts.push('.+?');
|
|
477
|
+
return utcDate;
|
|
430
478
|
}
|
|
431
|
-
|
|
432
|
-
}, []);
|
|
433
|
-
const regex = new RegExp(regexParts.join(''));
|
|
434
|
-
const match = dateString.match(regex);
|
|
435
|
-
if (match === null) return dateString;
|
|
436
|
-
const dateObj = {year: 1972, month: 0, day: 1, hour: 0, minute: 0, second: 0, fractionalSecondDigits: 0};
|
|
437
|
-
match.slice(1).forEach((m, index) => {
|
|
438
|
-
const [element, func] = lookups[index];
|
|
439
|
-
dateObj[element] = func(m, dateObj);
|
|
440
|
-
});
|
|
441
|
-
if (hourCycle === 'h24' && dateObj.hour === 24) dateObj.hour = 0;
|
|
442
|
-
if (hourCycle === 'h12' && dateObj.hour === 12) dateObj.hour = 0;
|
|
443
|
-
if (_bUseUTC) {
|
|
444
|
-
const utcDate = new Date(Date.UTC(
|
|
479
|
+
const jsDate = new Date(
|
|
445
480
|
dateObj.year,
|
|
446
481
|
dateObj.month,
|
|
447
482
|
dateObj.day,
|
|
@@ -449,25 +484,14 @@ function parseDate(dateString, language, skeleton, timeZone, bUseUTC = false) {
|
|
|
449
484
|
dateObj.minute,
|
|
450
485
|
dateObj.second,
|
|
451
486
|
dateObj.fractionalSecondDigits,
|
|
452
|
-
)
|
|
487
|
+
);
|
|
453
488
|
if (_setFullYear) {
|
|
454
|
-
|
|
489
|
+
jsDate.setFullYear(dateObj.year);
|
|
455
490
|
}
|
|
456
|
-
return
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
dateObj.year,
|
|
460
|
-
dateObj.month,
|
|
461
|
-
dateObj.day,
|
|
462
|
-
dateObj.hour,
|
|
463
|
-
dateObj.minute,
|
|
464
|
-
dateObj.second,
|
|
465
|
-
dateObj.fractionalSecondDigits,
|
|
466
|
-
);
|
|
467
|
-
if (_setFullYear) {
|
|
468
|
-
jsDate.setFullYear(dateObj.year);
|
|
491
|
+
return timeZone == null ? jsDate : adjustTimeZone(jsDate, timeZone);
|
|
492
|
+
} catch (error) {
|
|
493
|
+
return null;
|
|
469
494
|
}
|
|
470
|
-
return timeZone == null ? jsDate : adjustTimeZone(jsDate, timeZone);
|
|
471
495
|
}
|
|
472
496
|
function parseDefaultDate(dateString, language, bUseUTC) {
|
|
473
497
|
return parseDate(dateString, language, 'yyyy-MM-dd', null, bUseUTC);
|
package/lib/date/DateParser.js
CHANGED
|
@@ -377,152 +377,182 @@ 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
|
-
|
|
380
|
+
try {
|
|
381
|
+
// start by getting all the localized parts of a date/time picture:
|
|
382
|
+
// digits, calendar name
|
|
383
|
+
if (skeleton.startsWith('date|')) {
|
|
384
|
+
skeleton = skeleton.split('|')[1];
|
|
385
|
+
}
|
|
385
386
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
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
|
|
396
397
|
|
|
397
|
-
|
|
398
|
+
const isSeparator = str => str.length === 1 && ':-/.'.includes(str);
|
|
398
399
|
|
|
399
|
-
|
|
400
|
+
const monthNumber = str => getNumber(str) - 1;
|
|
400
401
|
|
|
401
|
-
|
|
402
|
+
const getNumber = str => str.split('').reduce((total, digit) => total * 10 + digits.indexOf(digit), 0);
|
|
402
403
|
|
|
403
|
-
|
|
404
|
-
|
|
404
|
+
const yearNumber = templateDigits => str => {
|
|
405
|
+
let year = getNumber(str); //todo: align with AF
|
|
405
406
|
|
|
406
|
-
|
|
407
|
-
|
|
407
|
+
year = year < 100 && templateDigits === 2 ? year + 2000 : year;
|
|
408
|
+
if (calendar === 'islamic') year = Math.ceil(year * 0.97 + 622);
|
|
408
409
|
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
410
|
+
if (templateDigits > 2 && year < 100) {
|
|
411
|
+
_setFullYear = true;
|
|
412
|
+
}
|
|
412
413
|
|
|
413
|
-
|
|
414
|
-
|
|
414
|
+
return year;
|
|
415
|
+
};
|
|
416
|
+
|
|
417
|
+
const monthLookup = list => month => list.indexOf(month);
|
|
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
|
+
}
|
|
415
453
|
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
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
|
-
if (isSeparator(value)) regexParts.push(`[^${digits[0]}-${digits[9]}]`);else 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') {
|
|
454
|
+
regexParts.push(twoDigit);
|
|
455
|
+
lookups.push([option, getNumber]);
|
|
456
|
+
} else if (option === 'fractionalSecondDigits') {
|
|
439
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);
|
|
470
|
+
|
|
471
|
+
if (dayPeriod) {
|
|
472
|
+
regexParts.push(dayPeriod.regex);
|
|
473
|
+
lookups.push(['hour', dayPeriod.fn]);
|
|
474
|
+
} // Any other part that we don't need, we'll just add a non-greedy consumption
|
|
475
|
+
|
|
476
|
+
} else if (option === 'hourCycle') {
|
|
477
|
+
_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('.+?');
|
|
440
497
|
}
|
|
441
498
|
|
|
442
|
-
regexParts
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
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
|
-
}
|
|
499
|
+
return regexParts;
|
|
500
|
+
}, []);
|
|
501
|
+
const regex = new RegExp(regexParts.join(''));
|
|
502
|
+
const match = dateString.match(regex);
|
|
503
|
+
|
|
504
|
+
if (match === null) {
|
|
505
|
+
if (skeleton.toLowerCase() === 'yyyy-MM-dd'.toLowerCase()) {
|
|
506
|
+
return null;
|
|
507
|
+
} else {
|
|
508
|
+
// Try parsing with 'yyyy-MM-dd' skeleton
|
|
509
|
+
const parsedDate = parseDate(dateString, language, 'yyyy-MM-dd', timeZone, bUseUTC);
|
|
510
|
+
|
|
511
|
+
if (parsedDate instanceof Date) {
|
|
512
|
+
return parsedDate;
|
|
513
|
+
} else {
|
|
514
|
+
return null;
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
} // now loop through all the matched pieces and build up an object we'll use to create a Date object
|
|
486
518
|
|
|
487
|
-
return regexParts;
|
|
488
|
-
}, []);
|
|
489
|
-
const regex = new RegExp(regexParts.join(''));
|
|
490
|
-
const match = dateString.match(regex);
|
|
491
|
-
if (match === null) return dateString; // 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;
|
|
508
519
|
|
|
509
|
-
|
|
510
|
-
|
|
520
|
+
const dateObj = {
|
|
521
|
+
year: 1972,
|
|
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
|
+
}
|
|
511
542
|
|
|
512
|
-
|
|
513
|
-
utcDate.setUTCFullYear(dateObj.year);
|
|
543
|
+
return utcDate;
|
|
514
544
|
}
|
|
515
545
|
|
|
516
|
-
|
|
517
|
-
}
|
|
546
|
+
const jsDate = new Date(dateObj.year, dateObj.month, dateObj.day, dateObj.hour, dateObj.minute, dateObj.second, dateObj.fractionalSecondDigits);
|
|
518
547
|
|
|
519
|
-
|
|
548
|
+
if (_setFullYear) {
|
|
549
|
+
jsDate.setFullYear(dateObj.year);
|
|
550
|
+
}
|
|
520
551
|
|
|
521
|
-
|
|
522
|
-
|
|
552
|
+
return timeZone == null ? jsDate : adjustTimeZone(jsDate, timeZone);
|
|
553
|
+
} catch (error) {
|
|
554
|
+
return null;
|
|
523
555
|
}
|
|
524
|
-
|
|
525
|
-
return timeZone == null ? jsDate : adjustTimeZone(jsDate, timeZone);
|
|
526
556
|
}
|
|
527
557
|
|
|
528
558
|
function parseDefaultDate(dateString, language, bUseUTC) {
|