Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Format feature #131

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Detailed API documentation can be found at: http://gf3.github.io/moment-range/Da
- [Compare](#compare)
- [Equality](#equality)
- [Difference](#difference)
- [Format](#format)
- [Conversion](#conversion)
- [`toArray`](#toarray)
- [`toDate`](#todate)
Expand Down Expand Up @@ -232,6 +233,23 @@ dr.diff('days'); // 92
dr.diff(); // 7945200000
```

### Format

Similar to [moment.js' `format`
method](http://momentjs.com/docs/#/displaying/format/) with slightly different tokens.

``` javascript
var start = new Date(2011, 2, 5, 15);
var end = new Date(2011, 2, 5, 20);
moment.range(start, end).format(); // "March 5, 2011 3:00 PM ‒ 8:00 PM"
moment.range(start, end).format({ showTime: false }); // "March 5, 2011"
moment.range(start, null).format({ showTime: false }); // "From March 5, 2011"
moment.range(null, end).format({ showTime: false }); // "To March 5, 2011"
moment.range(start, end).format({ collapse: 'none' }); // "March 5, 2011 3:00 PM — March 5, 2011 8:00 PM"
moment.range(start, end).format({ collapse: 'year' }); // "March 5 3:00 PM — March 5 8:00 PM, 2011"
moment.range(start, end).format("1{Do MMMM} — 2{Do MMMM}"); // "5th March — 5th March"
```

### Conversion

#### `toArray`
Expand Down
103 changes: 100 additions & 3 deletions dist/moment-range.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
// like Node.
module.exports = factory(require("moment"));
} else {
root['DateRange'] = factory(moment);
root['DateRange'] = factory(root["moment"]);
}
}(this, function (moment) {

Expand All @@ -30,6 +30,24 @@ var INTERVALS = {
second: true
};

var DATE_RANGE_FORMATS = {
DR: "1{LL} — 2{LL}",
DRT: "1{LLL} — 2{LLL}",
DRY: "1{MMMM D} — 2{MMMM D, YYYY}",
DRYT: "1{MMMM D LT} — 2{MMMM D LT, YYYY}",
DRM: "1{MMMM D} ‒ 2{D, YYYY}",
DRMT: "1{MMMM D LT} — 2{MMMM D LT, YYYY}",
DRD: "1{MMMM D, YYYY}",
DRDT: "1{MMMM D, YYYY} 1{LT} ‒ 2{LT}",
DRS: "[From] LL",
DRST: "[From] LLL",
DRE: "[To] LL",
DRET: "[To] LLL"
};

var MIN_TIMESTAMP = -8640000000000000,
MAX_TIMESTAMP = 8640000000000000;


//-----------------------------------------------------------------------------
// Date Ranges
Expand Down Expand Up @@ -69,8 +87,8 @@ function DateRange(start, end) {
}
}

this.start = (s === null) ? moment(-8640000000000000) : moment(s);
this.end = (e === null) ? moment(8640000000000000) : moment(e);
this.start = (s === null) ? moment(MIN_TIMESTAMP) : moment(s);
this.end = (e === null) ? moment(MAX_TIMESTAMP) : moment(e);
}

/**
Expand Down Expand Up @@ -275,6 +293,85 @@ function _byRange(interval, hollaback, exclusive) {
}
}

/**
* Date range with nice formatting
*
* @param {(Object|String)} options list or format
* @param {String} options.collapse Collapse depth. Can be 'year', 'month', 'date' or 'none'
* @param {boolean} options.showTime Show time
* @param {boolean} options.openRange Format open ranges
*
* @return {!String}
*/
DateRange.prototype.format = function(opts) {
if (typeof opts === "string") {
opts = { format: opts };
} else if (typeof opts === "undefined") {
opts = {};
}
var options = Object.assign({
collapse: 'date',
showTime: true,
openRange: true
}, opts);

var start = this.start,
end = this.end;

var hasStart = options.openRange && !start.isSame(MIN_TIMESTAMP),
hasEnd = options.openRange && !end.isSame(MAX_TIMESTAMP);

var sameYear = (start.year() == end.year()),
sameMonth = sameYear && (start.month() == end.month()),
sameDate = sameMonth && (start.date() == end.date());

if (!options.format) {
var f = 'DR';
if (hasStart && !hasEnd) {
f += 'S';
} else if (!hasStart && hasEnd) {
f += 'E';
} else switch (options.collapse) {
case 'date':
if (sameDate) {
f += 'D';
break;
}
case 'month':
if (sameMonth) {
f += 'M';
break;
}
case 'year':
if (sameYear) {
f += 'Y';
break;
}
}
if (options.showTime) {
f += 'T';
}
var formats = moment.localeData()._dateRangeFormat;
options.format = (formats && formats.hasOwnProperty(f)) ? formats[f] : DATE_RANGE_FORMATS[f];
}
options.format = options.format.replace(/\[.*?\]|1\{(.+?)\}/g, function(m, g) {
if (!g) return m;
return "[[]" + g + "[]]";
}).replace(/\[.*?\]|2\{(.+?)\}/g, function(m, g) {
if (!g) return m;
return "[" + g + "]";
});

var res = '';
if (hasStart) {
res = start.format(res || options.format);
}
if (hasEnd) {
res = end.format(res || options.format);
}
return res;
};

/**
* Date range formatted as an [ISO8601 Time
* Interval](http://en.wikipedia.org/wiki/ISO_8601#Time_intervals).
Expand Down
2 changes: 1 addition & 1 deletion dist/moment-range.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

101 changes: 99 additions & 2 deletions lib/moment-range.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,24 @@ const INTERVALS = {
second: true
};

const DATE_RANGE_FORMATS = {
DR: "1{LL} — 2{LL}",
DRT: "1{LLL} — 2{LLL}",
DRY: "1{MMMM D} — 2{MMMM D, YYYY}",
DRYT: "1{MMMM D LT} — 2{MMMM D LT, YYYY}",
DRM: "1{MMMM D} ‒ 2{D, YYYY}",
DRMT: "1{MMMM D LT} — 2{MMMM D LT, YYYY}",
DRD: "1{MMMM D, YYYY}",
DRDT: "1{MMMM D, YYYY} 1{LT} ‒ 2{LT}",
DRS: "[From] LL",
DRST: "[From] LLL",
DRE: "[To] LL",
DRET: "[To] LLL"
};

const MIN_TIMESTAMP = -8640000000000000,
MAX_TIMESTAMP = 8640000000000000;


//-----------------------------------------------------------------------------
// Date Ranges
Expand Down Expand Up @@ -53,8 +71,8 @@ function DateRange(start, end) {
}
}

this.start = (s === null) ? moment(-8640000000000000) : moment(s);
this.end = (e === null) ? moment(8640000000000000) : moment(e);
this.start = (s === null) ? moment(MIN_TIMESTAMP) : moment(s);
this.end = (e === null) ? moment(MAX_TIMESTAMP) : moment(e);
}

/**
Expand Down Expand Up @@ -259,6 +277,85 @@ function _byRange(interval, hollaback, exclusive) {
}
}

/**
* Date range with nice formatting
*
* @param {(Object|String)} options list or format
* @param {String} options.collapse Collapse depth. Can be 'year', 'month', 'date' or 'none'
* @param {boolean} options.showTime Show time
* @param {boolean} options.openRange Format open ranges
*
* @return {!String}
*/
DateRange.prototype.format = function(opts) {
if (typeof opts === "string") {
opts = { format: opts };
} else if (typeof opts === "undefined") {
opts = {};
}
var options = Object.assign({
collapse: 'date',
showTime: true,
openRange: true
}, opts);

var start = this.start,
end = this.end;

var hasStart = options.openRange && !start.isSame(MIN_TIMESTAMP),
hasEnd = options.openRange && !end.isSame(MAX_TIMESTAMP);

var sameYear = (start.year() == end.year()),
sameMonth = sameYear && (start.month() == end.month()),
sameDate = sameMonth && (start.date() == end.date());

if (!options.format) {
var f = 'DR';
if (hasStart && !hasEnd) {
f += 'S';
} else if (!hasStart && hasEnd) {
f += 'E';
} else switch (options.collapse) {
case 'date':
if (sameDate) {
f += 'D';
break;
}
case 'month':
if (sameMonth) {
f += 'M';
break;
}
case 'year':
if (sameYear) {
f += 'Y';
break;
}
}
if (options.showTime) {
f += 'T';
}
var formats = moment.localeData()._dateRangeFormat;
options.format = (formats && formats.hasOwnProperty(f)) ? formats[f] : DATE_RANGE_FORMATS[f];
}
options.format = options.format.replace(/\[.*?\]|1\{(.+?)\}/g, function(m, g) {
if (!g) return m;
return "[[]" + g + "[]]";
}).replace(/\[.*?\]|2\{(.+?)\}/g, function(m, g) {
if (!g) return m;
return "[" + g + "]";
});

var res = '';
if (hasStart) {
res = start.format(res || options.format);
}
if (hasEnd) {
res = end.format(res || options.format);
}
return res;
};

/**
* Date range formatted as an [ISO8601 Time
* Interval](http://en.wikipedia.org/wiki/ISO_8601#Time_intervals).
Expand Down
48 changes: 42 additions & 6 deletions test/moment-range.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,14 +94,14 @@ describe('DateRange', function() {
m1.isSame(dr.start).should.be.true;
m2.isSame(dr.end).should.be.true;
});

it('should allow initialization with open-ended ranges', function() {
var dr = moment.range(null, m1);

moment.isMoment(dr.start).should.be.true;

dr = moment.range(m1, null);

moment.isMoment(dr.end).should.be.true;
});

Expand Down Expand Up @@ -708,10 +708,46 @@ describe('DateRange', function() {
});
});

describe('#format()', function() {
var firstMonth = moment.months(0);
var secondMonth = moment.months(1);

var sameNone = moment.range('2016-01-01 12:00:00', '2017-02-02 15:00:00');
var sameYear = moment.range('2016-01-01 12:00:00', '2016-02-02 15:00:00');
var sameMont = moment.range('2016-01-01 12:00:00', '2016-01-02 15:00:00');
var sameDate = moment.range('2016-01-01 12:00:00', '2016-01-01 15:00:00');

var noStart = moment.range(null, '2016-01-01 12:00:00');
var noEnd = moment.range('2016-01-01 12:00:00', null);

it('should collapse dates by default', function() {
sameNone.format({ showTime: false }).should.eql(firstMonth + ' 1, 2016 — ' + secondMonth + ' 2, 2017');
sameYear.format({ showTime: false }).should.eql(firstMonth + ' 1 — ' + secondMonth + ' 2, 2016');
sameMont.format({ showTime: false }).should.eql(firstMonth + ' 1 ‒ 2, 2016');
sameDate.format({ showTime: false }).should.eql(firstMonth + ' 1, 2016');
sameDate.format().should.eql(firstMonth + ' 1, 2016 12:00 PM ‒ 3:00 PM');
});

it('should not collapse all when option is specified', function() {
sameDate.format({ showTime: false, collapse: 'year' }).should.eql(firstMonth + ' 1 — ' + firstMonth + ' 1, 2016');
sameDate.format({ showTime: false, collapse: 'month' }).should.eql(firstMonth + ' 1 ‒ 1, 2016');
});

it('should work with custom formats', function() {
sameNone.format('1{DD MMMM} - 2{DD MMMM}').should.eql('01 January - 02 February');
});

it('should work with open ranges', function() {
noStart.format().should.eql('To ' + firstMonth + ' 1, 2016 12:00 PM');
noEnd.format().should.eql('From ' + firstMonth + ' 1, 2016 12:00 PM');
noEnd.format({ showTime: false }).should.eql('From ' + firstMonth + ' 1, 2016');
});
});

describe('#toString()', function() {
it('should be a correctly formatted ISO8601 Time Interval', function() {
var start = '2015-01-17T09:50:04+00:00';
var end = '2015-04-17T08:29:55+00:00';
var start = '2015-01-17T09:50:04Z';
var end = '2015-04-17T08:29:55Z';
var dr = moment.range(moment.utc(start), moment.utc(end));

dr.toString().should.equal(start + '/' + end);
Expand Down