timezoneParseRegex = /([\+\-]|\d\d)/gi,
VERSION = "1.5.0",
shortcuts = 'Month|Date|Hours|Minutes|Seconds|Milliseconds'.split('|'),
- durationGetters = 'years|months|weeks|days|hours|minutes|seconds|milliseconds'.split('|');
+ durationGetters = 'years|months|days|hours|minutes|seconds|milliseconds'.split('|');
// Moment prototype object
function Moment(date, isUTC) {
this._isUTC = !!isUTC;
}
+ function absRound(number) {
+ if (number < 0) {
+ return Math.ceil(number);
+ } else {
+ return Math.floor(number);
+ }
+ }
+
// Duration Constructor
function Duration(duration) {
- var data = this._data = {};
- data.years = duration.years || duration.y || 0;
- data.months = duration.months || duration.M || 0;
- data.weeks = duration.weeks || duration.w || 0;
- data.days = duration.days || duration.d || 0;
- data.hours = duration.hours || duration.h || 0;
- data.minutes = duration.minutes || duration.m || 0;
- data.seconds = duration.seconds || duration.s || 0;
- data.milliseconds = duration.milliseconds || duration.ms || 0;
+ var data = this._data = {},
+ years = duration.years || duration.y || 0,
+ months = duration.months || duration.M || 0,
+ weeks = duration.weeks || duration.w || 0,
+ days = duration.days || duration.d || 0,
+ hours = duration.hours || duration.h || 0,
+ minutes = duration.minutes || duration.m || 0,
+ seconds = duration.seconds || duration.s || 0,
+ milliseconds = duration.milliseconds || duration.ms || 0;
+
+ // representation for dateAddRemove
+ this._milliseconds = milliseconds +
+ seconds * 1e3 + // 1000
+ minutes * 6e4 + // 1000 * 60
+ hours * 36e5; // 1000 * 60 * 60
+ // Because of dateAddRemove treats 24 hours as different from a
+ // day when working around DST, we need to store them separately
+ this._days = days +
+ weeks * 7;
+ // It is impossible translate months into days without knowing
+ // which months you are are talking about, so we have to store
+ // it separately.
+ this._months = months +
+ years * 12;
+
+ // The following code bubbles up values, see the tests for
+ // examples of what that means.
+ data.milliseconds = milliseconds % 1000;
+ seconds += absRound(milliseconds / 1000);
+
+ data.seconds = seconds % 60;
+ minutes += absRound(seconds / 60);
+
+ data.minutes = minutes % 60;
+ hours += absRound(minutes / 60);
+
+ data.hours = hours % 24;
+ days += absRound(hours / 24);
+
+ days += weeks * 7;
+ data.days = days % 30;
+
+ months += absRound(days / 30);
+
+ data.months = months % 12;
+ years += absRound(months / 12);
+
+ data.years = years;
}
// left zero fill a number
input = moment.duration(_input);
}
- ms = input.milliseconds() +
- (input.seconds()) * 1e3 + // 1000
- (input.minutes()) * 6e4 + // 1000 * 60
- (input.hours()) * 36e5; // 1000 * 60 * 60
- d = (input.days()) +
- (input.weeks()) * 7;
- M = (input.months()) +
- (input.years()) * 12;
+ ms = input._milliseconds;
+ d = input._days;
+ M = input._months;
+
if (ms) {
date.setTime(+date + ms * adding);
}
makeShortcut('year', 'FullYear');
moment.duration.fn = Duration.prototype = {
+ weeks : function () {
+ return absRound(this.days() / 7);
+ },
+
valueOf : function () {
- return this._data.milliseconds +
- (this._data.seconds * 1000) + // 1000
- (this._data.minutes * 60000) + // 60 * 1000
- (this._data.hours * 3600000) + // 60 * 60 * 1000
- (this._data.days * 86400000) + // 24 * 60 * 60 * 1000
- (this._data.weeks * 604800000) + // 7 * 24 * 60 * 60 * 1000
- (this._data.months * 2592000000) + // 30 * 24 * 60 * 60 * 1000
- (this._data.years * 31536000000); // 365 * 24 * 60 * 60 * 1000
+ return this._milliseconds +
+ this._days * 864e5 +
+ this._months * 2592e6;
},
humanize : function (withSuffix) {
var d = moment.duration({
years: 2,
months: 3,
- weeks: 4,
+ weeks: 2,
days: 1,
hours: 8,
minutes: 9,
test.expect(8);
test.equal(d.years(), 2, "years");
test.equal(d.months(), 3, "months");
- test.equal(d.weeks(), 4, "weeks");
- test.equal(d.days(), 1, "days");
+ test.equal(d.weeks(), 2, "weeks");
+ test.equal(d.days(), 15, "days"); // two weeks + 1 day
test.equal(d.hours(), 8, "hours");
test.equal(d.minutes(), 9, "minutes");
test.equal(d.seconds(), 20, "seconds");
test.done();
},
+ "bubble value up" : function(test) {
+ test.expect(5);
+ test.equal(moment.duration({milliseconds: 61001}).milliseconds(), 1, "61001 milliseconds has 1 millisecond left over");
+ test.equal(moment.duration({milliseconds: 61001}).seconds(), 1, "61001 milliseconds has 1 second left over");
+ test.equal(moment.duration({milliseconds: 61001}).minutes(), 1, "61001 milliseconds has 1 minute left over");
+
+ test.equal(moment.duration({minutes: 350}).minutes(), 50, "350 minutes has 50 minutes left over");
+ test.equal(moment.duration({minutes: 350}).hours(), 5, "350 minutes has 5 hours left over");
+ test.done();
+ },
+
+ "clipping" : function(test) {
+ test.expect(18);
+ test.equal(moment.duration({months: 11}).months(), 11, "11 months is 11 months");
+ test.equal(moment.duration({months: 11}).years(), 0, "11 months makes no year");
+ test.equal(moment.duration({months: 12}).months(), 0, "12 months is 0 months left over");
+ test.equal(moment.duration({months: 12}).years(), 1, "12 months makes 1 year");
+ test.equal(moment.duration({months: 13}).months(), 1, "13 months is 1 month left over");
+ test.equal(moment.duration({months: 13}).years(), 1, "13 months makes 1 year");
+
+ test.equal(moment.duration({days: 29}).days(), 29, "29 days is 29 days");
+ test.equal(moment.duration({days: 29}).months(), 0, "29 days makes no month");
+ test.equal(moment.duration({days: 30}).days(), 0, "30 days is 0 days left over");
+ test.equal(moment.duration({days: 30}).months(), 1, "30 days is a month");
+ test.equal(moment.duration({days: 31}).days(), 1, "31 days is 1 day left over");
+ test.equal(moment.duration({days: 31}).months(), 1, "31 days is a month");
+
+ test.equal(moment.duration({hours: 23}).hours(), 23, "23 hours is 23 hours");
+ test.equal(moment.duration({hours: 23}).days(), 0, "23 hours makes no day");
+ test.equal(moment.duration({hours: 24}).hours(), 0, "24 hours is 0 hours left over");
+ test.equal(moment.duration({hours: 24}).days(), 1, "24 hours makes 1 day");
+ test.equal(moment.duration({hours: 25}).hours(), 1, "25 hours is 1 hour left over");
+ test.equal(moment.duration({hours: 25}).days(), 1, "25 hours makes 1 day");
+ test.done();
+ },
+
+ "effective equivalency" : function(test) {
+ test.expect(7);
+ test.deepEqual(moment.duration({seconds: 1})._data, moment.duration({milliseconds: 1000})._data, "1 second is the same as 1000 milliseconds");
+ test.deepEqual(moment.duration({seconds: 60})._data, moment.duration({minutes: 1})._data, "1 minute is the same as 60 seconds");
+ test.deepEqual(moment.duration({minutes: 60})._data, moment.duration({hours: 1})._data, "1 hour is the same as 60 minutes");
+ test.deepEqual(moment.duration({hours: 24})._data, moment.duration({days: 1})._data, "1 day is the same as 24 hours");
+ test.deepEqual(moment.duration({days: 7})._data, moment.duration({weeks: 1})._data, "1 week is the same as 7 days");
+ test.deepEqual(moment.duration({days: 30})._data, moment.duration({months: 1})._data, "1 month is the same as 30 days");
+ test.deepEqual(moment.duration({months: 12})._data, moment.duration({years: 1})._data, "1 years is the same as 12 months");
+ test.done();
+ },
+
"isDuration" : function(test) {
test.expect(3);
test.ok(moment.isDuration(moment.duration(12345678)), "correctly says true");