(function(root, factory) { if(typeof exports === 'object') { module.exports = factory(require('moment')); } else if(typeof define === 'function' && define.amd) { define('moment-range', ['moment'], factory); } else { root.moment = factory(root.moment); } }(this, function(moment) { var DateRange, INTERVALS; INTERVALS = { year: true, month: true, week: true, day: true, hour: true, minute: true, second: true }; /** * DateRange class to store ranges and query dates. * @typedef {!Object} * */ DateRange = (function() { /** * DateRange instance. * @param {(Moment|Date)} start Start of interval. * @param {(Moment|Date)} end End of interval. * @constructor * */ function DateRange(start, end) { this.start = moment(start); this.end = moment(end); } /** * Determine if the current interval contains a given moment/date/range. * @param {(Moment|Date|DateRange)} other Date to check. * @return {!boolean} * */ DateRange.prototype.contains = function(other) { if (other instanceof DateRange) { return this.start <= other.start && this.end >= other.end; } else { return (this.start <= other && other <= this.end); } }; /** * @private * */ DateRange.prototype._by_string = function(interval, hollaback) { var current, _results; current = moment(this.start); _results = []; while (this.contains(current)) { hollaback.call(this, current.clone()); _results.push(current.add(interval, 1)); } return _results; }; /** * @private * */ DateRange.prototype._by_range = function(range_interval, hollaback) { var i, l, _i, _results; l = Math.round(this / range_interval); if (l === Infinity) { return this; } _results = []; for (i = _i = 0; 0 <= l ? _i <= l : _i >= l; i = 0 <= l ? ++_i : --_i) { _results.push(hollaback.call(this, moment(this.start.valueOf() + range_interval.valueOf() * i))); } return _results; }; /** * Determine if the current date range overlaps a given date range. * @param {!DateRange} range Date range to check. * @return {!boolean} * */ DateRange.prototype.overlaps = function(range) { return this.intersect(range) !== null; }; /** * Determine the intersecting periods from one or more date ranges. * @param {!DateRange} other A date range to intersect with this one. * @return {!DateRange|null} * */ DateRange.prototype.intersect = function(other) { var _ref, _ref1, _ref2, _ref3, _ref4, _ref5, _ref6, _ref7; if (((this.start <= (_ref1 = other.start) && _ref1 < (_ref = this.end)) && _ref < other.end)) { return new DateRange(other.start, this.end); } else if (((other.start < (_ref3 = this.start) && _ref3 < (_ref2 = other.end)) && _ref2 <= this.end)) { return new DateRange(this.start, other.end); } else if (((other.start < (_ref5 = this.start) && _ref5 < (_ref4 = this.end)) && _ref4 < other.end)) { return this; } else if (((this.start <= (_ref7 = other.start) && _ref7 < (_ref6 = other.end)) && _ref6 <= this.end)) { return other; } else { return null; } }; /** * Subtract one range from another. * @param {!DateRange} other A date range to substract from this one. * @return {!DateRange[]} * */ DateRange.prototype.subtract = function(other) { var _ref, _ref1, _ref2, _ref3, _ref4, _ref5, _ref6, _ref7; if (this.intersect(other) === null) { return [this]; } else if (((other.start <= (_ref1 = this.start) && _ref1 < (_ref = this.end)) && _ref <= other.end)) { return []; } else if (((other.start <= (_ref3 = this.start) && _ref3 < (_ref2 = other.end)) && _ref2 < this.end)) { return [new DateRange(other.end, this.end)]; } else if (((this.start < (_ref5 = other.start) && _ref5 < (_ref4 = this.end)) && _ref4 <= other.end)) { return [new DateRange(this.start, other.start)]; } else if (((this.start < (_ref7 = other.start) && _ref7 < (_ref6 = other.end)) && _ref6 < this.end)) { return [new DateRange(this.start, other.start), new DateRange(other.end, this.end)]; } }; /** * Iterate over the date range by a given date range, executing a function * for each sub-range. * @param {!DateRange|String} range Date range to be used for iteration * or shorthand string (shorthands: * http://momentjs.com/docs/#/manipulating/add/) * @param {!function(Moment)} hollaback Function to execute for each sub-range. * @return {!boolean} * */ DateRange.prototype.by = function(range, hollaback) { if (typeof range === 'string') { this._by_string(range, hollaback); } else { this._by_range(range, hollaback); } return this; }; /** * Date range in milliseconds. Allows basic coercion math of date ranges. * @return {!number} * */ DateRange.prototype.valueOf = function() { return this.end - this.start; }; /** * Date range toDate * @return {!Array} * */ DateRange.prototype.toDate = function() { return [this.start.toDate(), this.end.toDate()]; }; /** * Determine if this date range is the same as another. * @param {!DateRange} other Another date range to compare to. * @return {!boolean} * */ DateRange.prototype.isSame = function(other) { return this.start.isSame(other.start) && this.end.isSame(other.end); }; /** * Return the difference of the end vs start. * - To get the difference in milliseconds, use range#diff * - To get the difference in another unit of measurement, pass that measurement as the second argument. * @return milliseconds if no measure is passed in, otherwise an increment of measure * */ DateRange.prototype.diff = function(unit) { if (unit == null) { unit = void 0; } return this.end.diff(this.start, unit); }; return DateRange; })(); /** * Build a date range. * @param {(Moment|Date)} start Start of range. * @param {(Moment|Date)} end End of range. * @this {Moment} * @return {!DateRange} * */ moment.fn.range = function(start, end) { if (start in INTERVALS) { return new DateRange(moment(this).startOf(start), moment(this).endOf(start)); } else { return new DateRange(start, end); } }; /** * Build a date range. * @param {(Moment|Date)} start Start of range. * @param {(Moment|Date)} end End of range. * @this {Moment} * @return {!DateRange} * */ moment.range = function(start, end) { return new DateRange(start, end); }; /** * Check if the current moment is within a given date range. * @param {!DateRange} range Date range to check. * @this {Moment} * @return {!boolean} * */ moment.fn.within = function(range) { return range.contains(this._d); }; return moment; }));