@opstarts/chimp
Version:
Develop acceptance tests & end-to-end tests with realtime feedback.
179 lines (166 loc) • 6.16 kB
JavaScript
'use strict';
var d = require('d')
, pad = require('es5-ext/number/#/pad')
, date = require('es5-ext/date/valid-date')
, daysInMonth = require('es5-ext/date/#/days-in-month')
, copy = require('es5-ext/date/#/copy')
, dfloor = require('es5-ext/date/#/floor-day')
, mfloor = require('es5-ext/date/#/floor-month')
, yfloor = require('es5-ext/date/#/floor-year')
, toInteger = require('es5-ext/number/to-integer')
, toPosInt = require('es5-ext/number/to-pos-integer')
, abs = Math.abs
, format, valueOf, getYear, Duration, getCalcData;
format = require('es5-ext/string/format-method')({
y: function () { return String(abs(this.year)); },
m: function () { return pad.call(abs(this.month), 2); },
d: function () { return pad.call(abs(this.day), 2); },
H: function () { return pad.call(abs(this.hour), 2); },
M: function () { return pad.call(abs(this.minute), 2); },
S: function () { return pad.call(abs(this.second), 2); },
L: function () { return pad.call(abs(this.millisecond), 3); },
ms: function () { return String(abs(this.months)); },
ds: function () { return String(abs(this.days)); },
Hs: function () { return String(abs(this.hours)); },
Ms: function () { return String(abs(this.minutes)); },
Ss: function () { return String(abs(this.seconds)); },
Ls: function () { return String(abs(this.milliseconds)); },
sign: function () { return (this.to < this.from) ? '-' : ''; }
});
getCalcData = function (duration) {
return (duration.to < duration.from) ?
{ to: duration.from, from: duration.to, sign: -1 } :
{ to: duration.to, from: duration.from, sign: 1 };
};
Duration = module.exports = function (from, to) {
// Make it both constructor and factory
if (!(this instanceof Duration)) return new Duration(from, to);
this.from = date(from);
this.to = (to == null) ? new Date() : date(to);
};
Duration.prototype = Object.create(Object.prototype, {
valueOf: d(valueOf = function () { return this.to - this.from; }),
millisecond: d.gs(function () { return this.milliseconds % 1000; }),
second: d.gs(function () { return this.seconds % 60; }),
minute: d.gs(function () { return this.minutes % 60; }),
hour: d.gs(function () { return this.hours % 24; }),
day: d.gs(function () {
var data = getCalcData(this)
, x = copy.call(data.to);
x.setMonth(x.getMonth() - 1);
x = daysInMonth.call(x);
return data.sign * ((x - data.from.getDate() + data.to.getDate()) % x -
((data.from - dfloor.call(copy.call(data.from))) >
(data.to - dfloor.call(copy.call(data.to)))));
}),
month: d.gs(function () {
var data = getCalcData(this);
return data.sign * ((12 - data.from.getMonth() + data.to.getMonth()) % 12 -
((data.from - mfloor.call(copy.call(data.from))) >
(data.to - mfloor.call(copy.call(data.to)))));
}),
year: d.gs(getYear = function () {
var data = getCalcData(this);
return data.sign * (data.to.getFullYear() - data.from.getFullYear() -
((data.from - yfloor.call(copy.call(data.from))) >
(data.to - yfloor.call(copy.call(data.to)))));
}),
milliseconds: d.gs(valueOf, null),
seconds: d.gs(function () { return toInteger(this.valueOf() / 1000); }),
minutes: d.gs(function () {
return toInteger(this.valueOf() / (1000 * 60));
}),
hours: d.gs(function () {
return toInteger(this.valueOf() / (1000 * 60 * 60));
}),
days: d.gs(function () {
return toInteger(this.valueOf() / (1000 * 60 * 60 * 24));
}),
months: d.gs(function () {
var data = getCalcData(this);
return data.sign * ((data.to.getFullYear() - data.from.getFullYear()) * 12 +
data.to.getMonth() - data.from.getMonth() -
((data.from - mfloor.call(copy.call(data.from))) >
(data.to - mfloor.call(copy.call(data.to)))));
}),
years: d.gs(getYear),
toString: d(function (pattern/*, threshold*/) {
var s, threshold, last;
if (pattern == null) pattern = 0;
if (isNaN(pattern)) return format.call(this, pattern);
pattern = Number(pattern);
threshold = toPosInt(arguments[1]);
s = "";
if (pattern === 1) {
if (threshold-- <= 0) s += abs(last = this.millisecond) + "ms";
if (this.seconds || (threshold >= 0)) {
if (threshold-- <= 0) {
s = abs(last = this.second) + "s" + (s ? " " : "") + s;
}
if (this.minutes || (threshold >= 0)) {
if (threshold-- <= 0) {
s = abs(last = this.minute) + "m" + (s ? " " : "") + s;
}
if (this.hours || (threshold >= 0)) {
if (threshold-- <= 0) {
s = abs(last = this.hour) + "h" + (s ? " " : "") + s;
}
if (this.days || (threshold >= 0)) {
if (threshold-- <= 0) {
s = abs(last = this.day) + "d" + (s ? " " : "") + s;
}
if (this.months || (threshold >= 0)) {
if (threshold-- <= 0) {
s = abs(last = this.month) + "m" + (s ? " " : "") + s;
}
if (this.years || (threshold >= 0)) {
s = abs(last = this.year) + "y" +
(s ? " " : "") + s;
}
}
}
}
}
}
} else {
if (threshold-- <= 0) {
s += "." + pad.call(abs(last = this.millisecond), 3);
}
if (this.seconds || (threshold >= 0)) {
if (threshold-- <= 0) {
last = this.second;
s = (this.minutes ? pad.call(abs(last), 2) :
abs(last)) + s;
}
if (this.minutes || (threshold >= 0)) {
if (threshold-- <= 0) {
last = this.minute;
s = ((this.hours || s) ? pad.call(abs(last), 2) : abs(last)) +
(s ? ":" : "") + s;
}
if (this.hours || (threshold >= 0)) {
if (threshold-- <= 0) {
s = pad.call(abs(last = this.hour), 2) + (s ? ":" : "") + s;
}
if (this.days || (threshold >= 0)) {
if (threshold-- <= 0) {
s = abs(last = this.day) + "d" + (s ? " " : "") + s;
}
if (this.months || (threshold >= 0)) {
if (threshold-- <= 0) {
s = abs(last = this.month) + "m" + (s ? " " : "") + s;
}
if (this.years || (threshold >= 0)) {
s = abs(last = this.year) + "y" +
(s ? " " : "") + s;
}
}
}
}
}
}
}
if (last && (this.to < this.from)) (s = '-' + s);
return s;
})
});