-import { matchOffset } from '../parse/regex';
import { configFromStringAndFormat } from './from-string-and-format';
import { hooks } from '../utils/hooks';
import { deprecate } from '../utils/deprecate';
// iso 8601 regex
// 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00)
-var isoRegex = /^\s*((?:[+-]\d{6}|\d{4})-?(?:\d\d$|\d\d-?\d\d|W\d\d$|W\d\d-?\d|\d\d\d))(?:(T| )(\d\d(?::?\d\d(?::?\d\d(?::?[.,]\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/;
+var isoRegex = /^\s*((?:[+-]\d{6}|\d{4})-?(?:\d\d-?\d\d|W\d\d-?\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::?\d\d(?::?\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?/;
+
+var tzRegex = /Z|[+-]\d\d(?::?\d\d)?/;
var isoDates = [
- ['YYYYYY-MM-DD', /[+-]\d{6}-\d{2}-\d{2}/, true],
- ['YYYY-MM-DD', /\d{4}-\d{2}-\d{2}/, true],
- ['GGGG-[W]WW-E', /\d{4}-W\d{2}-\d/, true],
- ['GGGG-[W]WW', /\d{4}-W\d{2}/, true],
+ ['YYYYYY-MM-DD', /[+-]\d{6}-\d\d-\d\d/, true],
+ ['YYYY-MM-DD', /\d{4}-\d\d-\d\d/, true],
+ ['GGGG-[W]WW-E', /\d{4}-W\d\d-\d/, true],
+ ['GGGG-[W]WW', /\d{4}-W\d\d/, true, false],
['YYYY-DDD', /\d{4}-\d{3}/, true],
- ['YYYYYYMMDD', /[+-]\d{6}\d{2}\d{2}/, false],
- ['YYYYMMDD', /\d{4}\d{2}\d{2}/, false],
+ ['YYYY-MM', /\d{4}-\d\d/, true, false],
+ ['YYYYYYMMDD', /[+-]\d{10}/, false],
+ ['YYYYMMDD', /\d{8}/, false],
// YYYYMM is NOT allowed by the standard
- ['GGGG[W]WWE', /\d{4}W\d{2}\d/, false],
- ['GGGG[W]WW', /\d{4}W\d{2}/, false],
- ['YYYYDDD', /\d{4}\d{3}/, false]
+ ['GGGG[W]WWE', /\d{4}W\d{3}/, false],
+ ['GGGG[W]WW', /\d{4}W\d{2}/, false, false],
+ ['YYYYDDD', /\d{7}/, false]
];
// iso time formats and regexes
var isoTimes = [
['HH:mm:ss.SSSS', /\d\d:\d\d:\d\d\.\d+/, true],
+ ['HH:mm:ss,SSSS', /\d\d:\d\d:\d\d,\d+/, true],
['HH:mm:ss', /\d\d:\d\d:\d\d/, true],
['HH:mm', /\d\d:\d\d/, true],
['HHmmss.SSSS', /\d\d\d\d\d\d\.\d+/, false],
var i, l,
string = config._i,
match = isoRegex.exec(string),
- extendedDate, extendedTime;
+ extendedDate, extendedTime, allowTime, dateFormat, timeFormat, tzFormat;
if (match) {
getParsingFlags(config).iso = true;
for (i = 0, l = isoDates.length; i < l; i++) {
if (isoDates[i][1].exec(match[1])) {
- config._f = isoDates[i][0];
+ dateFormat = isoDates[i][0];
extendedDate = isoDates[i][2];
+ allowTime = isoDates[i][3] !== false;
break;
}
}
- for (i = 0, l = isoTimes.length; i < l; i++) {
- if (isoTimes[i][1].exec(match[3])) {
- // match[2] should be 'T' or space
- config._f += (match[2] || ' ') + isoTimes[i][0];
- extendedTime = isoTimes[i][2];
- break;
+ if (dateFormat == null) {
+ config._isValid = false;
+ return;
+ }
+ if (match[3] != null) {
+ for (i = 0, l = isoTimes.length; i < l; i++) {
+ if (isoTimes[i][1].exec(match[3])) {
+ // match[2] should be 'T' or space
+ timeFormat = (match[2] || ' ') + isoTimes[i][0];
+ extendedTime = isoTimes[i][2];
+ break;
+ }
+ }
+ if (timeFormat == null) {
+ config._isValid = false;
+ return;
}
}
+ if (!allowTime && timeFormat != null) {
+ config._isValid = false;
+ return;
+ }
if (extendedDate != null &&
extendedTime != null &&
extendedDate !== extendedTime) {
config._isValid = false;
return;
}
- matchOffset.lastIndex = 0;
- if (matchOffset.exec(match[4])) {
- config._f += 'Z';
+ if (match[4] != null) {
+ if (tzRegex.exec(match[4])) {
+ tzFormat = 'Z';
+ } else {
+ config._isValid = false;
+ return;
+ }
}
+ config._f = dateFormat + (timeFormat || '') + (tzFormat || '');
configFromStringAndFormat(config);
} else {
config._isValid = false;
import { addSubtract } from '../moment/add-subtract';
import { isMoment, copyConfig } from '../moment/constructor';
import { addFormatToken } from '../format/format';
-import { addRegexToken, matchOffset } from '../parse/regex';
+import { addRegexToken, matchOffset, matchShortOffset } from '../parse/regex';
import { addParseToken } from '../parse/token';
import { createLocal } from '../create/local';
import { prepareConfig } from '../create/from-anything';
// PARSING
-addRegexToken('Z', matchOffset);
-addRegexToken('ZZ', matchOffset);
+addRegexToken('Z', matchShortOffset);
+addRegexToken('ZZ', matchShortOffset);
addParseToken(['Z', 'ZZ'], function (input, array, config) {
config._useUTC = true;
- config._tzm = offsetFromString(input);
+ config._tzm = offsetFromString(matchShortOffset, input);
});
// HELPERS
// '-1530' > ['-15', '30']
var chunkOffset = /([\+\-]|\d\d)/gi;
-function offsetFromString(string) {
- var matches = ((string || '').match(matchOffset) || []);
+function offsetFromString(matcher, string) {
+ var matches = ((string || '').match(matcher) || []);
var chunk = matches[matches.length - 1] || [];
var parts = (chunk + '').match(chunkOffset) || ['-', 0, 0];
var minutes = +(parts[1] * 60) + toInt(parts[2]);
}
if (input != null) {
if (typeof input === 'string') {
- input = offsetFromString(input);
+ input = offsetFromString(matchShortOffset, input);
}
if (Math.abs(input) < 16) {
input = input * 60;
if (this._tzm) {
this.utcOffset(this._tzm);
} else if (typeof this._i === 'string') {
- this.utcOffset(offsetFromString(this._i));
+ this.utcOffset(offsetFromString(matchOffset, this._i));
}
return this;
}
tz2 = tz.replace(':', ''),
tz3 = tz2.slice(0, 3),
formats = [
+ ['2011-10', '2011-10-01T00:00:00.000' + tz],
['2011-10-08', '2011-10-08T00:00:00.000' + tz],
['2011-10-08T18', '2011-10-08T18:00:00.000' + tz],
['2011-10-08T18:04', '2011-10-08T18:04:00.000' + tz],
}
});
+test('non iso 8601 strings', function (assert) {
+ assert.ok(!moment('2015-10T10:15', moment.ISO_8601).isValid(), 'incomplete date with time');
+ assert.ok(!moment('2015-W10T10:15', moment.ISO_8601).isValid(), 'incomplete week date with time');
+ assert.ok(!moment('201510', moment.ISO_8601).isValid(), 'basic YYYYMM is not allowed');
+ assert.ok(!moment('2015W10T1015', moment.ISO_8601).isValid(), 'incomplete week date with time (basic)');
+ assert.ok(!moment('2015-10-08T1015', moment.ISO_8601).isValid(), 'mixing extended and basic format');
+ assert.ok(!moment('20151008T10:15', moment.ISO_8601).isValid(), 'mixing basic and extended format');
+});
+
test('parsing iso week year/week/weekday', function (assert) {
assert.equal(moment.utc('2007-W01').format(), '2007-01-01T00:00:00+00:00', '2008 week 1 (1st Jan Mon)');
assert.equal(moment.utc('2008-W01').format(), '2007-12-31T00:00:00+00:00', '2008 week 1 (1st Jan Tue)');