Skip to content

Commit

Permalink
Fault-tolerant Date parsing for dashes
Browse files Browse the repository at this point in the history
Summary: This is addressing a gap between Hermes and V8 regarding date parsing, raised in facebook#796 . There is whitespace allowed between M D Y. However, we should also support allowing a dash to be present as the first character in those gaps.

Reviewed By: jpporto

Differential Revision: D40368889

fbshipit-source-id: 5a9529300a221609ebb5c59dc44c4cf97a153700
  • Loading branch information
Michael Anthony Leon authored and facebook-github-bot committed Oct 14, 2022
1 parent 030381f commit a26472f
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 6 deletions.
27 changes: 21 additions & 6 deletions lib/VM/JSLib/DateUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -901,7 +901,7 @@ static double parseESDate(StringView str) {

/// Reads the next \p len characters into `tok`,
/// but instead of consuming \p len chars, it consumes a single word
/// whatever how long it is (i.e. until a space is encountered).
/// whatever how long it is (i.e. until a space or dash is encountered).
/// e.g.
/// &str ="Garbage G MayG"
/// scanStrAndSkipWord(3); consumeSpaces(); // &str="G MayG", &tok="Gar"
Expand All @@ -913,7 +913,7 @@ static double parseESDate(StringView str) {
if (it + len > str.end())
return false;
tok = str.slice(it, it + len);
while (it != str.end() && !std::isspace(*it))
while (it != str.end() && !std::isspace(*it) && *it != '-')
it++;
return true;
};
Expand All @@ -931,6 +931,21 @@ static double parseESDate(StringView str) {
++it;
};

/// Only one dash is ever allowed, and the dash must come first.
/// There is no limit to the number of spaces.
/// This is in line with V8's behavior.
auto consumeSpacesOrDash = [&]() {
auto first = true;
while (it != str.end()) {
if (std::isspace(*it) || (first && *it == '-')) {
++it;
} else {
return;
}
first = false;
}
};

// Weekday
if (!scanStr(3))
return nan;
Expand Down Expand Up @@ -964,7 +979,7 @@ static double parseESDate(StringView str) {
// Day
scanInt(it, end, d);
// Month
consumeSpaces();
consumeSpacesOrDash();
// e.g. `Janwhatever` will get read as `Jan`
if (!scanStrAndSkipWord(3))
return nan;
Expand All @@ -980,7 +995,7 @@ static double parseESDate(StringView str) {
// `tok` is now set to the Month candidate.
if (tokIsMonth()) {
// Day
consumeSpaces();
consumeSpacesOrDash();
if (!scanInt(it, end, d))
return nan;
break;
Expand All @@ -993,12 +1008,12 @@ static double parseESDate(StringView str) {
}

// Year
consumeSpaces();
consumeSpacesOrDash();
if (!scanInt(it, end, y))
return nan;

// Hour:minute:second.
consumeSpaces();
consumeSpacesOrDash();

if (it != end) {
if (!scanInt(it, end, h))
Expand Down
19 changes: 19 additions & 0 deletions test/hermes/date-constructor.js
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,25 @@ print(Date.parse('Tue May 05 2020 00:00:00'.padEnd(60))); // trailing spaces.
print(Date.parse('Tue May 05 2020'.padEnd(60)));
// CHECK-NEXT: 1588662000000

// Fault tolerance on dashes
print(Date.parse("Friday, 02 Aug 2019 07:14:03 UTC"));
// CHECK-NEXT: 1564730043000
print(Date.parse("Friday, 02-Aug-2019-07:14:03 UTC"));
// CHECK-NEXT: 1564730043000
print(Date.parse("Friday, 02- Aug-2019-07:14:03 UTC"));
// CHECK-NEXT: 1564730043000
print(Date.parse("Friday, 02- Aug- 2019- 07:14:03 UTC"));
// CHECK-NEXT: 1564730043000
// Invalid use of dashes
print(Date.parse("Friday, 02 - Aug-2019-07:14:03 UTC"));
// CHECK-NEXT: NaN
print(Date.parse("Friday, 02-Aug -2019-07:14:03 UTC"));
// CHECK-NEXT: NaN
print(Date.parse("Friday, 02-Aug-2019- -07:14:03 UTC"));
// CHECK-NEXT: NaN
print(Date.parse("Friday, 02-Aug-2019 -07:14:03 UTC"));
// CHECK-NEXT: NaN

// Quick check that getters work; internal functions are unit tested instead.
print('getters');
// CHECK-LABEL: getters
Expand Down

0 comments on commit a26472f

Please sign in to comment.