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

Commit

Permalink
Add support for non-ASCII spaces in DateTimeParse.
Browse files Browse the repository at this point in the history
RELNOTES: Add support for non-ASCII spaces in DateTimeParse.

PiperOrigin-RevId: 500734816
Change-Id: I6f26204e36da56383e6dcacf995ff2dcb187c976
  • Loading branch information
Closure Team authored and copybara-github committed Jan 9, 2023
1 parent 2800dca commit e25a09a
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 3 deletions.
15 changes: 12 additions & 3 deletions closure/goog/i18n/datetimeparse.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,14 @@ const DayPeriods = goog.module.get('goog.i18n.DayPeriods');
*/
goog.i18n.DateTimeParse.PatternPart;

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

/**
* Construct a DateTimeParse based on current locale.
Expand Down Expand Up @@ -937,8 +945,8 @@ goog.i18n.DateTimeParse.prototype.subParseLiteral_ = function(
'use strict';
// A run of white space in the pattern matches a run
// of white space in the input text.
if (part.text.charAt(0) == ' ') {
// Advance over run in input text
const white_space_match = part.text.match(horizontalWhiteSpacePrefixRegex);
if (white_space_match != null) {
const start = pos[0];
this.skipSpace_(text, pos);

Expand Down Expand Up @@ -970,7 +978,8 @@ goog.i18n.DateTimeParse.prototype.subParseLiteral_ = function(
*/
goog.i18n.DateTimeParse.prototype.skipSpace_ = function(text, pos) {
'use strict';
const m = text.substring(pos[0]).match(/^\s+/);
// Skips Unicode spaces in addition to ASCII space.
const m = text.substring(pos[0]).match(skipWhiteSpacePrefixRegex);
if (m) {
pos[0] += m[0].length;
}
Expand Down
77 changes: 77 additions & 0 deletions closure/goog/i18n/datetimeparse_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -412,9 +412,15 @@ testSuite({
assertParseFails(parser, '5:4');
assertParseFails(parser, '5:44');
assertParsedTimeEquals(5, 44, 0, 0, parser, '5:44 ');
assertParsedTimeEquals(5, 44, 0, 0, parser, '5:44 ');
assertParsedTimeEquals(5, 44, 0, 0, parser, '5:44 p', {partial: 5});
assertParsedTimeEquals(
5, 44, 0, 0, parser, '5:44\u202f\u202fp', {partial: 6});
assertParsedTimeEquals(17, 44, 0, 0, parser, '5:44 pm');
assertParsedTimeEquals(17, 44, 0, 0, parser, '5:44\u202fpm');
assertParsedTimeEquals(5, 44, 0, 0, parser, '5:44 ym', {partial: 5});
assertParsedTimeEquals(
5, 44, 0, 0, parser, '5:44\u1680\u00a0\t\u0020 ym', {partial: 9});

parser = new DateTimeParse('mm:ss');
const date = new Date(0);
Expand Down Expand Up @@ -973,4 +979,75 @@ testSuite({
assertTrue(parsedOK > 0);
assertTimeEquals(17, 0, 0, 0, newDate);
},

testNonAsciiSpaces() {
const time_part = '3:26';
const white_spaces = [
' ',
'\t',
'\xA0',
'\u1680',
'\u180e',
'\u2000',
'\u2001',
'\u2002',
'\u2003',
'\u2004',
'\u2005',
'\u2006',
'\u2007',
'\u2008',
'\u2009',
'\u200a',
'\u202f',
'\u205f',
'\u3000',
' ', // Multiple spaces
'\u202f\u00a0\u200a', // Multiple non-ASCII spaces
];

let parser = new DateTimeParse(DateTimeFormat.Format.SHORT_TIME);
let newDate = new Date(0);
for (let index = 0; index < white_spaces.length; index++) {
let input_string = time_part + white_spaces[index] + 'AM';
let parsedOK = parser.parse(input_string, newDate);
assertTrue(
'Fails on index ' + index + ' >' + input_string + '<: ' + parsedOK,
parsedOK > 0);
assertTimeEquals(3, 26, 0, 0, newDate);
}
},

testNonAsciiWithPatterns() {
// Cloned from
// google3/alkali/apps/twitteralerts/client/app/new_alert/parse_twitter.ts
const dateFormats = [
'h:mm a - d MMM yyyy',
'h:mm a · d MMM yyyy',
'h:mm a · d MMM, yyyy',
'h:mm a · MMM d, yyyy',
];

const twitter_dates = [
'4:44\u202fAM 19 Jan 2018',
'4:44 AM - 19 Jan 2018',
'4:44 AM · 19 Jan 2018',
'4:44 AM · 19 Jan, 2018',
];
const date = new Date();
for (let i = 0; i < dateFormats.length; i++) {
for (let j = 0; j < twitter_dates.length; j++) {
let text = twitter_dates[j];
const parser = new DateTimeParse(dateFormats[i]);
const parseDate = parser.parse(text, date, {validate: true});
if (parseDate !== 0) {
// DateTimeParse uses current seconds since they are not provided in
// the input string. We prefer to have stable output, so we set
// seconds to 0.
assertParsedDateEquals(2018, 0, 19, parser, text);
}
}
}
},

});

0 comments on commit e25a09a

Please sign in to comment.