* isValid -> compute before "construction", checkOverflow
- do we have parsing flags if the object is constructed without format?
* parseZone -> fixedOffset(...., 'parse') + special tmp timezone + check in quick
+ * what to do if parseZone is used but there is no parsed zone? ---> UTC or invalid
+
+ * single format
+ * array format
+ * string only (ISO/RFC2822)
* Moment should be called from 3 places (invalid, local, utc)
+* _pf gets out-of-sync from config._i/_f/_strict
+ * straigten up interface between different create/parse components
+* rething creationData (isUTC? format?, what for all other cases)
OLD TODO (maybe del)
* remove _nextDay from moment -> handle it before "creation"
import { createCollect, createInvalid } from './from-anything';
import { localTimeZone } from '../timezone/local';
import { fixedTimeZoneForOffset } from '../timezone/fixed-offset';
+import { parsedTimeZone } from '../timezone/parsed';
import { isMoment } from '../moment/constructor';
export function createUTC (input, format, locale, strict) {
return createCollect(input, format, locale, strict, fixedTimeZoneForOffset(0));
}
+export function createParsedOffset (input, format, locale, strict) {
+ return createCollect(input, format, locale, strict, parsedTimeZone);
+}
+
// TODO(Iskren): Enabled 'parse' offset, which uses it from the parsed string.
export function createFixedOffset () {
var args = [].slice.apply(arguments),
config._i = input = config._locale.preparse(input);
}
- if (isUndefined(input)) {
+ if (isUndefined(input) && !format) {
return quickCreateUTC(hooks.now(), config._locale, config._tz);
} else if (isMoment(input) || isDate(input)) {
return quickCreateUTC(input.valueOf(), config._locale, config._tz);
- } else if (isNumber(input)) {
+ } else if (isNumber(input) && !format) {
return quickCreateUTC(input, config._locale, config._tz);
} else if (isArray(format)) {
configFromStringAndArray(config);
} else {
hooks.createFromInputFallback(config);
}
- if (!isValid(config) && (config._d == null || !isNaN(config._d.getTime()))) {
+ if (!isValid(config)) {
return createInvalid(getParsingFlags(config));
}
+ // TODO: parsing flags fail ...
+ if (config._pf.format == null) {
+ config._pf.format = config._f;
+ }
if (!config._useUTC) {
return quickCreateLocal(+config._d, config._locale, config._tz, config._pf);
} else {
}
export function quickCreateLocal(lts, locale, timeZone, pf) {
+ if (!timeZone.isValid()) {
+ return createInvalid({badTimeZone: true});
+ }
var localTsOffset = computeOffset(lts, timeZone);
- // console.log('Local', lts, '###', localTsOffset[0], localTsOffset[1]);
return new Moment({_ts: localTsOffset[0], _offset: localTsOffset[1], _locale: locale, _tz: timeZone, _pf: pf});
}
export function quickCreateUTC(uts, locale, timeZone, pf) {
+ if (!timeZone.isValid()) {
+ return createInvalid({badTimeZone: true});
+ }
var offset = timeZone.offsetFromTimestamp(uts);
- // console.log('UTC', uts, '###', uts + offset, offset);
return new Moment({_ts: uts + offset, _offset: offset, _locale: locale, _tz: timeZone, _pf: pf});
}
import { weekOfYear, weeksInYear, dayOfYearFromWeeks } from '../units/week-calendar-utils';
import { YEAR, MONTH, DATE, HOUR, MINUTE, SECOND, MILLISECOND } from '../units/constants';
import { fixedTimeZoneForOffset } from '../timezone/fixed-offset';
+import { parsedTimeZone } from '../timezone/parsed';
import defaults from '../utils/defaults';
import getParsingFlags from './parsing-flags';
import checkOverflow from './check-overflow';
// TODO(Iskren): Call only if needed
+// TODO(Iskren): tz.isValid -- does it make sense?
function currentDateArray(config, tz) {
var now = hooks.now(),
- nowValue = new Date(now + tz.offsetFromTimestamp(now));
+ nowValue = new Date(now + (tz.isValid() ? tz.offsetFromTimestamp(now) : 0));
return [nowValue.getUTCFullYear(), nowValue.getUTCMonth(), nowValue.getUTCDate()];
}
}
// TODO: Implement ignoreOffset config flag
- if (config._tzm) {
+ if (config._tzm != null) {
tz = fixedTimeZoneForOffset(config._tzm);
}
config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);
config._useUTC = true;
}
- // TODO: Implement fixedOffset 'parse'
- // if (config._tz === parseTimeZone) {
- // config._tz = fixedTimeZoneForOffset(config._tzm);
- // }
-
+ if (config._tz === parsedTimeZone) {
+ config._tz = fixedTimeZoneForOffset(isNaN(config._tzm) ? 0 : config._tzm);
+ }
if (config._nextDay) {
config._a[HOUR] = 24;
import { isValid } from './valid';
import extend from '../utils/extend';
+function cloneConfig(config) {
+ return {
+ _tz : config._tz,
+ _locale : config._locale,
+ _i : config._i,
+ _f : config._f,
+ _strict : config._strict
+ }
+}
+
// date from string and array of format strings
export function configFromStringAndArray(config) {
var tempConfig,
for (i = 0; i < config._f.length; i++) {
currentScore = 0;
- tempConfig = copyConfig({}, config);
+ tempConfig = cloneConfig(config);
tempConfig._f = config._f[i];
configFromStringAndFormat(tempConfig);
import { configFromStringAndFormat } from './from-string-and-format';
+import { isValid } from './valid';
import { hooks } from '../utils/hooks';
import { deprecate } from '../utils/deprecate';
import getParsingFlags from './parsing-flags';
var parsedParts = some.call(flags.parsedDateParts, function (i) {
return i != null;
});
- var isNowValid = !isNaN(m._d.getTime()) &&
+ var isNowValid = m._d != null && !isNaN(m._d.getTime()) &&
flags.overflow < 0 &&
!flags.empty &&
!flags.invalidMonth &&
var d, uts;
// console.log('SET', arguments);
if (msCoef != null) {
- // this is one of ms, second, minute, hour
+ // this is one of ms, second, minute
uts = mom.valueOf();
uts += (value - get(mom, unit)) * msCoef;
return quickCreateUTC(uts, mom._locale, mom._tz);
} else {
- // day or year, NOT month
+ // hour, day or year, NOT month
d = new Date(mom._d);
d['setUTC' + unit](value);
return quickCreateLocal(d.valueOf(), mom._locale, mom._tz);
-import { createLocal, createUTC, createFixedOffset } from '../create/constructors';
+import { createLocal, createUTC, createFixedOffset, createParsedOffset, createZoned } from '../create/constructors';
import { createInvalid } from '../create/from-anything';
import { isMoment } from './constructor';
import { min, max } from './min-max';
createUnix,
createLocal,
createFixedOffset,
+ createParsedOffset,
+ createZoned,
createInvalid,
momentPrototype
};
--- /dev/null
+export default function BaseTimeZone() {
+}
+
+BaseTimeZone.prototype.isValid = function() {
+ return true;
+}
import hasOwnProp from '../utils/has-own-prop';
+import BaseTimeZone from './base';
+import extend from '../utils/extend';
var memo = {};
return memo[offset];
};
+FixedOffsetTimeZone.prototype = extend({}, BaseTimeZone.prototype);
+
FixedOffsetTimeZone.prototype.offsetFromTimestamp = function (uts) {
return this.offsetMs;
};
+import extend from '../utils/extend';
+import BaseTimeZone from './base';
+
function LocalTimeZone() {
}
+LocalTimeZone.prototype = extend({}, BaseTimeZone.prototype);
+
LocalTimeZone.prototype.offsetFromTimestamp = function (uts) {
return -(new Date(uts).getTimezoneOffset()) * 60 * 1000;
};
--- /dev/null
+import extend from '../utils/extend';
+import BaseTimeZone from './base';
+
+function ParsedTimeZone() {
+}
+
+ParsedTimeZone.prototype = extend({}, BaseTimeZone.prototype);
+
+ParsedTimeZone.prototype.isValid = function () {
+ return false;
+}
+
+export var parsedTimeZone = new ParsedTimeZone();
// specified which hour he wants. So trying to maintain the same hour (in
// a new timezone) makes sense. Adding/subtracting hours does not follow
// this rule.
-export var getSetHour = makeGetSet('Hours', 60 * 60 * 1000);
+export var getSetHour = makeGetSet('Hours');
// PRIORITY
// }
export function isLocal () {
- return this._tz.type === 'local';
+ return this.isValid() && this._tz.type === 'local';
}
export function isUtcOffset () {
- return this._tz.type === 'fixed-offset';
+ return this.isValid() && this._tz.type === 'fixed-offset';
}
export function isUtc () {
- return this._tz.type === 'fixed-offset' && this._tz.offset === 0;
+ return this.isValid() && this._tz.type === 'fixed-offset' && this._tz.offset === 0;
}
addRegexToken('X', matchTimestamp);
addParseToken('X', function (input, array, config) {
config._d = new Date(parseFloat(input, 10) * 1000);
+ config._useUTC = true;
});
addParseToken('x', function (input, array, config) {
config._d = new Date(toInt(input));
+ config._useUTC = true;
});
createUnix as unix,
createLocal as local,
createInvalid as invalid,
- createFixedOffset as fixedOffset
+ createFixedOffset as fixedOffset,
+ createParsedOffset as parseZone,
+ createZoned as zoned
} from './lib/moment/moment';
import {
moment.max = max;
moment.now = now;
moment.utc = utc;
+moment.parseZone = parseZone;
+moment.zoned = zoned;
moment.unix = unix;
moment.months = months;
moment.isDate = isDate;
--- /dev/null
+import BaseTimeZone from '../../lib/timezone/base';
+import extend from '../../lib/utils/extend';
+
+function DSTTimeZone(dstAt, oldOffset, newOffset) {
+ BaseTimeZone.call(this);
+
+ this.dstAt = dstAt;
+ this.oldOffsetMs = oldOffset * 60 * 60 * 1000;
+ this.newOffsetMs = newOffset * 60 * 60 * 1000;
+}
+
+DSTTimeZone.prototype = extend({}, BaseTimeZone.prototype);
+
+DSTTimeZone.prototype.offsetFromTimestamp = function (utc) {
+ if (utc < this.dstAt) {
+ return this.oldOffsetMs;
+ } else {
+ return this.newOffsetMs;
+ }
+}
+
+export var dstTimeZone = function (dstAt, oldOffset, newOffset) {
+ return new DSTTimeZone(dstAt, oldOffset, newOffset);
+}
assert.equal(+moment(extend({}, nowu)), +nowu, 'cloning extend-ed utc now is utc now');
});
-test('cloning respects moment.momentProperties', function (assert) {
- var m = moment();
+// TODO: Drop this altogether?
+// test('cloning respects moment.momentProperties', function (assert) {
+// var m = moment();
- assert.equal(moment(m)._special, undefined, 'cloning ignores extra properties');
- m._special = 'bacon';
- moment.momentProperties.push('_special');
- assert.equal(moment(m)._special, 'bacon', 'cloning respects momentProperties');
- moment.momentProperties.pop();
-});
+// assert.equal(moment(m)._special, undefined, 'cloning ignores extra properties');
+// m._special = 'bacon';
+// moment.momentProperties.push('_special');
+// assert.equal(moment(m)._special, 'bacon', 'cloning respects momentProperties');
+// moment.momentProperties.pop();
+// });
test('undefined', function (assert) {
assert.ok(moment().toDate() instanceof Date, 'undefined');
assert.equal(moment('11-02-10', ['MM.DD.YY', 'DD-MM-YY']).format('MM DD YYYY'), '02 11 2010', 'escape RegExp special characters on comparing');
- assert.equal(moment('13-10-98', ['DD MM YY', 'DD MM YYYY'])._f, 'DD MM YY', 'use two digit year');
- assert.equal(moment('13-10-1998', ['DD MM YY', 'DD MM YYYY'])._f, 'DD MM YYYY', 'use four digit year');
+ assert.equal(moment('13-10-98', ['DD MM YY', 'DD MM YYYY']).parsingFlags().format, 'DD MM YY', 'use two digit year');
+ assert.equal(moment('13-10-1998', ['DD MM YY', 'DD MM YYYY']).parsingFlags().format, 'DD MM YYYY', 'use four digit year');
- assert.equal(moment('01', ['MM', 'DD'])._f, 'MM', 'Should use first valid format');
+ assert.equal(moment('01', ['MM', 'DD']).parsingFlags().format, 'MM', 'Should use first valid format');
assert.equal(moment('Thursday 8:30pm', ['dddd h:mma']).format('YYYY MM DD dddd h:mma'), thursdayForCurrentWeek + ' Thursday 8:30pm', 'Default to current week');
});
assert.equal(momentA.month(), 5, 'momentB keeps original month');
});
-test('cloning carrying over utc mode', function (assert) {
- assert.equal(moment(moment().local())._isUTC, false, 'A cloned local moment should have _isUTC == false');
- assert.equal(moment(moment().utc())._isUTC, true, 'A cloned utc moment should have _isUTC == true');
- assert.equal(moment(moment())._isUTC, false, 'A cloned local moment should have _isUTC == false');
- assert.equal(moment(moment.utc())._isUTC, true, 'A cloned utc moment should have _isUTC == true');
+test('cloning uses utc mode of new constructor', function (assert) {
+ assert.equal(moment(moment().local()).isUTC(), false, 'local(local) -> local');
+ assert.equal(moment(moment().utc()).isUTC(), false, 'local(utc) -> local');
+ assert.equal(moment.utc(moment().local()).isUTC(), true, 'utc(local) -> utc');
+ assert.equal(moment.utc(moment().utc()).isUTC(), true, 'utc(utc) -> utc');
});
test('parsing RFC 2822', function (assert) {
});
test('parsing iso with T', function (assert) {
- assert.equal(moment('2011-10-08T18')._f, 'YYYY-MM-DDTHH', 'should include \'T\' in the format');
- assert.equal(moment('2011-10-08T18:20')._f, 'YYYY-MM-DDTHH:mm', 'should include \'T\' in the format');
- assert.equal(moment('2011-10-08T18:20:13')._f, 'YYYY-MM-DDTHH:mm:ss', 'should include \'T\' in the format');
- assert.equal(moment('2011-10-08T18:20:13.321')._f, 'YYYY-MM-DDTHH:mm:ss.SSSS', 'should include \'T\' in the format');
-
- assert.equal(moment('2011-10-08 18')._f, 'YYYY-MM-DD HH', 'should not include \'T\' in the format');
- assert.equal(moment('2011-10-08 18:20')._f, 'YYYY-MM-DD HH:mm', 'should not include \'T\' in the format');
- assert.equal(moment('2011-10-08 18:20:13')._f, 'YYYY-MM-DD HH:mm:ss', 'should not include \'T\' in the format');
- assert.equal(moment('2011-10-08 18:20:13.321')._f, 'YYYY-MM-DD HH:mm:ss.SSSS', 'should not include \'T\' in the format');
+ assert.equal(moment('2011-10-08T18').parsingFlags().format, 'YYYY-MM-DDTHH', 'should include \'T\' in the format');
+ assert.equal(moment('2011-10-08T18:20').parsingFlags().format, 'YYYY-MM-DDTHH:mm', 'should include \'T\' in the format');
+ assert.equal(moment('2011-10-08T18:20:13').parsingFlags().format, 'YYYY-MM-DDTHH:mm:ss', 'should include \'T\' in the format');
+ assert.equal(moment('2011-10-08T18:20:13.321').parsingFlags().format, 'YYYY-MM-DDTHH:mm:ss.SSSS', 'should include \'T\' in the format');
+
+ assert.equal(moment('2011-10-08 18').parsingFlags().format, 'YYYY-MM-DD HH', 'should not include \'T\' in the format');
+ assert.equal(moment('2011-10-08 18:20').parsingFlags().format, 'YYYY-MM-DD HH:mm', 'should not include \'T\' in the format');
+ assert.equal(moment('2011-10-08 18:20:13').parsingFlags().format, 'YYYY-MM-DD HH:mm:ss', 'should not include \'T\' in the format');
+ assert.equal(moment('2011-10-08 18:20:13.321').parsingFlags().format, 'YYYY-MM-DD HH:mm:ss.SSSS', 'should not include \'T\' in the format');
});
test('parsing iso Z timezone', function (assert) {
import { module, test } from '../qunit';
import moment from '../../moment';
+import { dstTimeZone } from '../helpers/dst-time-zone';
module('getters and setters');
});
test('setters across DST +1', function (assert) {
- var oldUpdateOffset = moment.updateOffset,
- // Based on a real story somewhere in America/Los_Angeles
- dstAt = moment('2014-03-09T02:00:00-08:00').parseZone(),
- m;
-
- moment.updateOffset = function (mom, keepTime) {
- if (mom.isBefore(dstAt)) {
- return mom.utcOffset(-8, keepTime);
- }
- return mom.utcOffset(-7, keepTime);
- };
-
- m = moment('2014-03-15T00:00:00-07:00').parseZone();
+ var // Based on a real story somewhere in America/Los_Angeles
+ dstAt = moment.parseZone('2014-03-09T02:00:00-08:00'),
+ m,
+ tz = dstTimeZone(+dstAt, -8, -7);
+
+ m = moment.zoned('2014-03-15T00:00:00', tz);
+ assert.equal(+m, +moment.parseZone('2014-03-15T00:00:00-07:00'), 'initial');
assert.equal(m.year(2013).format(), '2013-03-15T00:00:00-08:00', 'year across +1');
assert.equal(m.month(0).format(), '2014-01-15T00:00:00-08:00', 'month across +1');
assert.equal(m.date(1).format(), '2014-03-01T00:00:00-08:00', 'date across +1');
- m = moment('2014-03-09T03:05:00-07:00').parseZone();
+ m = moment.zoned('2014-03-09T03:05:00-07:00', tz);
assert.equal(m.hour(0).format(), '2014-03-09T00:05:00-08:00', 'hour across +1');
-
- moment.updateOffset = oldUpdateOffset;
});
test('setters across DST -1', function (assert) {
- var oldUpdateOffset = moment.updateOffset,
- // Based on a real story somewhere in America/Los_Angeles
- dstAt = moment('2014-11-02T02:00:00-07:00').parseZone(),
- m;
-
- moment.updateOffset = function (mom, keepTime) {
- if (mom.isBefore(dstAt)) {
- return mom.utcOffset(-7, keepTime);
- }
- return mom.utcOffset(-8, keepTime);
- };
-
- m = moment('2014-11-15T00:00:00-08:00').parseZone();
+ var // Based on a real story somewhere in America/Los_Angeles
+ dstAt = moment.parseZone('2014-11-02T02:00:00-07:00'),
+ m,
+ tz = dstTimeZone(+dstAt, -7, -8);
+
+ m = moment.zoned('2014-11-15T00:00:00', tz);
+ assert.equal(+m, +moment.parseZone('2014-11-15T00:00:00-08:00'), 'initial');
assert.equal(m.year(2013).format(), '2013-11-15T00:00:00-07:00', 'year across -1');
assert.equal(m.month(0).format(), '2014-01-15T00:00:00-07:00', 'month across -1');
assert.equal(m.date(1).format(), '2014-11-01T00:00:00-07:00', 'date across -1');
- m = moment('2014-11-02T03:30:00-08:00').parseZone();
+ m = moment.zoned('2014-11-02T03:30:00-08:00', tz);
assert.equal(m.hour(0).format(), '2014-11-02T00:30:00-07:00', 'hour across -1');
-
- moment.updateOffset = oldUpdateOffset;
});
test('startOf across DST +1', function (assert) {
var oldUpdateOffset = moment.updateOffset,
// Based on a real story somewhere in America/Los_Angeles
- dstAt = moment('2014-03-09T02:00:00-08:00').parseZone(),
+ dstAt = moment.parseZone('2014-03-09T02:00:00-08:00'),
m;
moment.updateOffset = function (mom, keepTime) {
return mom.utcOffset(-7, keepTime);
};
- m = moment('2014-03-15T00:00:00-07:00').parseZone();
+ m = moment.parseZone('2014-03-15T00:00:00-07:00');
assert.equal(m.startOf('y').format(), '2014-01-01T00:00:00-08:00', 'startOf(\'year\') across +1');
assert.equal(m.startOf('M').format(), '2014-03-01T00:00:00-08:00', 'startOf(\'month\') across +1');
- m = moment('2014-03-09T09:00:00-07:00').parseZone();
+ m = moment.parseZone('2014-03-09T09:00:00-07:00');
assert.equal(m.startOf('d').format(), '2014-03-09T00:00:00-08:00', 'startOf(\'day\') across +1');
- m = moment('2014-03-09T03:05:00-07:00').parseZone();
+ m = moment.parseZone('2014-03-09T03:05:00-07:00');
assert.equal(m.startOf('h').format(), '2014-03-09T03:00:00-07:00', 'startOf(\'hour\') after +1');
- m = moment('2014-03-09T01:35:00-08:00').parseZone();
+ m = moment.parseZone('2014-03-09T01:35:00-08:00');
assert.equal(m.startOf('h').format(), '2014-03-09T01:00:00-08:00', 'startOf(\'hour\') before +1');
// There is no such time as 2:30-7 to try startOf('hour') across that
test('startOf across DST -1', function (assert) {
var oldUpdateOffset = moment.updateOffset,
// Based on a real story somewhere in America/Los_Angeles
- dstAt = moment('2014-11-02T02:00:00-07:00').parseZone(),
+ dstAt = moment.parseZone('2014-11-02T02:00:00-07:00'),
m;
moment.updateOffset = function (mom, keepTime) {
return mom.utcOffset(-8, keepTime);
};
- m = moment('2014-11-15T00:00:00-08:00').parseZone();
+ m = moment.parseZone('2014-11-15T00:00:00-08:00');
assert.equal(m.startOf('y').format(), '2014-01-01T00:00:00-07:00', 'startOf(\'year\') across -1');
assert.equal(m.startOf('M').format(), '2014-11-01T00:00:00-07:00', 'startOf(\'month\') across -1');
- m = moment('2014-11-02T09:00:00-08:00').parseZone();
+ m = moment.parseZone('2014-11-02T09:00:00-08:00');
assert.equal(m.startOf('d').format(), '2014-11-02T00:00:00-07:00', 'startOf(\'day\') across -1');
// note that utc offset is -8
- m = moment('2014-11-02T01:30:00-08:00').parseZone();
+ m = moment.parseZone('2014-11-02T01:30:00-08:00');
assert.equal(m.startOf('h').format(), '2014-11-02T01:00:00-08:00', 'startOf(\'hour\') after +1');
// note that utc offset is -7
- m = moment('2014-11-02T01:30:00-07:00').parseZone();
+ m = moment.parseZone('2014-11-02T01:30:00-07:00');
assert.equal(m.startOf('h').format(), '2014-11-02T01:00:00-07:00', 'startOf(\'hour\') before +1');
moment.updateOffset = oldUpdateOffset;
});
test('parse zone', function (assert) {
- var m = moment('2013-01-01T00:00:00-13:00').parseZone();
+ var m = moment.parseZone('2013-01-01T00:00:00-13:00');
assert.equal(m.utcOffset(), -13 * 60);
assert.equal(m.hours(), 0);
});
test('parse UTC zone', function (assert) {
- var m = moment('2013-01-01T05:00:00+00:00').parseZone();
+ var m = moment.parseZone('2013-01-01T05:00:00+00:00');
assert.equal(m.utcOffset(), 0);
assert.equal(m.hours(), 5);
});
});
test('parse zone with a timezone from the format string', function (assert) {
- var m = moment('11-12-2013 -0400 +1100', 'DD-MM-YYYY ZZ #####').parseZone();
+ var m = moment.parseZone('11-12-2013 -0400 +1100', 'DD-MM-YYYY ZZ #####');
assert.equal(m.utcOffset(), -4 * 60);
});
test('parse zone without a timezone included in the format string', function (assert) {
- var m = moment('11-12-2013 -0400 +1100', 'DD-MM-YYYY').parseZone();
+ var m = moment.parseZone('11-12-2013 -0400 +1100', 'DD-MM-YYYY');
assert.equal(m.utcOffset(), 11 * 60);
});
});
test('parse zone', function (assert) {
- var m = moment('2013-01-01T00:00:00-13:00').parseZone();
+ var m = moment.parseZone('2013-01-01T00:00:00-13:00');
assert.equal(m.zone(), 13 * 60);
assert.equal(m.hours(), 0);
});
});
test('parse zone without a timezone included in the format string', function (assert) {
- var m = moment('11-12-2013 -0400 +1100', 'DD-MM-YYYY').parseZone();
+ var m = moment.parseZone('11-12-2013 -0400 +1100', 'DD-MM-YYYY');
assert.equal(m.zone(), -11 * 60);
});