Skip to content
This repository was archived by the owner on Aug 1, 2024. It is now read-only.

Commit 6b26bd2

Browse files
Closure Teamcopybara-github
Closure Team
authored andcommittedMar 6, 2023
Update DateTimeParse to handle non-ASCII spaces in date/time patterns
RELNOTES: Update DateTimeParse to handle non-ASCII spaces in date/time patterns PiperOrigin-RevId: 513943273 Change-Id: I78180ccf32e149bc0a31a832d9f24ee552ae9165
1 parent 6e384c9 commit 6b26bd2

File tree

2 files changed

+175
-3
lines changed

2 files changed

+175
-3
lines changed
 

‎closure/goog/i18n/datetimeparse.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -237,8 +237,8 @@ goog.i18n.DateTimeParse.prototype.applyPattern_ = function(pattern) {
237237
for (let i = 0; i < pattern.length; i++) {
238238
const ch = pattern.charAt(i);
239239

240-
// handle space, add literal part (if exist), and add space part
241-
if (ch == ' ') {
240+
// handle whitespace, add literal part (if exist), and add space part
241+
if (horizontalWhiteSpacePrefixRegex.test(ch)) {
242242
if (buf.length > 0) {
243243
this.patternParts_.push(
244244
{text: buf, count: 0, abutStart: false, numeric: false});

‎closure/goog/i18n/datetimeparse_test.js

+173-1
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,14 @@ const DateLike = goog.require('goog.date.DateLike');
1818
const DateTimeFormat = goog.require('goog.i18n.DateTimeFormat');
1919
const DateTimeParse = goog.require('goog.i18n.DateTimeParse');
2020
/** @suppress {extraRequire} */
21-
const DateTimeSymbols = goog.require('goog.i18n.DateTimeSymbols');
21+
const DateTimePatterns_ru = goog.require('goog.i18n.DateTimePatterns_ru');
2222
const DateTimeSymbols_ca = goog.require('goog.i18n.DateTimeSymbols_ca');
2323
const DateTimeSymbols_en = goog.require('goog.i18n.DateTimeSymbols_en');
2424
const DateTimeSymbols_fa = goog.require('goog.i18n.DateTimeSymbols_fa');
2525
const DateTimeSymbols_fr = goog.require('goog.i18n.DateTimeSymbols_fr');
2626
const DateTimeSymbols_ko = goog.require('goog.i18n.DateTimeSymbols_ko');
2727
const DateTimeSymbols_pl = goog.require('goog.i18n.DateTimeSymbols_pl');
28+
const DateTimeSymbols_ru = goog.require('goog.i18n.DateTimeSymbols_ru');
2829
const DateTimeSymbols_zh = goog.require('goog.i18n.DateTimeSymbols_zh');
2930
const DateTimeSymbols_zh_TW = goog.require('goog.i18n.DateTimeSymbols_zh_TW');
3031
const GoogDate = goog.require('goog.date.Date');
@@ -429,6 +430,126 @@ testSuite({
429430
assertEquals(0, date.getSeconds());
430431
},
431432

433+
testTimeParsing_partial_nonBreakableSpace() {
434+
const parser = new DateTimeParse('h:mm\u00a0a');
435+
assertParseFails(parser, '5');
436+
assertParsedTimeEquals(5, 44, 0, 0, parser, '5:44\u00a0');
437+
assertParsedTimeEquals(5, 44, 0, 0, parser, '5:44\u00a0p', {partial: 5});
438+
assertParsedTimeEquals(17, 44, 0, 0, parser, '5:44\u00a0pm');
439+
},
440+
441+
testTimeParsing_partial_narrowNonBreakableSpace() {
442+
const parser = new DateTimeParse('h:mm\u202fa');
443+
assertParseFails(parser, '5');
444+
assertParsedTimeEquals(5, 44, 0, 0, parser, '5:44\u202f');
445+
assertParsedTimeEquals(5, 44, 0, 0, parser, '5:44\u202fp', {partial: 5});
446+
assertParsedTimeEquals(17, 44, 0, 0, parser, '5:44\u202fpm');
447+
},
448+
449+
testTimeParsing_partial_emQuad() {
450+
const parser = new DateTimeParse('h:mm\u2001a');
451+
assertParseFails(parser, '5');
452+
assertParsedTimeEquals(5, 44, 0, 0, parser, '5:44\u2001');
453+
assertParsedTimeEquals(5, 44, 0, 0, parser, '5:44\u2001p', {partial: 5});
454+
assertParsedTimeEquals(17, 44, 0, 0, parser, '5:44\u2001pm');
455+
},
456+
457+
testTimeParsing_partial_enQuad() {
458+
const parser = new DateTimeParse('h:mm\u2000a');
459+
assertParseFails(parser, '5');
460+
assertParsedTimeEquals(5, 44, 0, 0, parser, '5:44\u2000');
461+
assertParsedTimeEquals(5, 44, 0, 0, parser, '5:44\u2000p', {partial: 5});
462+
assertParsedTimeEquals(17, 44, 0, 0, parser, '5:44\u2000pm');
463+
},
464+
465+
testTimeParsing_partial_emSpace() {
466+
const parser = new DateTimeParse('h:mm\u2003a');
467+
assertParseFails(parser, '5');
468+
assertParsedTimeEquals(5, 44, 0, 0, parser, '5:44\u2003');
469+
assertParsedTimeEquals(5, 44, 0, 0, parser, '5:44\u2003p', {partial: 5});
470+
assertParsedTimeEquals(17, 44, 0, 0, parser, '5:44\u2003pm');
471+
},
472+
473+
testTimeParsing_partial_enSpace() {
474+
const parser = new DateTimeParse('h:mm\u2002a');
475+
assertParseFails(parser, '5');
476+
assertParsedTimeEquals(5, 44, 0, 0, parser, '5:44\u2002');
477+
assertParsedTimeEquals(5, 44, 0, 0, parser, '5:44\u2002p', {partial: 5});
478+
assertParsedTimeEquals(17, 44, 0, 0, parser, '5:44\u2002pm');
479+
},
480+
481+
testTimeParsing_partial_thickSpace() {
482+
const parser = new DateTimeParse('h:mm\u2004a');
483+
assertParseFails(parser, '5');
484+
assertParsedTimeEquals(5, 44, 0, 0, parser, '5:44\u2004');
485+
assertParsedTimeEquals(5, 44, 0, 0, parser, '5:44\u2004p', {partial: 5});
486+
assertParsedTimeEquals(17, 44, 0, 0, parser, '5:44\u2004pm');
487+
},
488+
489+
testTimeParsing_partial_midSpace() {
490+
const parser = new DateTimeParse('h:mm\u2005a');
491+
assertParseFails(parser, '5');
492+
assertParsedTimeEquals(5, 44, 0, 0, parser, '5:44\u2005');
493+
assertParsedTimeEquals(5, 44, 0, 0, parser, '5:44\u2005p', {partial: 5});
494+
assertParsedTimeEquals(17, 44, 0, 0, parser, '5:44\u2005pm');
495+
},
496+
497+
testTimeParsing_partial_thinSpace() {
498+
const parser = new DateTimeParse('h:mm\u2006a');
499+
assertParseFails(parser, '5');
500+
assertParsedTimeEquals(5, 44, 0, 0, parser, '5:44\u2006');
501+
assertParsedTimeEquals(5, 44, 0, 0, parser, '5:44\u2006p', {partial: 5});
502+
assertParsedTimeEquals(17, 44, 0, 0, parser, '5:44\u2006pm');
503+
},
504+
505+
testTimeParsing_partial_thinSpace2() {
506+
const parser = new DateTimeParse('h:mm\u2009a');
507+
assertParseFails(parser, '5');
508+
assertParsedTimeEquals(5, 44, 0, 0, parser, '5:44\u2009');
509+
assertParsedTimeEquals(5, 44, 0, 0, parser, '5:44\u2009p', {partial: 5});
510+
assertParsedTimeEquals(17, 44, 0, 0, parser, '5:44\u2009pm');
511+
},
512+
513+
testTimeParsing_partial_figureSpace() {
514+
const parser = new DateTimeParse('h:mm\u2007a');
515+
assertParseFails(parser, '5');
516+
assertParsedTimeEquals(5, 44, 0, 0, parser, '5:44\u2007');
517+
assertParsedTimeEquals(5, 44, 0, 0, parser, '5:44\u2007p', {partial: 5});
518+
assertParsedTimeEquals(17, 44, 0, 0, parser, '5:44\u2007pm');
519+
},
520+
521+
testTimeParsing_partial_punctuationSpace() {
522+
const parser = new DateTimeParse('h:mm\u2008a');
523+
assertParseFails(parser, '5');
524+
assertParsedTimeEquals(5, 44, 0, 0, parser, '5:44\u2008');
525+
assertParsedTimeEquals(5, 44, 0, 0, parser, '5:44\u2008p', {partial: 5});
526+
assertParsedTimeEquals(17, 44, 0, 0, parser, '5:44\u2008pm');
527+
},
528+
529+
testTimeParsing_partial_hairSpace() {
530+
const parser = new DateTimeParse('h:mm\u200aa');
531+
assertParseFails(parser, '5');
532+
assertParsedTimeEquals(5, 44, 0, 0, parser, '5:44\u200a');
533+
assertParsedTimeEquals(5, 44, 0, 0, parser, '5:44\u200ap', {partial: 5});
534+
assertParsedTimeEquals(17, 44, 0, 0, parser, '5:44\u200apm');
535+
},
536+
537+
testTimeParsing_partial_mediumMatematicalSpace() {
538+
const parser = new DateTimeParse('h:mm\u205fa');
539+
assertParseFails(parser, '5');
540+
assertParsedTimeEquals(5, 44, 0, 0, parser, '5:44\u205f');
541+
assertParsedTimeEquals(5, 44, 0, 0, parser, '5:44\u205fp', {partial: 5});
542+
assertParsedTimeEquals(17, 44, 0, 0, parser, '5:44\u205fpm');
543+
},
544+
545+
testTimeParsing_partial_ideographicSpace() {
546+
const parser = new DateTimeParse('h:mm\u3000a');
547+
assertParseFails(parser, '5');
548+
assertParsedTimeEquals(5, 44, 0, 0, parser, '5:44\u3000');
549+
assertParsedTimeEquals(5, 44, 0, 0, parser, '5:44\u3000p', {partial: 5});
550+
assertParsedTimeEquals(17, 44, 0, 0, parser, '5:44\u3000pm');
551+
},
552+
432553
testTimeParsing_overflow() {
433554
const parser = new DateTimeParse('H:mm');
434555

@@ -1050,4 +1171,55 @@ testSuite({
10501171
}
10511172
},
10521173

1174+
testRussianParseWithNnbs() {
1175+
// Check that dates
1176+
1177+
replacer.replace(goog.i18n, DATETIMESYMBOLS, DateTimeSymbols_ru);
1178+
// Checking parse of output for non-ASCII whitespace characters.
1179+
const test_cases = [
1180+
'28 июн. 2012 г.', // ASCII Space
1181+
'28 июн. 2012 г.', // Narrow non-breaking space
1182+
'28 июн. 2012\tг.', // Horizontal tab
1183+
'28 июн. 2012\u3000г.', // Ideographic space
1184+
'чт, 28 июн. 2012 г.',
1185+
];
1186+
1187+
// From datetimepatterns for Russian.
1188+
const format_patterns = [
1189+
DateTimePatterns_ru.MONTH_DAY_YEAR_MEDIUM,
1190+
DateTimePatterns_ru.MONTH_DAY_YEAR_MEDIUM,
1191+
DateTimePatterns_ru.MONTH_DAY_YEAR_MEDIUM,
1192+
DateTimePatterns_ru.MONTH_DAY_YEAR_MEDIUM,
1193+
DateTimePatterns_ru.WEEKDAY_MONTH_DAY_YEAR_MEDIUM,
1194+
];
1195+
1196+
const output_date = new Date();
1197+
for (let index = 0; index < test_cases.length; index++) {
1198+
const string_date = test_cases[index];
1199+
const pattern = format_patterns[index];
1200+
1201+
const parser = new DateTimeParse(pattern);
1202+
const parseDate =
1203+
parser.parse(string_date, output_date, {validate: true});
1204+
if (parseDate !== 0) {
1205+
assertParsedDateEquals(2012, 5, 28, parser, string_date);
1206+
}
1207+
}
1208+
},
1209+
1210+
testBulgarian() {
1211+
const short_time_string = '20:29 ч.';
1212+
1213+
const short_time_bg_pattern = 'H:mm \'ч\'.';
1214+
const parser = new DateTimeParse(short_time_bg_pattern);
1215+
const output_date = new Date();
1216+
const parseDate =
1217+
parser.parse(short_time_string, output_date, {validate: true});
1218+
if (parseDate !== 0) {
1219+
const hr = output_date.getHours();
1220+
const min = output_date.getMinutes();
1221+
assertEquals(20, hr);
1222+
assertEquals(29, min);
1223+
}
1224+
}
10531225
});

0 commit comments

Comments
 (0)
This repository has been archived.