Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Fix zone parsing in potentially ambiguous cases (fixes #1336) #1347

Merged
merged 3 commits into from

2 participants

@pimterry

This patch changes zone() and parseZone(), so that zone(tzString) now parses for timezones from the right, and parseZone() now uses _tmz data as specified by the format string, if available (and continues to fallback to zone(originalInput) if not).

@ichernev
Owner

Can you please make sure that both cases of the parseZone are hit (from _tzm and from last tz-looking thing in the string) -- and put a comment in the test case. Also global regexes tend to remember where you matched them last. Is that why you switches the rexexp.exec(string) to string.match(regex) (RegExp MDN lastIndex property).

@pimterry

I've added a test covering that in more detail, and rebased this branch back up to date. Does that look better?

And yes, the switch from regex.exec to string.match is entirely to get around the lastIndex state. Unlike regex.exec, string.match doesn't track any extra state, so the results are always independent and consistent; it gives you back the full array of all the possible matches every time.

@ichernev
Owner

Looks great! Thank you very much!

@ichernev ichernev merged commit bcec595 into from
@pimterry pimterry deleted the branch
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
Showing with 31 additions and 6 deletions.
  1. +10 −6 moment.js
  2. +21 −0 test/moment/zones.js
View
16 moment.js
@@ -49,7 +49,7 @@
parseTokenOneToSixDigits = /[+\-]?\d{1,6}/, // -999,999 - 999,999
parseTokenDigits = /\d+/, // nonzero number of digits
parseTokenWord = /[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i, // any word (or two) characters or numbers including two/three word month in arabic.
- parseTokenTimezone = /Z|[\+\-]\d\d:?\d\d/i, // +00:00 -00:00 +0000 -0000 or Z
+ parseTokenTimezone = /Z|[\+\-]\d\d:?\d\d/gi, // +00:00 -00:00 +0000 -0000 or Z
parseTokenT = /T/i, // T (ISO separator)
parseTokenTimestampMs = /[\+\-]?\d+(\.\d{1,3})?/, // 123456789 123456789.123
@@ -986,8 +986,10 @@
}
function timezoneMinutesFromString(string) {
- var tzchunk = (parseTokenTimezone.exec(string) || [])[0],
- parts = (tzchunk + '').match(parseTimezoneChunker) || ['-', 0, 0],
+ string = string || "";
+ var possibleTzMatches = (string.match(parseTokenTimezone) || []),
+ tzChunk = possibleTzMatches[possibleTzMatches.length - 1] || [],
+ parts = (tzChunk + '').match(parseTimezoneChunker) || ['-', 0, 0],
minutes = +(parts[1] * 60) + toInt(parts[2]);
return parts[0] === '+' ? -minutes : minutes;
@@ -1235,7 +1237,7 @@
for (i = 0; i < tokens.length; i++) {
token = tokens[i];
- parsedInput = (getParseRegexForToken(token, config).exec(string) || [])[0];
+ parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0];
if (parsedInput) {
skipped = string.substr(0, string.indexOf(parsedInput));
if (skipped.length > 0) {
@@ -1353,7 +1355,7 @@
break;
}
}
- if (parseTokenTimezone.exec(string)) {
+ if (string.match(parseTokenTimezone)) {
config._f += "Z";
}
makeDateFromStringAndFormat(config);
@@ -2015,7 +2017,9 @@
},
parseZone : function () {
- if (typeof this._i === 'string') {
+ if (this._tzm) {
+ this.zone(this._tzm);
+ } else if (typeof this._i === 'string') {
this.zone(this._i);
}
return this;
View
21 test/moment/zones.js
@@ -62,6 +62,9 @@ exports.zones = {
zone.zone("2013-03-07T07:00:00+0100");
test.equal(zone.zone(), -60, "set the zone with a string that uses the +0000 syntax");
+ zone.zone("03-07-2013T07:00:00-08:00");
+ test.equal(zone.zone(), 480, "set the zone with a string with a non-ISO 8601 date");
+
test.done();
},
@@ -478,6 +481,24 @@ exports.zones = {
test.equal(m.hours(), 0);
test.done();
},
+
+ "parse zone with a timezone from the format string" : function (test) {
+ test.expect(1);
+
+ var m = moment("11-12-2013 -0400 +1100", "DD-MM-YYYY ZZ #####").parseZone();
+
+ test.equal(m.zone(), 4 * 60);
+ test.done();
+ },
+
+ "parse zone without a timezone included in the format string" : function (test) {
+ test.expect(1);
+
+ var m = moment("11-12-2013 -0400 +1100", "DD-MM-YYYY").parseZone();
+
+ test.equal(m.zone(), -11 * 60);
+ test.done();
+ },
"timezone format" : function (test) {
test.equal(moment().zone(-60).format('ZZ'), "+0100", "-60 -> +0100");
Something went wrong with that request. Please try again.