import { configFromArray } from './from-array';
import { configFromObject } from './from-object';
+var updateInProgress = false;
+
function createFromConfig (config) {
var res = new Moment(checkOverflow(prepareConfig(config)));
+
+ // Prevent infinite loop in case updateOffset creates new moment objects.
+ if (updateInProgress === false) {
+ updateInProgress = true;
+ res = hooks.updateOffset(res);
+ updateInProgress = false;
+ }
+
if (res._nextDay) {
// Adding is smart enough around DST
res = res.add(1, 'd');
val = typeof val === 'string' ? +val : val;
dur = createDuration(val, period);
- addSubtract(this, dur, direction);
- return this;
+ return addSubtract(this, dur, direction);
};
}
if (!mom.isValid()) {
// No op
- return;
+ return mom;
}
updateOffset = updateOffset == null ? true : updateOffset;
setMonth(mom, get(mom, 'Month') + months * isAdding);
}
if (updateOffset) {
- hooks.updateOffset(mom, days || months);
+ mom = hooks.updateOffset(mom, days || months);
}
+ return mom;
}
export var add = createAdder(1, 'add');
return to;
}
-var updateInProgress = false;
-
-// Moment prototype object
+// Moment prototype object.
+//
+// Run hooks.updateOffset(new Moment(config)) if you're constructing from user
+// input, but be careful to detect and break out of loops in case the user's
+// version of hooks.updateOffset() decides to trigger the same code path.
+// (Or just use from-anything's createFromConfig(), which handles this for you.)
export function Moment(config) {
copyConfig(this, config);
this._d = new Date(config._d != null ? config._d.getTime() : NaN);
if (!this.isValid()) {
this._d = new Date(NaN);
}
- // Prevent infinite loop in case updateOffset creates new moment
- // objects.
- if (updateInProgress === false) {
- updateInProgress = true;
- hooks.updateOffset(this);
- updateInProgress = false;
- }
}
export function isMoment (obj) {
return function (value) {
if (value != null) {
set(this, unit, value);
- hooks.updateOffset(this, keepTime);
- return this;
+ return hooks.updateOffset(this, keepTime);
} else {
return get(this, unit);
}
export function getSetMonth (value) {
if (value != null) {
setMonth(this, value);
- hooks.updateOffset(this, true);
- return this;
+ return hooks.updateOffset(this, true);
} else {
return get(this, 'Month');
}
diff = (isMoment(input) || isDate(input) ? input.valueOf() : createLocal(input).valueOf()) - res.valueOf();
// Use low-level api, because this fn is low-level api.
res._d.setTime(res._d.valueOf() + diff);
- hooks.updateOffset(res, false);
- return res;
+ return hooks.updateOffset(res, false);
} else {
return createLocal(input).local();
}
// This function will be called whenever a moment is mutated.
// It is intended to keep the offset in sync with the timezone.
-hooks.updateOffset = function () {};
+//
+// Because Moment's external API is immutable and this hook will be defined
+// externally (e.g. by Moment Timezone), this hook must return a (possibly new)
+// Moment instance that reflects the correctly-updated offset.
+hooks.updateOffset = function (m) {
+ return m;
+};
// MOMENTS
return input != null ? this : NaN;
}
if (input != null) {
+ var ret = this;
if (typeof input === 'string') {
input = offsetFromString(matchShortOffset, input);
if (input === null) {
} else if (Math.abs(input) < 16 && !keepMinutes) {
input = input * 60;
}
- if (!this._isUTC && keepLocalTime) {
- localAdjust = getDateOffset(this);
+ if (!ret._isUTC && keepLocalTime) {
+ localAdjust = getDateOffset(ret);
}
- this._offset = input;
- this._isUTC = true;
+ ret._offset = input;
+ ret._isUTC = true;
if (localAdjust != null) {
- this.add(localAdjust, 'm');
+ ret = ret.add(localAdjust, 'm');
}
if (offset !== input) {
- if (!keepLocalTime || this._changeInProgress) {
- addSubtract(this, createDuration(input - offset, 'm'), 1, false);
- } else if (!this._changeInProgress) {
- this._changeInProgress = true;
- hooks.updateOffset(this, true);
- this._changeInProgress = null;
+ if (!keepLocalTime || ret._changeInProgress) {
+ ret = addSubtract(ret, createDuration(input - offset, 'm'), 1, false);
+ } else if (!ret._changeInProgress) {
+ ret._changeInProgress = true;
+ ret = hooks.updateOffset(ret, true);
+ ret._changeInProgress = null;
}
}
- return this;
+ return ret;
} else {
return this._isUTC ? offset : getDateOffset(this);
}
moment.updateOffset = function (mom, keepTime) {
if (mom.isBefore(dstAt)) {
- mom.utcOffset(-8, keepTime);
- } else {
- mom.utcOffset(-7, keepTime);
+ return mom.utcOffset(-8, keepTime);
}
+ return mom.utcOffset(-7, keepTime);
};
m = moment('2014-03-15T00:00:00-07:00').parseZone();
moment.updateOffset = function (mom, keepTime) {
if (mom.isBefore(dstAt)) {
- mom.utcOffset(-7, keepTime);
+ mom = mom.utcOffset(-7, keepTime);
} else {
- mom.utcOffset(-8, keepTime);
+ mom = mom.utcOffset(-8, keepTime);
}
+ return mom;
};
m = moment('2014-11-15T00:00:00-08:00').parseZone();
moment.updateOffset = function (mom, keepTime) {
if (mom.isBefore(dstAt)) {
- mom.utcOffset(-8, keepTime);
+ mom = mom.utcOffset(-8, keepTime);
} else {
- mom.utcOffset(-7, keepTime);
+ mom = mom.utcOffset(-7, keepTime);
}
+ return mom;
};
m = moment('2014-03-15T00:00:00-07:00').parseZone();
moment.updateOffset = function (mom, keepTime) {
if (mom.isBefore(dstAt)) {
- mom.utcOffset(-7, keepTime);
+ mom = mom.utcOffset(-7, keepTime);
} else {
- mom.utcOffset(-8, keepTime);
+ mom = mom.utcOffset(-8, keepTime);
}
+ return mom;
};
m = moment('2014-11-15T00:00:00-08:00').parseZone();
test('update offset after changing any values', function (assert) {
var oldOffset = moment.updateOffset,
- m = moment.utc([2000, 6, 1]);
+ m = moment.utc([2000, 6, 1]),
+ doChange = false;
moment.updateOffset = function (mom, keepTime) {
- if (mom.__doChange) {
+ if (doChange) {
if (+mom > 962409600000) {
- mom.utcOffset(-120, keepTime);
+ mom = mom.utcOffset(-120, keepTime);
} else {
- mom.utcOffset(-60, keepTime);
+ mom = mom.utcOffset(-60, keepTime);
}
}
+ return mom;
};
assert.equal(m.format('ZZ'), '+0000', 'should be at +0000');
assert.equal(m.format('HH:mm'), '00:00', 'should start 12AM at +0000 timezone');
- m.__doChange = true;
- m.add(1, 'h');
+ doChange = true;
+ m = m.add(1, 'h');
assert.equal(m.format('ZZ'), '-0200', 'should be at -0200');
assert.equal(m.format('HH:mm'), '23:00', '1AM at +0000 should be 11PM at -0200 timezone');
moment.updateOffset = function (mom, keepTime) {
if (mom.utc().month() > 2) {
- mom.utcOffset(60, keepTime);
+ mom = mom.utcOffset(60, keepTime);
} else {
- mom.utcOffset(0, keepTime);
+ mom = mom.utcOffset(0, keepTime);
}
+ return mom;
};
assert.equal(m.hour(), 3, 'should start at 00:00');
moment.updateOffset = function (mom, keepTime) {
if (mom.month() > 2 && mom.month() < 9) {
- mom.utcOffset(60, keepTime);
+ mom = mom.utcOffset(60, keepTime);
} else {
- mom.utcOffset(0, keepTime);
+ mom = mom.utcOffset(0, keepTime);
}
+ return mom;
};
assert.ok(!moment().month(0).isDST(), 'Jan should not be summer dst');
moment.updateOffset = function (mom) {
if (mom.month() > 2 && mom.month() < 9) {
- mom.utcOffset(0);
+ mom = mom.utcOffset(0);
} else {
- mom.utcOffset(60);
+ mom = mom.utcOffset(60);
}
+ return mom;
};
assert.ok(moment().month(0).isDST(), 'Jan should be winter dst');
test('update offset after changing any values', function (assert) {
var oldOffset = moment.updateOffset,
- m = moment.utc([2000, 6, 1]);
+ m = moment.utc([2000, 6, 1]),
+ doChange = false;
moment.updateOffset = function (mom, keepTime) {
- if (mom.__doChange) {
+ if (doChange) {
if (+mom > 962409600000) {
- mom.zone(120, keepTime);
+ mom = mom.zone(120, keepTime);
} else {
- mom.zone(60, keepTime);
+ mom = mom.zone(60, keepTime);
}
}
+ return mom;
};
assert.equal(m.format('ZZ'), '+0000', 'should be at +0000');
assert.equal(m.format('HH:mm'), '00:00', 'should start 12AM at +0000 timezone');
- m.__doChange = true;
- m.add(1, 'h');
+ doChange = true;
+ m = m.add(1, 'h');
assert.equal(m.format('ZZ'), '-0200', 'should be at -0200');
assert.equal(m.format('HH:mm'), '23:00', '1AM at +0000 should be 11PM at -0200 timezone');
moment.updateOffset = function (mom, keepTime) {
if (mom.utc().month() > 2) {
- mom.zone(-60, keepTime);
+ mom = mom.zone(-60, keepTime);
} else {
- mom.zone(0, keepTime);
+ mom = mom.zone(0, keepTime);
}
+ return mom;
};
assert.equal(m.hour(), 3, 'should start at 00:00');
moment.updateOffset = function (mom, keepTime) {
if (mom.month() > 2 && mom.month() < 9) {
- mom.zone(-60, keepTime);
+ mom = mom.zone(-60, keepTime);
} else {
- mom.zone(0, keepTime);
+ mom = mom.zone(0, keepTime);
}
+ return mom;
};
assert.ok(!moment().month(0).isDST(), 'Jan should not be summer dst');
moment.updateOffset = function (mom) {
if (mom.month() > 2 && mom.month() < 9) {
- mom.zone(0);
+ mom = mom.zone(0);
} else {
- mom.zone(-60);
+ mom = mom.zone(-60);
}
+ return mom;
};
assert.ok(moment().month(0).isDST(), 'Jan should be winter dst');