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

Commit e25a09a

Browse files
Closure Teamcopybara-github
Closure Team
authored andcommitted
Add support for non-ASCII spaces in DateTimeParse.
RELNOTES: Add support for non-ASCII spaces in DateTimeParse. PiperOrigin-RevId: 500734816 Change-Id: I6f26204e36da56383e6dcacf995ff2dcb187c976
1 parent 2800dca commit e25a09a

File tree

2 files changed

+89
-3
lines changed

2 files changed

+89
-3
lines changed

closure/goog/i18n/datetimeparse.js

+12-3
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,14 @@ const DayPeriods = goog.module.get('goog.i18n.DayPeriods');
144144
*/
145145
goog.i18n.DateTimeParse.PatternPart;
146146

147+
// To match one white horizontal space character at start of string, including
148+
// non-ASCII.
149+
const horizontalWhiteSpacePrefixRegex =
150+
/^[ \t\xA0\u1680\u180e\u2000-\u200a\u202f\u205f\u3000]/;
151+
// Match one or more white space, including those covered by JavaScript's \s
152+
// match.
153+
const skipWhiteSpacePrefixRegex =
154+
/^[\s\xA0\u1680\u180e\u2000-\u200a\u202f\u205f\u3000]+/;
147155

148156
/**
149157
* Construct a DateTimeParse based on current locale.
@@ -937,8 +945,8 @@ goog.i18n.DateTimeParse.prototype.subParseLiteral_ = function(
937945
'use strict';
938946
// A run of white space in the pattern matches a run
939947
// of white space in the input text.
940-
if (part.text.charAt(0) == ' ') {
941-
// Advance over run in input text
948+
const white_space_match = part.text.match(horizontalWhiteSpacePrefixRegex);
949+
if (white_space_match != null) {
942950
const start = pos[0];
943951
this.skipSpace_(text, pos);
944952

@@ -970,7 +978,8 @@ goog.i18n.DateTimeParse.prototype.subParseLiteral_ = function(
970978
*/
971979
goog.i18n.DateTimeParse.prototype.skipSpace_ = function(text, pos) {
972980
'use strict';
973-
const m = text.substring(pos[0]).match(/^\s+/);
981+
// Skips Unicode spaces in addition to ASCII space.
982+
const m = text.substring(pos[0]).match(skipWhiteSpacePrefixRegex);
974983
if (m) {
975984
pos[0] += m[0].length;
976985
}

closure/goog/i18n/datetimeparse_test.js

+77
Original file line numberDiff line numberDiff line change
@@ -412,9 +412,15 @@ testSuite({
412412
assertParseFails(parser, '5:4');
413413
assertParseFails(parser, '5:44');
414414
assertParsedTimeEquals(5, 44, 0, 0, parser, '5:44 ');
415+
assertParsedTimeEquals(5, 44, 0, 0, parser, '5:44 ');
415416
assertParsedTimeEquals(5, 44, 0, 0, parser, '5:44 p', {partial: 5});
417+
assertParsedTimeEquals(
418+
5, 44, 0, 0, parser, '5:44\u202f\u202fp', {partial: 6});
416419
assertParsedTimeEquals(17, 44, 0, 0, parser, '5:44 pm');
420+
assertParsedTimeEquals(17, 44, 0, 0, parser, '5:44\u202fpm');
417421
assertParsedTimeEquals(5, 44, 0, 0, parser, '5:44 ym', {partial: 5});
422+
assertParsedTimeEquals(
423+
5, 44, 0, 0, parser, '5:44\u1680\u00a0\t\u0020 ym', {partial: 9});
418424

419425
parser = new DateTimeParse('mm:ss');
420426
const date = new Date(0);
@@ -973,4 +979,75 @@ testSuite({
973979
assertTrue(parsedOK > 0);
974980
assertTimeEquals(17, 0, 0, 0, newDate);
975981
},
982+
983+
testNonAsciiSpaces() {
984+
const time_part = '3:26';
985+
const white_spaces = [
986+
' ',
987+
'\t',
988+
'\xA0',
989+
'\u1680',
990+
'\u180e',
991+
'\u2000',
992+
'\u2001',
993+
'\u2002',
994+
'\u2003',
995+
'\u2004',
996+
'\u2005',
997+
'\u2006',
998+
'\u2007',
999+
'\u2008',
1000+
'\u2009',
1001+
'\u200a',
1002+
'\u202f',
1003+
'\u205f',
1004+
'\u3000',
1005+
' ', // Multiple spaces
1006+
'\u202f\u00a0\u200a', // Multiple non-ASCII spaces
1007+
];
1008+
1009+
let parser = new DateTimeParse(DateTimeFormat.Format.SHORT_TIME);
1010+
let newDate = new Date(0);
1011+
for (let index = 0; index < white_spaces.length; index++) {
1012+
let input_string = time_part + white_spaces[index] + 'AM';
1013+
let parsedOK = parser.parse(input_string, newDate);
1014+
assertTrue(
1015+
'Fails on index ' + index + ' >' + input_string + '<: ' + parsedOK,
1016+
parsedOK > 0);
1017+
assertTimeEquals(3, 26, 0, 0, newDate);
1018+
}
1019+
},
1020+
1021+
testNonAsciiWithPatterns() {
1022+
// Cloned from
1023+
// google3/alkali/apps/twitteralerts/client/app/new_alert/parse_twitter.ts
1024+
const dateFormats = [
1025+
'h:mm a - d MMM yyyy',
1026+
'h:mm a · d MMM yyyy',
1027+
'h:mm a · d MMM, yyyy',
1028+
'h:mm a · MMM d, yyyy',
1029+
];
1030+
1031+
const twitter_dates = [
1032+
'4:44\u202fAM 19 Jan 2018',
1033+
'4:44 AM - 19 Jan 2018',
1034+
'4:44 AM · 19 Jan 2018',
1035+
'4:44 AM · 19 Jan, 2018',
1036+
];
1037+
const date = new Date();
1038+
for (let i = 0; i < dateFormats.length; i++) {
1039+
for (let j = 0; j < twitter_dates.length; j++) {
1040+
let text = twitter_dates[j];
1041+
const parser = new DateTimeParse(dateFormats[i]);
1042+
const parseDate = parser.parse(text, date, {validate: true});
1043+
if (parseDate !== 0) {
1044+
// DateTimeParse uses current seconds since they are not provided in
1045+
// the input string. We prefer to have stable output, so we set
1046+
// seconds to 0.
1047+
assertParsedDateEquals(2018, 0, 19, parser, text);
1048+
}
1049+
}
1050+
}
1051+
},
1052+
9761053
});

0 commit comments

Comments
 (0)