moment-holiday
Advanced tools
Comparing version 1.2.0 to 1.3.0
@@ -9,4 +9,18 @@ # Changelog | ||
## [1.3.0] - TBA | ||
### Added | ||
- Support for holidays that span multiple days. | ||
- Support for "The [Weekday] on or before/after [Day]". | ||
- Support for year specific holidays. | ||
- Locale functionality. | ||
- Easter and Canadian locales. | ||
- Documentation on `modifyHolidays.extendParser` function. | ||
### Changed | ||
- `moment().modifyHolidays` to `moment.modifyHolidays`. | ||
- Made `moment.modifyHolidays` functions chainable. | ||
## [1.2.0] - 2017-07-17 | ||
## Added | ||
### Added | ||
- `modifyHolidays.extendParser` function. | ||
@@ -16,3 +30,3 @@ | ||
## [1.1.1] - 2017-07-17 | ||
## Changed | ||
### Changed | ||
- `previousHoliday` and `nextHoliday` functions will return a single moment object if `count` is set to `1`. | ||
@@ -38,4 +52,5 @@ | ||
[Unreleased]: https://github.com/kodie/moment-holiday/compare/v1.0.0...HEAD | ||
[1.3.0]: https://github.com/kodie/moment-holiday/compare/v1.2.1...v1.3.0 | ||
[1.2.0]: https://github.com/kodie/moment-holiday/compare/v1.1.1...v1.2.0 | ||
[1.1.1]: https://github.com/kodie/moment-holiday/compare/v1.1.0...v1.1.1 | ||
[1.1.0]: https://github.com/kodie/moment-holiday/compare/v1.0.0...v1.1.0 |
//! moment-holiday.js | ||
//! version : 1.2.0 | ||
//! version : 1.3.0 | ||
//! author : Kodie Grantham | ||
//! license : MIT | ||
//! github.com/kodie/moment-holiday | ||
//! https://github.com/kodie/moment-holiday | ||
@@ -10,3 +10,7 @@ (function() { | ||
moment.holidays = { | ||
var holidayObject = {}; | ||
moment.holidays = {}; | ||
moment.holidays.us = { | ||
"New Year's Day": { | ||
@@ -52,3 +56,3 @@ date: '1/1', | ||
date: '9/(1,1)', | ||
keywords_y: ['labor'] | ||
keywords_y: ['labor', 'labour'] | ||
}, | ||
@@ -97,48 +101,121 @@ "Columbus Day": { | ||
var parseHoliday = function(self, date, adjust) { | ||
var m; | ||
var days = []; | ||
for (var i = 0; i < parserExtensions.length; i++) { | ||
if (pe = parserExtensions[i](self, date)) { m = pe; } | ||
var pe = parserExtensions[i](self, date); | ||
if (pe === false) { return false; } | ||
if (pe) { days = pe; } | ||
} | ||
if (!moment.isMoment(m)) { | ||
m = moment(self); | ||
date = date.split('/'); | ||
m.month((parseInt(date[0]) - 1)); | ||
if (!moment.isMoment(days) && !days.length) { | ||
var range = false; | ||
var dates = date.split('|'); | ||
if (date[1].charAt(0) == '(') { | ||
var w = date[1].slice(1, -1).split(','); | ||
var wd = parseInt(w[0]); | ||
var dt = parseInt(w[1]); | ||
var d = moment(m).startOf('month'); | ||
var limit = (moment(m).endOf('month').diff(d, 'days') + 1); | ||
var days = []; | ||
if (dates.length > 1) { range = true; } | ||
if (dates.length > 2) { dates = [dates[0], dates[1]]; } | ||
for (var i = 0; i < limit; i++) { | ||
if (d.day() === wd) { days.push(moment(d)); } | ||
d.add(1, 'day'); | ||
for (var i = 0; i < dates.length; i++) { | ||
var m = moment(self); | ||
var ds = dates[i].split('/'); | ||
if (ds.length === 1 || (ds.length === 2 && ds[1].charAt(0) !== '(' && ds[1].length === 4)) { | ||
var td = dates[i]; | ||
i = -1; | ||
dates = []; | ||
for (var ii = 1; ii < 13; ii++) { dates.push(ii + '/' + td); } | ||
continue; | ||
} | ||
if (dt < 0) { | ||
m = days[days.length + dt]; | ||
if (ds.length > 2) { m.year(parseInt(ds[2])); } | ||
m.month((parseInt(ds[0]) - 1)); | ||
if (ds[1].charAt(0) === '(') { | ||
var w = ds[1].slice(1, -1).split(','); | ||
var wd = parseInt(w[0]); | ||
var dt = parseInt(w[1]); | ||
var d = moment(m).startOf('month'); | ||
var limit = (moment(m).endOf('month').diff(d, 'days') + 1); | ||
var wds = []; | ||
if (w[1] && w[1].charAt(0) === '[') { | ||
var forward = true; | ||
dt = parseInt(w[1].slice(1, -1)); | ||
if (dt < 0) { | ||
forward = false; | ||
dt = parseInt(w[1].slice(2, -1)); | ||
} | ||
d = moment(m).date(dt); | ||
for (var wi = 0; wi < 6; wi++) { | ||
if (d.day() === wd) { days.push(moment(d)); break; } | ||
if (forward) { | ||
d.add(1, 'day'); | ||
} else { | ||
d.subtract(1, 'day'); | ||
} | ||
} | ||
continue; | ||
} | ||
for (var ai = 0; ai < limit; ai++) { | ||
if (d.day() === wd) { wds.push(moment(d)); } | ||
d.add(1, 'day'); | ||
} | ||
if (!dt) { | ||
days = days.concat(wds); | ||
continue; | ||
} else if (dt < 0) { | ||
m = wds[wds.length + dt]; | ||
} else { | ||
m = wds[dt - 1]; | ||
} | ||
days.push(m); | ||
} else { | ||
m = days[dt - 1]; | ||
days.push(m.date(ds[1])); | ||
} | ||
} else { | ||
m.date(date[1]); | ||
} | ||
if (range && days.length > 1) { | ||
var diff = days[1].diff(days[0], 'days'); | ||
if (diff > 1) { | ||
var di = moment(days[0]); | ||
days = [days[0]]; | ||
for (var i = 0; i < diff; i++) { | ||
di.add(1, 'day'); | ||
days.push(moment(di)); | ||
} | ||
} | ||
} | ||
} | ||
if (!moment.isMoment(m)) { return false; } | ||
days = arrayify(days); | ||
if (adjust) { | ||
if (m.day() == 0) { m.add(1, 'day'); } | ||
if (m.day() == 6) { m.subtract(1, 'day'); } | ||
for (var i = 0; i < days.length; i++) { | ||
if (!moment.isMoment(days[i])) { delete(days[i]); continue; } | ||
if (adjust) { | ||
if (days[i].day() === 0) { days[i] = days[i].add(1, 'day'); } | ||
if (days[i].day() === 6) { days[i] = days[i].subtract(1, 'day'); } | ||
} | ||
days[i] = days[i].startOf('day'); | ||
} | ||
return m.startOf('day'); | ||
if (!days.length) { return false; } | ||
if (days.length === 1) { return days[0]; } | ||
return days; | ||
}; | ||
var findHoliday = function(self, holiday, adjust, parse) { | ||
var h = moment.holidays; | ||
var h = holidayObject; | ||
var pt = {}; | ||
@@ -201,3 +278,3 @@ var wn = []; | ||
var getAllHolidays = function(self, adjust) { | ||
var h = moment.holidays; | ||
var h = holidayObject; | ||
var d = {}; | ||
@@ -241,8 +318,15 @@ | ||
for (var hd in h) { | ||
if (d.isSame(h[hd], 'day')) { | ||
w.push(h[hd]); | ||
l = moment(d); | ||
b = true; | ||
break; | ||
var b2 = false; | ||
var ha = arrayify(h[hd]); | ||
for (var hi = 0; hi < ha.length; hi++) { | ||
if (d.isSame(ha[hi], 'day')) { | ||
w.push(ha[hi]); | ||
l = moment(d); | ||
b2 = true; | ||
break; | ||
} | ||
} | ||
if (b2) { b = true; break; } | ||
} | ||
@@ -260,4 +344,9 @@ | ||
var arrayify = function(arr) { | ||
if (arr && arr.constructor !== Array) { return [arr]; } | ||
return arr; | ||
}; | ||
moment.fn.holiday = function(holidays, adjust) { | ||
var h = moment.holidays; | ||
var h = holidayObject; | ||
var d = {}; | ||
@@ -280,3 +369,3 @@ var single = false; | ||
if (!dKeys.length) { return false; } | ||
if (single) { return d[dKeys[0]]; } | ||
if (dKeys.length === 1 && single) { return d[dKeys[0]]; } | ||
@@ -291,18 +380,28 @@ return d; | ||
moment.fn.isHoliday = function(holidays, adjust) { | ||
var h, returnTitle; | ||
if (holidays) { | ||
if (holidays.constructor !== Array) { holidays = [holidays]; } | ||
holidays = arrayify(holidays); | ||
h = this.holiday(holidays, adjust); | ||
returnTitle = false; | ||
} else { | ||
h = getAllHolidays(this, adjust); | ||
returnTitle = true; | ||
} | ||
var h = this.holiday(holidays, adjust); | ||
if (!h) { return false; } | ||
if (!h) { return false; } | ||
for (var hd in h) { | ||
if (!h.hasOwnProperty(hd)) { continue; } | ||
if (this.isSame(h[hd], 'day')) { return true; } | ||
} | ||
} else { | ||
var h = getAllHolidays(this, adjust); | ||
for (var hd in h) { | ||
if (!h.hasOwnProperty(hd)) { continue; } | ||
for (var hd in h) { | ||
if (!h.hasOwnProperty(hd)) { continue; } | ||
if (this.isSame(h[hd], 'day')) { return hd; } | ||
var ha = arrayify(h[hd]); | ||
for (var hi = 0; hi < ha.length; hi++) { | ||
if (this.isSame(ha[hi], 'day')) { | ||
if (returnTitle) { | ||
return hd; | ||
} else { | ||
return true; | ||
} | ||
} | ||
} | ||
@@ -350,6 +449,14 @@ } | ||
for (var hd in h) { | ||
if (d.isSame(h[hd], 'day')) { | ||
w.push(h[hd]); | ||
break; | ||
var b = false; | ||
var ha = arrayify(h[hd]); | ||
for (var hi = 0; hi < ha.length; hi++) { | ||
if (d.isSame(ha[hi], 'day')) { | ||
w.push(ha[hi]); | ||
b = true; | ||
break; | ||
} | ||
} | ||
if (b) { break; } | ||
} | ||
@@ -363,3 +470,3 @@ } | ||
moment.fn.modifyHolidays = { | ||
moment.modifyHolidays = { | ||
set: function(holidays) { | ||
@@ -374,22 +481,51 @@ if (holidays.constructor === Array) { | ||
for (var hd in moment.holidays) { | ||
if (!moment.holidays.hasOwnProperty(hd)) { continue; } | ||
if (hs.indexOf(hd) === -1) { delete(moment.holidays[hd]); } | ||
for (var hd in holidayObject) { | ||
if (!holidayObject.hasOwnProperty(hd)) { continue; } | ||
if (hs.indexOf(hd) === -1) { delete(holidayObject[hd]); } | ||
} | ||
} else if (typeof holidays === 'string') { | ||
var locale = holidays.toLowerCase(); | ||
if (!moment.holidays[locale]) { | ||
try { | ||
require('./locale/' + locale); | ||
} catch(e) { } | ||
} | ||
if (moment.holidays[locale]) { holidayObject = moment.holidays[locale]; } | ||
} else { | ||
moment.holidays = holidays; | ||
holidayObject = holidays; | ||
} | ||
return this; | ||
}, | ||
add: function(holidays) { | ||
moment.holidays = Object.assign({}, moment.holidays, holidays); | ||
if (typeof holidays === 'string') { | ||
var locale = holidays.toLowerCase(); | ||
holidays = {}; | ||
if (!moment.holidays[locale]) { | ||
try { | ||
require('./locale/' + locale); | ||
} catch(e) { } | ||
} | ||
if (moment.holidays[locale]) { holidays = moment.holidays[locale]; } | ||
} | ||
holidayObject = Object.assign({}, holidayObject, holidays); | ||
return this; | ||
}, | ||
remove: function(holidays) { | ||
if (holidays.constructor !== Array) { holidays = [holidays]; } | ||
holidays = arrayify(holidays); | ||
for (i = 0; i < holidays.length; i++) { | ||
var d = findHoliday(this, holidays[i], null, false); | ||
if (d) { delete(moment.holidays[d]); } | ||
if (d) { delete(holidayObject[d]); } | ||
} | ||
return this; | ||
}, | ||
@@ -399,8 +535,9 @@ | ||
parserExtensions.push(func); | ||
return this; | ||
} | ||
}; | ||
if ((typeof module !== 'undefined' && module !== null ? module.exports : void 0) != null) { | ||
module.exports = moment; | ||
} | ||
moment.modifyHolidays.set('US').add('Easter'); | ||
if ((typeof module !== 'undefined' && module !== null ? module.exports : void 0) != null) { module.exports = moment; } | ||
}).call(this); |
{ | ||
"name": "moment-holiday", | ||
"version": "1.2.0", | ||
"version": "1.3.0", | ||
"description": "A Moment.js plugin for handling holidays.", | ||
@@ -27,2 +27,5 @@ "keywords": [ | ||
"main": "moment-holiday.js", | ||
"files": [ | ||
"locale/" | ||
], | ||
"dependencies": { | ||
@@ -32,7 +35,8 @@ "moment": ">=2.0.0" | ||
"devDependencies": { | ||
"ava": ">=0.10.0" | ||
"ava": ">=0.10.0", | ||
"jshint": ">=2.9.1" | ||
}, | ||
"scripts": { | ||
"test": "ava" | ||
"test": "./node_modules/.bin/jshint *.js **/*.js && ava" | ||
} | ||
} |
@@ -257,8 +257,12 @@ # moment-holiday [![npm version](https://badge.fury.io/js/moment-holiday.svg)](https://badge.fury.io/js/moment-holiday) [![Build Status](https://travis-ci.org/kodie/moment-holiday.svg?branch=master)](https://travis-ci.org/kodie/moment-holiday) | ||
Easter Sunday and Good Friday are also automatically included if you are using Node. (You can still easily add them in even when not using Node. See: [Modifying Holidays](#modifying-holidays)) | ||
### Modifying Holidays | ||
You can add and remove holidays by using the following helper functions: | ||
*Note: Helper functions can be chained.* | ||
#### modifyHolidays.set | ||
```javascript | ||
moment().modifyHolidays.set(['New Years Day', 'Memorial Day', 'Thanksgiving']); | ||
moment.modifyHolidays.set(['New Years Day', 'Memorial Day', 'Thanksgiving']); | ||
@@ -270,3 +274,3 @@ moment().holidays(); // Returns all holidays | ||
moment().modifyHolidays.set({ | ||
moment.modifyHolidays.set({ | ||
"My Birthday": { | ||
@@ -289,3 +293,3 @@ date: '11/17', | ||
```javascript | ||
moment().modifyHolidays.add({ | ||
moment.modifyHolidays.add({ | ||
"Inauguration Day": { | ||
@@ -303,10 +307,36 @@ date: '1/20', | ||
```javascript | ||
moment().modifyHolidays.remove('Christmas'); | ||
moment.modifyHolidays.remove('Christmas'); | ||
moment().modifyHolidays.remove(['Dad Day', 'Mom Day', 'Saint Paddys Day']); | ||
moment.modifyHolidays.remove(['Dad Day', 'Mom Day', 'Saint Paddys Day']); | ||
``` | ||
#### Adding/Setting Locales | ||
You can also use these functions to set or add holidays from an available locale file: | ||
```javascript | ||
moment.modifyHolidays.set('Canada').add('Easter'); | ||
moment('2001-12-26').isHoliday('Boxing Day'); | ||
//true | ||
moment.modifyHolidays.add('Easter').remove('Good Friday'); | ||
moment().holiday(['Easter Sunday', 'Good Friday']); | ||
//{ 'Easter Sunday': moment("2017-04-16T00:00:00.000") } | ||
``` | ||
*Note: If you're not using Node (or anything that doesn't support the `require` function), you'll need to make sure that you include the locale file(s) that you're trying to use. For example:* | ||
```html | ||
<script src="./moment-holiday/locale/canada.js"></script> | ||
<script src="./moment-holiday/locale/easter.js"></script> | ||
<script> | ||
moment.modifyHolidays.set('Canada').add('Easter'); | ||
moment('2001-12-26').isHoliday('Boxing Day'); | ||
//true | ||
</script> | ||
``` | ||
##### Holiday Objects | ||
Holiday objects accept the following options: | ||
* **date** *(Required)* - The date of the holiday in the format of `Month/Day`. A day wrapped in parentheses means a specific day of the week and expects two values separated by a comma. The first part is the day of the week as recognized by [moment().day()](https://momentjs.com/docs/#/get-set/day/) (0=Sunday, 6=Saturday). The second part is the 1-indexed index of that day of week. | ||
* **date** *(Required)* - The date of the holiday in the format of `Month/Day`. A day wrapped in parentheses `()` means a specific day of the week and expects two values separated by a comma `,`. The first part is the day of the week as recognized by [moment().day()](https://momentjs.com/docs/#/get-set/day/) (0=Sunday, 6=Saturday). The second part (optional) is the 1-indexed index of that day of week unless separated by brackets `[]` which means "The weekday on or before/after this day". Two dates separated by a vertical bar `|` means a date range. You may also specific a 4-digit year by adding an additional `/` after the day. | ||
@@ -317,2 +347,12 @@ Examples: | ||
* `3/(4,-1)` - The last Thursday of March. | ||
* `6/(2,[16])` - The Tuesday on or after the 16th of June. | ||
* `11/(5,[-9])` - The Friday on or before the 9th of November. | ||
* `8/21|9/4` - The 21st of August through the 4th of September. | ||
* `11` - The 11th of every month of the year. | ||
* `(0)` - Every Sunday of the year. | ||
* `10/(3)` - Every Wednesday in October. | ||
* `12/7/2014` - December 7th, 2014. | ||
* `(6)/2014` - Every Saturday of the year 2014. | ||
* `2/(1,1)|5/(5,-1)` - The first Monday of February through the last Friday of May. | ||
* `4/(3,[-11])|5/(0,1)` - The Wednesday on or before the 11th of March through the first Sunday of May. | ||
@@ -325,3 +365,46 @@ * **keywords** - An array of optional keywords. | ||
#### modifyHolidays.extendParser | ||
This is a handy little function that allows you to extend the functionality of the date parser. It accepts a single function as a variable that gets passed a moment object and the date string as variables. It can return a single moment object, an array of moment objects, `false` to bail on parsing, or nothing at all to continue with the default parser. | ||
Example: | ||
```javascript | ||
moment.modifyHolidays.add({ | ||
"Friday The Thirteenth": { | ||
date: 'fridaythethirteenth', | ||
keywords_y: ['friday'], | ||
keywords: ['thirteen', '13', 'the'] | ||
} | ||
}).extendParser(function(m, date){ | ||
if (date === 'fridaythethirteenth') { | ||
var days = []; | ||
for (i = 0; i < 12; i++) { | ||
var d = moment(m).month(i).date(13); | ||
if (d.day() === 5) { days.push(moment(d)); } | ||
} | ||
if (!days.length) { return false; } | ||
return days; | ||
} | ||
}); | ||
moment().holiday('Friday 13th'); | ||
//[ moment("2017-01-13T00:00:00.000"), | ||
// moment("2017-10-13T00:00:00.000") ] | ||
``` | ||
You can also see how we take advantage of this by viewing the source of [locale/easter.js](locale/easter.js). | ||
## Locales | ||
Locale files are simply files that add holidays and special holiday parsing functionality for other countries. They are all located in the `locale/` folder. | ||
Pull Requests will be accepted (and encouraged!) but must meet the following guidelines: | ||
* Must contain a `moment.holidays.[locale]` object matching the filename all in lowercase. | ||
* Example: `locale/japan.js` would need to have `moment.holidays.japan` in it. | ||
* Invalid: `local/Japan.js` or `moment.holidays.Japan` | ||
* Must pass `npm test`. | ||
See the source of [locale/canada.js](locale/canada.js) and [locale/easter.js](locale/easter.js) for good examples of locale files. | ||
## License | ||
MIT. See the License file for more info. |
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
32162
512
405
2
7
5