├── .npmignore ├── examples ├── react │ ├── build │ │ └── .gitignore │ ├── .gitignore │ ├── app.jsx │ ├── index.html │ ├── components │ │ ├── Week.jsx │ │ ├── Day.jsx │ │ └── Calendar.jsx │ └── package.json └── vue │ ├── build │ └── .gitignore │ ├── .gitignore │ ├── index.html │ ├── components │ ├── week.js │ ├── day.js │ └── calendar.js │ ├── package.json │ └── app.js ├── .gitignore ├── .travis.yml ├── test ├── .eslintrc ├── formatting.js ├── related-months.js ├── create.js └── calendar.js ├── .codeclimate.yml ├── CHANGELOG.md ├── src ├── index.js ├── enums.js ├── validate.js └── month.js ├── .editorconfig ├── .eslintrc ├── LICENSE.md ├── package.json └── README.md /.npmignore: -------------------------------------------------------------------------------- 1 | .idea 2 | examples 3 | -------------------------------------------------------------------------------- /examples/react/build/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /examples/vue/build/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /dist 2 | node_modules 3 | npm-debug.log 4 | -------------------------------------------------------------------------------- /examples/vue/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | -------------------------------------------------------------------------------- /examples/react/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 'stable' 4 | -------------------------------------------------------------------------------- /test/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "mocha": true 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /.codeclimate.yml: -------------------------------------------------------------------------------- 1 | engines: 2 | eslint: 3 | enabled: true 4 | ratings: 5 | paths: 6 | - src/**/* 7 | exclude_paths: 8 | - lib/**/* 9 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All Notable changes to `calendar-months` will be documented in this file 4 | 5 | ## 1.0.1 6 | - Initial release 7 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import { days, months } from './enums'; 2 | import Month from './month'; 3 | 4 | export default Month; 5 | 6 | export { 7 | days, 8 | Month, 9 | months, 10 | }; 11 | -------------------------------------------------------------------------------- /examples/react/app.jsx: -------------------------------------------------------------------------------- 1 | import Calendar from './components/Calendar'; 2 | import Month from 'calendar-months'; 3 | import React from 'react'; 4 | import { render } from 'react-dom'; 5 | 6 | render( 7 | , 8 | document.getElementById('calendar') 9 | ); 10 | -------------------------------------------------------------------------------- /examples/vue/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Calendar Months Vue 6 | 7 | 8 |
9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /examples/react/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Calendar Months React 6 | 7 | 8 |
9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /examples/vue/components/week.js: -------------------------------------------------------------------------------- 1 | import Day from './day'; 2 | 3 | export default { 4 | 5 | props: ['days', 'month'], 6 | 7 | template: ` 8 | 9 | 10 | 11 | 12 | 13 | `, 14 | 15 | components: { 16 | Day, 17 | }, 18 | 19 | }; 20 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | ; This file is for unifying the coding style for different editors and IDEs. 2 | ; More information at http://editorconfig.org 3 | 4 | root = true 5 | 6 | [*] 7 | charset = utf-8 8 | indent_size = 4 9 | indent_style = space 10 | end_of_line = lf 11 | insert_final_newline = true 12 | trim_trailing_whitespace = true 13 | 14 | [{package.json,*.scss}] 15 | indent_size = 2 16 | 17 | [*.md] 18 | trim_trailing_whitespace = false 19 | -------------------------------------------------------------------------------- /examples/react/components/Week.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import Day from './Day'; 3 | 4 | class Week extends Component { 5 | 6 | render() { 7 | return ( 8 | 9 | {this.props.days.map((day, i) => 10 | 11 | )} 12 | 13 | ); 14 | } 15 | } 16 | 17 | export default Week; 18 | -------------------------------------------------------------------------------- /examples/vue/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "lint": "eslint .", 4 | "build": "browserify app.js -o build/app.js -t [ babelify --presets [ es2015 ] ]" 5 | }, 6 | "dependencies": { 7 | "calendar-months": "^1.0.1", 8 | "moment": "^2.15.1", 9 | "vue": "^1.0.0" 10 | }, 11 | "devDependencies": { 12 | "babel-preset-es2015": "^6.9.0", 13 | "babelify": "^7.3.0", 14 | "browserify": "^13.0.1", 15 | "eslint": "^2.9.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/enums.js: -------------------------------------------------------------------------------- 1 | const months = { 2 | JANUARY: 0, 3 | FEBRUARY: 1, 4 | MARCH: 2, 5 | APRIL: 3, 6 | MAY: 4, 7 | JUNE: 5, 8 | JULY: 6, 9 | AUGUST: 7, 10 | SEPTEMBER: 8, 11 | OCTOBER: 9, 12 | NOVEMBER: 10, 13 | DECEMBER: 11, 14 | }; 15 | 16 | const days = { 17 | SUNDAY: 0, 18 | MONDAY: 1, 19 | TUESDAY: 2, 20 | WEDNESDAY: 3, 21 | THURSDAY: 4, 22 | FRIDAY: 5, 23 | SATURDAY: 6, 24 | }; 25 | 26 | export { months, days }; 27 | -------------------------------------------------------------------------------- /examples/vue/app.js: -------------------------------------------------------------------------------- 1 | import Calendar from './components/calendar'; 2 | import Month from 'calendar-months'; 3 | import Vue from 'vue'; 4 | 5 | new Vue({ 6 | 7 | el: '#calendar', 8 | 9 | template: ` 10 |
11 | 12 |
13 | `, 14 | 15 | components: { 16 | Calendar, 17 | }, 18 | 19 | data() { 20 | return { 21 | month: Month.now(), 22 | }; 23 | }, 24 | 25 | }); 26 | -------------------------------------------------------------------------------- /examples/react/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "lint": "eslint .", 4 | "build": "browserify app.jsx -o build/app.js --extension=.jsx -t [ babelify --presets [ es2015 react ] ]" 5 | }, 6 | "dependencies": { 7 | "calendar-months": "^1.0.1", 8 | "moment": "^2.15.1", 9 | "react": "^15.1.0", 10 | "react-dom": "^15.1.0" 11 | }, 12 | "devDependencies": { 13 | "babel-preset-es2015": "^6.9.0", 14 | "babel-preset-react": "^6.5.0", 15 | "babelify": "^7.3.0", 16 | "browserify": "^13.0.1", 17 | "eslint": "^2.9.0" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "comma-dangle": [2, "always-multiline"], 4 | "indent": [2, 4], 5 | "linebreak-style": [2, "unix"], 6 | "quotes": [2, "single"], 7 | "semi": [2, "always"], 8 | "sort-imports": ["error", { "ignoreCase": true }], 9 | "space-before-function-paren": ["error", { "anonymous": "always", "named": "never" }], 10 | "strict": [2, "never"] 11 | }, 12 | "parserOptions": { 13 | "ecmaVersion": 6, 14 | "sourceType": "module" 15 | }, 16 | "env": { 17 | "es6": true, 18 | "browser": true 19 | }, 20 | "extends": "eslint:recommended" 21 | } 22 | -------------------------------------------------------------------------------- /examples/vue/components/day.js: -------------------------------------------------------------------------------- 1 | import moment from 'moment'; 2 | 3 | export default { 4 | 5 | props: ['date', 'month'], 6 | 7 | template: ` 8 | 9 | {{ date.format('DD') }} 10 | 11 | `, 12 | 13 | computed: { 14 | color() { 15 | if (!this.isInCurrentMonth()) { 16 | return 'gray'; 17 | } 18 | 19 | if (this.isToday()) { 20 | return 'red'; 21 | } 22 | 23 | return ''; 24 | }, 25 | }, 26 | 27 | methods: { 28 | isToday() { 29 | return moment().isSame(this.date, 'day'); 30 | }, 31 | isInCurrentMonth() { 32 | return this.month.containsDay(this.date); 33 | }, 34 | }, 35 | 36 | }; 37 | -------------------------------------------------------------------------------- /examples/react/components/Day.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import moment from 'moment'; 3 | 4 | class Day extends Component { 5 | 6 | isToday() { 7 | return moment().isSame(this.props.date, 'day'); 8 | } 9 | 10 | isInCurrentMonth() { 11 | return this.props.month.containsDay(this.props.date); 12 | } 13 | 14 | get color() { 15 | if (!this.isInCurrentMonth()) { 16 | return 'gray'; 17 | } 18 | 19 | if (this.isToday()) { 20 | return 'red'; 21 | } 22 | 23 | return ''; 24 | } 25 | 26 | render() { 27 | return ( 28 | 29 | 30 | {this.props.date.format('DD')} 31 | 32 | 33 | ); 34 | } 35 | } 36 | 37 | export default Day; 38 | -------------------------------------------------------------------------------- /examples/vue/components/calendar.js: -------------------------------------------------------------------------------- 1 | import { days } from 'calendar-months'; 2 | import Week from './week'; 3 | 4 | export default { 5 | 6 | props: ['month'], 7 | 8 | template: ` 9 |
10 |

{{ month.format('MMMM YYYY') }}

11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |
MonTueWedThuFriSatSun
27 |
28 | `, 29 | 30 | components: { 31 | Week, 32 | }, 33 | 34 | computed: { 35 | weeks() { 36 | return this.month.calendarWeeks(days.MONDAY); 37 | }, 38 | }, 39 | 40 | }; 41 | -------------------------------------------------------------------------------- /examples/react/components/Calendar.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { days } from 'calendar-months'; 3 | import Week from './Week'; 4 | 5 | class Calendar extends Component { 6 | 7 | render() { 8 | return ( 9 |
10 |

{this.props.month.format('MMMM YYYY')}

11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | {this.props.month.calendarWeeks(days.MONDAY).map((week, i) => 25 | 26 | )} 27 | 28 |
MonTueWedThuFriSatSun
29 |
30 | ); 31 | } 32 | } 33 | 34 | export default Calendar; 35 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Spatie bvba 4 | 5 | > Permission is hereby granted, free of charge, to any person obtaining a copy 6 | > of this software and associated documentation files (the "Software"), to deal 7 | > in the Software without restriction, including without limitation the rights 8 | > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | > copies of the Software, and to permit persons to whom the Software is 10 | > furnished to do so, subject to the following conditions: 11 | > 12 | > The above copyright notice and this permission notice shall be included in 13 | > all copies or substantial portions of the Software. 14 | > 15 | > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | > THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/validate.js: -------------------------------------------------------------------------------- 1 | import moment from 'moment'; 2 | 3 | /** 4 | * Determine whether the object is a string. 5 | * 6 | * @param {mixed} object 7 | * 8 | * @return {bool} 9 | */ 10 | const isString = (object) => typeof object === 'string'; 11 | 12 | /** 13 | * Determine whether the object is an instance of Moment. 14 | * 15 | * @param {mixed} object 16 | * 17 | * @return {bool} 18 | */ 19 | const isMoment = (object) => moment.isMoment(object); 20 | 21 | /** 22 | * Determine whether the object is an instance of Date (JavaScript standard library). 23 | * 24 | * @param {mixed} object 25 | * 26 | * @return {bool} 27 | */ 28 | const isDate = (object) => object instanceof Date; 29 | 30 | /** 31 | * Determine whether a number is a valid month number (0-11). 32 | * 33 | * @param {number} number 34 | * 35 | * @return {bool} 36 | */ 37 | const isValidMonthNumber = (number) => (!isNaN(number) && number >= 0 && number <= 11); 38 | 39 | /** 40 | * Determine whether a number is a valid year number. 41 | * 42 | * @param {number} number 43 | * 44 | * @return {bool} 45 | */ 46 | const isValidYearNumber = (number) => !isNaN(number); 47 | 48 | export default { isString, isMoment, isDate, isValidMonthNumber, isValidYearNumber }; 49 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "calendar-months", 3 | "version": "1.0.1", 4 | "description": "Month class with specialized functions for generating calendar user interfaces", 5 | "main": "dist/index.js", 6 | "jsnext:main": "src/index.js", 7 | "scripts": { 8 | "test": "mocha --compilers js:babel-register", 9 | "lint": "eslint src test", 10 | "build": "babel src -d dist", 11 | "prepublish": "npm test && npm run build" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/spatie/calendar-months.git" 16 | }, 17 | "keywords": [ 18 | "spatie", 19 | "calendar", 20 | "date", 21 | "moment" 22 | ], 23 | "author": "Sebastian De Deyne", 24 | "license": "MIT", 25 | "bugs": { 26 | "url": "https://github.com/spatie/calendar-months/issues" 27 | }, 28 | "homepage": "https://github.com/spatie/calendar-months", 29 | "devDependencies": { 30 | "babel-cli": "^6.8.0", 31 | "babel-preset-es2015": "^6.3.13", 32 | "babel-register": "^6.4.3", 33 | "chai": "^3.4.1", 34 | "eslint": "^2.9.0", 35 | "mocha": "^2.4.5", 36 | "moment": "^2.10.6" 37 | }, 38 | "peerDependencies": { 39 | "moment": "^2.10.6" 40 | }, 41 | "babel": { 42 | "presets": [ 43 | "es2015" 44 | ] 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /test/formatting.js: -------------------------------------------------------------------------------- 1 | import Month, { months } from '../src/index'; 2 | import { assert } from 'chai'; 3 | 4 | describe('It can be formatted to', () => { 5 | 6 | it('YYYY-MM by default', () => { 7 | 8 | const cases = [ 9 | [ new Month(months.SEPTEMBER, 2015), '2015-09' ], 10 | [ new Month(months.FEBRUARY, 1992), '1992-02' ], 11 | [ new Month(months.DECEMBER, 2019), '2019-12' ], 12 | ]; 13 | 14 | cases.forEach(([ month, formatted ]) => { 15 | assert.equal(month.format(), formatted); 16 | }); 17 | }); 18 | 19 | it('anything your heart desires', () => { 20 | 21 | const cases = [ 22 | [ new Month(months.SEPTEMBER, 2015), '2015-09', '15-09', '2015-09-01', '01/09/2015' ], 23 | [ new Month(months.FEBRUARY, 1992), '1992-02', '92-02', '1992-02-01', '01/02/1992' ], 24 | [ new Month(months.DECEMBER, 2019), '2019-12', '19-12', '2019-12-01', '01/12/2019' ], 25 | ]; 26 | 27 | cases.forEach(([ month, plain, shortYear, withDay, backwardsWithSlashes ]) => { 28 | assert.equal(month.format('YYYY-MM'), plain); 29 | assert.equal(month.format('YY-MM'), shortYear); 30 | assert.equal(month.format('YYYY-MM-DD'), withDay); 31 | assert.equal(month.format('DD/MM/YYYY'), backwardsWithSlashes); 32 | }); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /test/related-months.js: -------------------------------------------------------------------------------- 1 | import Month, { months } from '../src/index'; 2 | import { assert } from 'chai'; 3 | 4 | describe('It returns returns a new instance for', () => { 5 | 6 | it('the current month through `thisMonth`', () => { 7 | 8 | const cases = [ 9 | [ new Month(months.SEPTEMBER, 2015), '2015-09' ], 10 | [ new Month(months.FEBRUARY, 1992), '1992-02' ], 11 | [ new Month(months.DECEMBER, 2019), '2019-12' ], 12 | ]; 13 | 14 | cases.forEach(([ month, result ]) => { 15 | assert.equal(month.thisMonth().format(), result); 16 | }); 17 | }); 18 | 19 | it('the current month through `clone`', () => { 20 | 21 | const cases = [ 22 | [ new Month(months.SEPTEMBER, 2015), '2015-09' ], 23 | [ new Month(months.FEBRUARY, 1992), '1992-02' ], 24 | [ new Month(months.DECEMBER, 2019), '2019-12' ], 25 | ]; 26 | 27 | cases.forEach(([ month, result ]) => { 28 | assert.equal(month.clone().format(), result); 29 | }); 30 | }); 31 | 32 | it('the next month', () => { 33 | 34 | const cases = [ 35 | [ new Month(months.SEPTEMBER, 2015), '2015-10' ], 36 | [ new Month(months.FEBRUARY, 1992), '1992-03' ], 37 | [ new Month(months.DECEMBER, 2019), '2020-01' ], 38 | ]; 39 | 40 | cases.forEach(([ month, result ]) => { 41 | assert.equal(month.nextMonth().format(), result); 42 | }); 43 | }); 44 | 45 | it('the last month', () => { 46 | 47 | const cases = [ 48 | [ new Month(months.SEPTEMBER, 2015), '2015-08' ], 49 | [ new Month(months.FEBRUARY, 1992), '1992-01' ], 50 | [ new Month(months.DECEMBER, 2019), '2019-11' ], 51 | ]; 52 | 53 | cases.forEach(([ month, result ]) => { 54 | assert.equal(month.lastMonth().format(), result); 55 | }); 56 | }); 57 | }); 58 | -------------------------------------------------------------------------------- /test/create.js: -------------------------------------------------------------------------------- 1 | import Month, { months } from '../src/index'; 2 | import { assert } from 'chai'; 3 | import moment from 'moment'; 4 | 5 | describe('It returns a new instance', () => { 6 | 7 | it('through the `new` keyword', () => { 8 | 9 | const cases = [ 10 | [ months.SEPTEMBER, 2015 ], 11 | [ months.FEBRUARY, 1992 ], 12 | [ months.DECEMBER, 2019 ], 13 | ]; 14 | 15 | cases.forEach(([ monthNumber, yearNumber ]) => { 16 | const month = new Month(monthNumber, yearNumber); 17 | 18 | assert.equal(month.month, monthNumber); 19 | assert.equal(month.year, yearNumber); 20 | }); 21 | }); 22 | 23 | it('by passing month and year numbers to the `create` method', () => { 24 | 25 | const cases = [ 26 | [ months.SEPTEMBER, 2015 ], 27 | [ months.FEBRUARY, 1992 ], 28 | [ months.DECEMBER, 2019 ], 29 | ]; 30 | 31 | cases.forEach(([ monthNumber, yearNumber ]) => { 32 | const month = Month.create(monthNumber, yearNumber); 33 | 34 | assert.equal(month.month, monthNumber); 35 | assert.equal(month.year, yearNumber); 36 | }); 37 | }); 38 | 39 | it('from a `moment` object', () => { 40 | 41 | const cases = [ 42 | [ moment('2015-09-17'), months.SEPTEMBER, 2015 ], 43 | [ moment('1992-02-01'), months.FEBRUARY, 1992 ], 44 | [ moment('2019-12-25'), months.DECEMBER, 2019 ], 45 | ]; 46 | 47 | cases.forEach(([ moment, monthNumber, yearNumber ]) => { 48 | const month = Month.create(moment); 49 | 50 | assert.equal(month.month, monthNumber); 51 | assert.equal(month.year, yearNumber); 52 | }); 53 | }); 54 | 55 | it('from a `date` object', () => { 56 | 57 | const cases = [ 58 | [ new Date('2015-09-17'), months.SEPTEMBER, 2015 ], 59 | [ new Date('1992-02-01'), months.FEBRUARY, 1992 ], 60 | [ new Date('2019-12-25'), months.DECEMBER, 2019 ], 61 | ]; 62 | 63 | cases.forEach(([ date, monthNumber, yearNumber ]) => { 64 | const month = Month.create(date); 65 | 66 | assert.equal(month.month, monthNumber); 67 | assert.equal(month.year, yearNumber); 68 | }); 69 | }); 70 | 71 | it('from a date string', () => { 72 | 73 | const cases = [ 74 | [ '2015-09-17', months.SEPTEMBER, 2015 ], 75 | [ '1992-02-01', months.FEBRUARY, 1992 ], 76 | [ '2019-12-25', months.DECEMBER, 2019 ], 77 | ]; 78 | 79 | cases.forEach(([ date, monthNumber, yearNumber ]) => { 80 | const month = Month.create(date); 81 | 82 | assert.equal(month.month, monthNumber); 83 | assert.equal(month.year, yearNumber); 84 | }); 85 | }); 86 | 87 | it('for the current month', () => { 88 | 89 | const now = new Date(); 90 | const thisMonth = Month.thisMonth(); 91 | 92 | assert.equal(thisMonth.month, now.getMonth()); 93 | assert.equal(thisMonth.year, now.getFullYear()); 94 | }); 95 | }); 96 | 97 | describe('It throws an error when', () => { 98 | 99 | it('an invalid month is provided', () => { 100 | 101 | assert.throw(() => new Month(13, 2015)); 102 | assert.throw(() => new Month(12, 2015)); 103 | assert.throw(() => new Month(-2, 2015)); 104 | assert.throw(() => new Month(null, 2015)); 105 | }); 106 | 107 | it('an invalid year is provided', () => { 108 | 109 | assert.throw(() => new Month(1, null)); 110 | }); 111 | 112 | it('an non-supported argument is passed to `create`', () => { 113 | 114 | assert.throw(() => Month.create([1, 2015])); 115 | assert.throw(() => Month.create(() => [1, 2015])); 116 | assert.throw(() => Month.create('january 2015')); 117 | }); 118 | }); 119 | -------------------------------------------------------------------------------- /test/calendar.js: -------------------------------------------------------------------------------- 1 | import Month, { days, months } from '../src/index'; 2 | import { assert } from 'chai'; 3 | import moment from 'moment'; 4 | 5 | describe('It returns the first calendar day', () => { 6 | 7 | it('with weeks starting on a Sunday (default)', () => { 8 | 9 | const cases = [ 10 | [ Month.create(months.JANUARY, 2015), '2014-12-28' ], 11 | [ Month.create(months.FEBRUARY, 2015), '2015-02-01' ], 12 | [ Month.create(months.JUNE, 2015), '2015-05-31' ], 13 | [ Month.create(months.FEBRUARY, 2016), '2016-01-31' ], 14 | [ Month.create(months.MARCH, 2016), '2016-02-28' ], 15 | ]; 16 | 17 | cases.forEach(([ month, result ]) => { 18 | assert.equal(month.firstCalendarDay().format('YYYY-MM-DD'), result); 19 | assert.equal(month.firstCalendarDay(days.SUNDAY).format('YYYY-MM-DD'), result); 20 | }); 21 | }); 22 | 23 | it('with weeks starting on a a Monday', () => { 24 | 25 | const cases = [ 26 | [ Month.create(months.JANUARY, 2015), '2014-12-29' ], 27 | [ Month.create(months.FEBRUARY, 2015), '2015-01-26' ], 28 | [ Month.create(months.JUNE, 2015), '2015-06-01' ], 29 | [ Month.create(months.FEBRUARY, 2016), '2016-02-01' ], 30 | [ Month.create(months.MARCH, 2016), '2016-02-29' ], 31 | ]; 32 | 33 | cases.forEach(([ month, result ]) => { 34 | assert.equal(month.firstCalendarDay(days.MONDAY).format('YYYY-MM-DD'), result); 35 | }); 36 | }); 37 | 38 | it('with weeks starting on a a Wednesday', () => { 39 | 40 | const cases = [ 41 | [ Month.create(months.JANUARY, 2015), '2014-12-31' ], 42 | [ Month.create(months.FEBRUARY, 2015), '2015-01-28' ], 43 | [ Month.create(months.JUNE, 2015), '2015-05-27' ], 44 | [ Month.create(months.FEBRUARY, 2016), '2016-01-27' ], 45 | [ Month.create(months.MARCH, 2016), '2016-02-24' ], 46 | ]; 47 | 48 | cases.forEach(([ month, result ]) => { 49 | assert.equal(month.firstCalendarDay(days.WEDNESDAY).format('YYYY-MM-DD'), result); 50 | }); 51 | }); 52 | }); 53 | 54 | describe('It generates an array of weeks for a calendar month', () => { 55 | 56 | it('with weeks starting on a Sunday (default)', () => { 57 | 58 | const cases = [ 59 | [ Month.create(months.JANUARY, 2015), '2014-12-28', '2015-02-07' ], 60 | [ Month.create(months.FEBRUARY, 2015), '2015-02-01', '2015-03-14' ], 61 | [ Month.create(months.JUNE, 2015), '2015-05-31', '2015-07-11' ], 62 | [ Month.create(months.FEBRUARY, 2016), '2016-01-31', '2016-03-12' ], 63 | [ Month.create(months.MARCH, 2016), '2016-02-28', '2016-04-09' ], 64 | ]; 65 | 66 | cases.forEach(([ month, start, end ]) => { 67 | const calendarDays = month.calendarDays(days.SUNDAY); 68 | 69 | assert.lengthOf(calendarDays, 42); 70 | assert.equal(calendarDays[0].format('YYYY-MM-DD'), start); 71 | assert.equal(calendarDays[41].format('YYYY-MM-DD'), end); 72 | }); 73 | }); 74 | 75 | it('with weeks starting on a Monday', () => { 76 | 77 | const cases = [ 78 | [ Month.create(months.JANUARY, 2015), '2014-12-29', '2015-02-08' ], 79 | [ Month.create(months.FEBRUARY, 2015), '2015-01-26', '2015-03-08' ], 80 | [ Month.create(months.JUNE, 2015), '2015-06-01', '2015-07-12' ], 81 | [ Month.create(months.FEBRUARY, 2016), '2016-02-01', '2016-03-13' ], 82 | [ Month.create(months.MARCH, 2016), '2016-02-29', '2016-04-10' ], 83 | ]; 84 | 85 | cases.forEach(([ month, start, end ]) => { 86 | const calendarDays = month.calendarDays(days.MONDAY); 87 | 88 | assert.lengthOf(calendarDays, 42); 89 | assert.equal(calendarDays[0].format('YYYY-MM-DD'), start); 90 | assert.equal(calendarDays[41].format('YYYY-MM-DD'), end); 91 | }); 92 | }); 93 | }); 94 | 95 | describe('It generates an array of weeks for a calendar month', () => { 96 | 97 | it('with weeks starting on a Sunday (default)', () => { 98 | 99 | const cases = [ 100 | [ Month.create(months.JANUARY, 2015), '2014-12-28', '2015-02-07' ], 101 | [ Month.create(months.FEBRUARY, 2015), '2015-02-01', '2015-03-14' ], 102 | [ Month.create(months.JUNE, 2015), '2015-05-31', '2015-07-11' ], 103 | [ Month.create(months.FEBRUARY, 2016), '2016-01-31', '2016-03-12' ], 104 | [ Month.create(months.MARCH, 2016), '2016-02-28', '2016-04-09' ], 105 | ]; 106 | 107 | cases.forEach(([ month, start, end ]) => { 108 | const calendarWeeks = month.calendarWeeks(days.SUNDAY); 109 | 110 | assert.lengthOf(calendarWeeks, 6); 111 | assert.equal(calendarWeeks[0][0].format('YYYY-MM-DD'), start); 112 | assert.equal(calendarWeeks[5][6].format('YYYY-MM-DD'), end); 113 | }); 114 | }); 115 | }); 116 | 117 | describe('It can check whether a month', () => { 118 | 119 | it('contains a day', () => { 120 | 121 | const cases = [ 122 | [ new Month(months.SEPTEMBER, 2015), moment('2015-09-12') ], 123 | [ new Month(months.FEBRUARY, 1992), moment('1992-02-01') ], 124 | [ new Month(months.DECEMBER, 2019), moment('2019-12-30') ], 125 | ]; 126 | 127 | cases.forEach(([ month, day ]) => { 128 | assert.isTrue(month.containsDay(day)); 129 | }); 130 | }); 131 | 132 | it('doesn\'t contain a day', () => { 133 | 134 | const cases = [ 135 | [ new Month(months.SEPTEMBER, 2015), moment('2014-09-12') ], 136 | [ new Month(months.FEBRUARY, 1992), moment('1992-01-31') ], 137 | [ new Month(months.DECEMBER, 2019), moment('2019-11-30') ], 138 | ]; 139 | 140 | cases.forEach(([ month, day ]) => { 141 | assert.isFalse(month.containsDay(day)); 142 | }); 143 | }); 144 | 145 | it('is the current month', () => { 146 | 147 | assert.isTrue(Month.thisMonth().isThisMonth()); 148 | assert.isFalse(Month.nextMonth().isThisMonth()); 149 | assert.isFalse(Month.lastMonth().isThisMonth()); 150 | }); 151 | 152 | it('is in the future', () => { 153 | 154 | assert.isTrue(Month.nextMonth().isFuture()); 155 | assert.isTrue(Month.nextMonth().nextMonth().isFuture()); 156 | assert.isFalse(Month.thisMonth().isFuture()); 157 | assert.isFalse(Month.lastMonth().isFuture()); 158 | assert.isFalse(Month.lastMonth().lastMonth().isFuture()); 159 | }); 160 | 161 | it('is in the past', () => { 162 | 163 | assert.isTrue(Month.lastMonth().isPast()); 164 | assert.isTrue(Month.lastMonth().lastMonth().isPast()); 165 | assert.isFalse(Month.thisMonth().isPast()); 166 | assert.isFalse(Month.nextMonth().nextMonth().isPast()); 167 | }); 168 | }); 169 | -------------------------------------------------------------------------------- /src/month.js: -------------------------------------------------------------------------------- 1 | import { days } from './enums'; 2 | import moment from 'moment'; 3 | import validate from './validate'; 4 | 5 | /** 6 | * @class Month 7 | * 8 | * @property {number} month 9 | * @property {number} year 10 | */ 11 | export class Month { 12 | /** 13 | * Create a new instance of Month from a month and a year. 14 | * 15 | * @param {number} month - A number from 0 to 11. 16 | * @param {number} year - A valid year number. 17 | * 18 | * @return {Month} 19 | */ 20 | constructor(month, year) { 21 | 22 | month = parseInt(month); 23 | year = parseInt(year); 24 | 25 | if (! validate.isValidMonthNumber(month)) { 26 | throw new Error('Argument `month` has to be a number between 0 and 11.'); 27 | } 28 | 29 | if (! validate.isValidYearNumber(year)) { 30 | throw new Error('Argument `year` has to be a number.'); 31 | } 32 | 33 | this.month = month; 34 | this.year = year; 35 | } 36 | 37 | /** 38 | * Return a fresh instance of the Month object. 39 | * 40 | * @return {Month} 41 | */ 42 | clone() { 43 | return new Month(this.month, this.year); 44 | } 45 | 46 | /** 47 | * Create a new instance of Month, this essentially creates a clone of the 48 | * object. 49 | * 50 | * @return {Month} 51 | */ 52 | thisMonth() { 53 | return this.clone(); 54 | } 55 | 56 | /** 57 | * Create a new instance for the current month. 58 | * 59 | * @return {Month} 60 | */ 61 | static now() { 62 | return Month.create(moment()); 63 | } 64 | 65 | /** 66 | * Create a new instance for the current month. 67 | * 68 | * @return {Month} 69 | */ 70 | static thisMonth() { 71 | return Month.now(); 72 | } 73 | 74 | /** 75 | * Return a new Month instance, set one month later than now. 76 | * 77 | * @return {Month} 78 | */ 79 | nextMonth() { 80 | return Month.create(this.moment().add(1, 'month')); 81 | } 82 | 83 | /** 84 | * Return a new Month instance, set one month later than now. 85 | * 86 | * @return {Month} 87 | */ 88 | static nextMonth() { 89 | return Month.thisMonth().nextMonth(); 90 | } 91 | 92 | /** 93 | * Return a new Month instance, set one month earlier than the current 94 | * instance. 95 | * 96 | * @return {Month} 97 | */ 98 | lastMonth() { 99 | return Month.create(this.moment().add(-1, 'month')); 100 | } 101 | 102 | /** 103 | * Alias for `lastMonth`. 104 | * 105 | * @return {Month} 106 | */ 107 | previousMonth() { 108 | return this.lastMonth(); 109 | } 110 | 111 | /** 112 | * Return a new Month instance, set one month earlier than now. 113 | * 114 | * @return {Month} 115 | */ 116 | static lastMonth() { 117 | return Month.thisMonth().lastMonth(); 118 | } 119 | 120 | /** 121 | * Alias for `static lastMonth`. 122 | * 123 | * @return {Month} 124 | */ 125 | static previousMonth() { 126 | return Month.lastMonth(); 127 | } 128 | 129 | /** 130 | * Format the month's date. Uses ISO 8601, defaults to YYYY-MM. 131 | * 132 | * @param {string} format - The format you want to return. 133 | * 134 | * @return {number} 135 | */ 136 | format(format = 'YYYY-MM') { 137 | return this.moment().format(format); 138 | } 139 | 140 | /** 141 | * Generate a new moment instance set to the first day of this month. 142 | * Since moment.js creates mutable instances, it's very important to always 143 | * return a new one here. 144 | * 145 | * @return {Moment} 146 | */ 147 | moment() { 148 | return moment([this.year, this.month, 1]); 149 | } 150 | 151 | /** 152 | * Return a moment instance of the first day of the month. 153 | * 154 | * @return {Moment} 155 | */ 156 | firstDay() { 157 | return this.moment(); 158 | } 159 | 160 | /** 161 | * Return a moment instance of the first 'calendar day' of the month. 162 | * 163 | * @return {Moment} 164 | */ 165 | firstCalendarDay(weekStartsOn = Month.weekStartsOn) { 166 | const firstDay = this.moment(); 167 | 168 | while (firstDay.day() !== weekStartsOn) { 169 | firstDay.subtract(1, 'day'); 170 | } 171 | 172 | return firstDay; 173 | } 174 | 175 | /** 176 | * Return an array of 'calendar days'. This array contains 42 days, 177 | * starting on a specific day of the week. 178 | * 179 | * @return {Moment[]} 180 | */ 181 | calendarDays(weekStartsOn = Month.weekStartsOn) { 182 | const current = this.firstCalendarDay(weekStartsOn); 183 | 184 | const days = []; 185 | 186 | while (days.length < 42) { 187 | days.push(current.clone()); 188 | current.add(1, 'day'); 189 | } 190 | 191 | return days; 192 | } 193 | 194 | /** 195 | * Return an array of 'calendar weeks'. This array contains 6 weeks, with 196 | * days starting on a specific day of the week. 197 | * 198 | * @return {Moment[][]} 199 | */ 200 | calendarWeeks(weekStartsOn = Month.weekStartsOn) { 201 | const weeks = []; 202 | 203 | for (let i = 0; i < 6; i++) { 204 | weeks.push(this.calendarDays(weekStartsOn).slice(i * 7, i * 7 + 7)); 205 | } 206 | 207 | return weeks; 208 | } 209 | 210 | /** 211 | * Creates a new instance of Month from various formats. 212 | * 213 | * - {number}, {number}: creates a Month from a month and year number. 214 | * - {string}: creates a Month from a string which is equal to 'YYYY-MM' 215 | * or starts with 'YYYY-MM-'. 216 | * - {Moment}: creates a Month for the month in which the Moment instance resides. 217 | * 218 | * @param {(number|string|Moment)} argument 219 | * @param {?number} year 220 | * 221 | * @return {Month} 222 | */ 223 | static create() { 224 | if (arguments.length > 2) { 225 | throw new Error('`Month.create()` can only accept zero, one or two arguments.'); 226 | } 227 | 228 | if (arguments.length === 2) { 229 | return new Month(...arguments); 230 | } 231 | 232 | if (arguments.length === 1) { 233 | 234 | const argument = arguments[0]; 235 | 236 | if (validate.isString(argument)) { 237 | const dateParts = argument.split('-'); 238 | 239 | return new Month(dateParts[1] - 1, dateParts[0]); 240 | } 241 | 242 | if (validate.isMoment(argument)) { 243 | return new Month(argument.month(), argument.year()); 244 | } 245 | 246 | if (validate.isDate(argument)) { 247 | return new Month(argument.getMonth(), argument.getFullYear()); 248 | } 249 | 250 | throw new Error('Invalid argument specified for `Month.create()`.'); 251 | } 252 | 253 | return Month.thisMonth(); 254 | } 255 | 256 | /** 257 | * Check whether a day in the form of a Moment instance is in this month. 258 | * 259 | * @param {Moment} day 260 | * 261 | * @return {bool} 262 | */ 263 | containsDay(day) { 264 | return ( 265 | day.month() === this.month && 266 | day.year() === this.year 267 | ); 268 | } 269 | 270 | /** 271 | * Check whether a day in the form of a Moment instance is not in this month. 272 | * 273 | * @param {Moment} day 274 | * 275 | * @return {bool} 276 | */ 277 | doesntContainDay(day) { 278 | return ! this.containsDay(day); 279 | } 280 | 281 | /** 282 | * Check whether the month instance is the current month in time. 283 | * 284 | * @return {bool} 285 | */ 286 | isThisMonth() { 287 | return this.containsDay(moment()); 288 | } 289 | 290 | /** 291 | * Check whether the month is in the future. Note: the current month will never be in the future. 292 | * 293 | * @return {bool} 294 | */ 295 | isFuture() { 296 | return this.moment().diff(Month.now().nextMonth().moment(), 'months') > -1; 297 | } 298 | 299 | /** 300 | * Check whether the month is in the future. Note: the current month will never be in the future. 301 | * 302 | * @return {bool} 303 | */ 304 | isPast() { 305 | return this.moment().diff(Month.now().lastMonth().moment(), 'months') < 1; 306 | } 307 | } 308 | 309 | /** 310 | * Default setting for the first day of the week. 311 | * 312 | * @type {number} - A number from 0 to 6, 0 being Sunday. 313 | */ 314 | Month.weekStartsOn = days.SUNDAY; 315 | 316 | export default Month; 317 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | [](https://supportukrainenow.org) 3 | 4 | # calendar-months 5 | 6 | [![Latest Version on NPM](https://img.shields.io/npm/v/calendar-months.svg?style=flat-square)](https://npmjs.com/package/calendar-months) 7 | [![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE.md) 8 | [![Build Status](https://img.shields.io/travis/spatie/calendar-months/master.svg?style=flat-square)](https://travis-ci.org/spatie/calendar-months) 9 | [![Code Climate](https://img.shields.io/codeclimate/github/spatie/calendar-months.svg?style=flat-square)](https://img.shields.io/codeclimate/github/spatie/calendar-months.svg) 10 | 11 | Provides a `Month` class with specialized functions for generating calendar user interfaces. 12 | 13 | Calendar UI's generally start each month on the same day of the week, and keep months at the same visual height every month. If a month starts on a Wednesday, you'll probably want to hide or gray out the Monday and Tuesday before. This package provides an unopinionated class to help you build these interfaces. 14 | 15 | A calendar month always has exactly 42 days, or 6 weeks. 16 | 17 | ``` 18 | |------------------------------------------------| 19 | | December 2015 | 20 | | M | T | W | T | F | S | S | 21 | |------------------------------------------------| 22 | | 30* | 1 | 2 | 3 | 4 | 5 | 6 | 23 | | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 24 | | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 25 | | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 26 | | 28 | 29 | 30 | 31 | 1* | 2* | 3* | 27 | | 4* | 5* | 6* | 7* | 8* | 9* | 10* | 28 | |------------------------------------------------| 29 | 30 | *: Gray out or hide 31 | ``` 32 | 33 | ```js 34 | import Month from 'calendar-months'; 35 | 36 | const january = new Month('2015-01'); 37 | 38 | const days = january.calendarDays(); 39 | // => An array of all days that could be visible on the calendar (always 42 days) 40 | 41 | const weeks = january.calendarWeeks(); 42 | // => An array of 6 arrays, each containing 7 days 43 | ``` 44 | 45 | The `examples` folder in this repository contains examples of React and Vue implementations. 46 | 47 | Spatie is a webdesign agency based in Antwerp, Belgium. You'll find an overview of all our open source projects [on our website](https://spatie.be/opensource). 48 | 49 | ## Support us 50 | 51 | [](https://spatie.be/github-ad-click/calendar-months) 52 | 53 | We invest a lot of resources into creating [best in class open source packages](https://spatie.be/open-source). You can support us by [buying one of our paid products](https://spatie.be/open-source/support-us). 54 | 55 | We highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using. You'll find our address on [our contact page](https://spatie.be/about-us). We publish all received postcards on [our virtual postcard wall](https://spatie.be/open-source/postcards). 56 | 57 | ## Postcardware 58 | 59 | You're free to use this package (it's [MIT-licensed](LICENSE.md)), but if it makes it to your production environment you are required to send us a postcard from your hometown, mentioning which of our package(s) you are using. 60 | 61 | Our address is: Spatie, Kruikstraat 22, 2018 Antwerp, Belgium. 62 | 63 | The best postcards will get published on the open source page on our website. 64 | 65 | ## Install 66 | 67 | You can install the package via npm: 68 | 69 | ```bash 70 | $ npm install calendar-months 71 | ``` 72 | 73 | ## Examples 74 | 75 | The `examples` directory in this repository contains Vue and a React example calendars. 76 | 77 | To open an example, navigate to it's directory to run `npm install` and `npm run build`, then open the `index.html` file in your browser. 78 | 79 | ## Usage 80 | 81 | ### Creating Month Instances 82 | 83 | #### From Integers 84 | 85 | ```js 86 | import Month from 'calendar-months'; 87 | 88 | new Month(0, 2016); 89 | // => January 2016 90 | ``` 91 | 92 | Since javascript uses a 0-based index for months, the package also ships with a set of enums to improve clarity when dealing with month numbers. 93 | 94 | ```js 95 | import Month, { months } from 'calendar-months'; 96 | 97 | new Month(months.JANUARY, 2016); 98 | // => January 2016 99 | ``` 100 | 101 | The `Month.create` method also accepts integers to create a `Month` object. 102 | 103 | ```js 104 | import Month from 'calendar-months'; 105 | 106 | Month.create(0, 2016); 107 | // => January 2016 108 | ``` 109 | 110 | #### From Strings 111 | 112 | The `Month.create` method accepts a string in the format of `YYYY-MM[-...]`. 113 | 114 | ```js 115 | import Month from 'calendar-months'; 116 | 117 | Month.create('2016-01'); 118 | // => January 2016 119 | 120 | Month.create('2016-02-04'); 121 | // => February 2016 122 | ``` 123 | 124 | #### From a Moment or Date object 125 | 126 | The `Month.create` method accepts `Moment` and Date objects. 127 | 128 | ```js 129 | import moment from 'moment'; 130 | import Month from 'calendar-months'; 131 | 132 | Month.create(moment()); 133 | // => This month 134 | 135 | Month.create(new Date()); 136 | // => This month 137 | ``` 138 | 139 | #### In a Relative Point in Time 140 | 141 | There are a few factory methods to create `Month` instances for this month, the previous month and the next month. 142 | 143 | ```js 144 | import Month from 'calendar-months'; 145 | 146 | Month.create(); 147 | Month.now(); 148 | Month.thisMonth(); 149 | // => This month 150 | 151 | Month.lastMonth(); 152 | Month.previousMonth(); 153 | // => The previous month 154 | 155 | Month.nextMonth(); 156 | // => The next month 157 | ``` 158 | 159 | `thisMonth`, `lastMonth`, `previousMonth` and `nextMonth` can also be used on existing `Month` instances. These methods are immutable, and return a new instance of the object. 160 | 161 | ```js 162 | import Month from 'calendar-months'; 163 | 164 | const june = Month.create('2016-06'); 165 | 166 | const may = june.lastMonth(); 167 | const july = june.nextMonth(); 168 | ``` 169 | 170 | ### Retrieving Days and Weeks 171 | 172 | To retrieve all the weeks in a calendar month, there's a `calendarWeeks` method. `calendarWeeks` returns an array of 6 arrays, each containing 7 days. A day is a moment object with the time set to `00:00:00`. 173 | 174 | ```js 175 | import Month from 'calendar-months'; 176 | 177 | const weeksInJune = Month.create('2016-06').calendarWeeks(); 178 | 179 | // => [ [ sun, mon, tue, wed, thu, fri, sat ], ... ] 180 | ``` 181 | 182 | If you want your calendars weeks to start on a different day, you can pass in a day as the first parameter. By default, a week starts on Sunday. Since javascript uses a 0-based index for days, the package also ships with a set of enums to improve clarity when dealing with day numbers. 183 | 184 | ```js 185 | import Month, { days } from 'calendar-months'; 186 | 187 | const weeksInJune = Month.create('2016-06').calendarWeeks(days.MONDAY); 188 | 189 | // => [ [ mon, tue, wed, thu, fri, sat, sun ], ... ] 190 | ``` 191 | 192 | If you want to retrieve all days without chunking them by week, there's a `calendarDays` method. This method also optionally accepts a starting day as it's first parameter. 193 | 194 | ```js 195 | import Month, { days } from 'calendar-months'; 196 | 197 | const daysInJune = Month.create('2016-06').calendarDays(days.MONDAY); 198 | 199 | // => [ mon, tue, wed, thu, fri, sat, sun, mon, tue, wed, ... ] 200 | ``` 201 | 202 | ### Additional Methods 203 | 204 | #### Checking Months 205 | 206 | There are three methods to check the position of a month compared to the current time: 207 | 208 | - `isThisMonth` 209 | - `isFuture` 210 | - `isPast` 211 | 212 | ```js 213 | // Considering it's currently June 2016... 214 | 215 | import Month from 'calendar-months'; 216 | 217 | const june = Month.create('2016-06'); 218 | 219 | june.isThisMonth(); // => true 220 | june.isPast(); // => false 221 | june.isFuture(); // => false 222 | 223 | const may = Month.create('2016-05'); 224 | 225 | may.isPast(); // => true 226 | 227 | const july = Month.create('2016-07'); 228 | 229 | july.isFuture(); // => true 230 | ``` 231 | 232 | #### Checking Days in a Month 233 | 234 | By providing a `moment` object of a date, you can check if that date is part of the `Month` instance with `containsDay` and `doesntContainDay`. 235 | 236 | ```js 237 | import Month from 'calendar-months'; 238 | 239 | const june = Month.create('2016-06'); 240 | 241 | june.containsDay(moment('2016-06-23')); // => true 242 | june.containsDay(moment('2016-04-03')); // => false 243 | 244 | june.doesntContainDay(moment('2016-06-23')); // => false 245 | june.doesntContainDay(moment('2016-04-03')); // => true 246 | ``` 247 | 248 | ## Change log 249 | 250 | Please see [CHANGELOG](CHANGELOG.md) for more information what has changed recently. 251 | 252 | ## Testing 253 | 254 | This package is fully tested with `mocha` and `chai`. To run the tests, use the npm script: 255 | 256 | ``` bash 257 | $ npm run test 258 | ``` 259 | 260 | ## Contributing 261 | 262 | Please see [CONTRIBUTING](https://github.com/spatie/.github/blob/main/CONTRIBUTING.md) for details. 263 | 264 | ## Security 265 | 266 | If you've found a bug regarding security please mail [security@spatie.be](mailto:security@spatie.be) instead of using the issue tracker. 267 | 268 | ## Credits 269 | 270 | - [Sebastian De Deyne](https://github.com/sebastiandedeyne) 271 | - [All Contributors](../../contributors) 272 | 273 | ## About Spatie 274 | Spatie is a webdesign agency based in Antwerp, Belgium. You'll find an overview of all our open source projects [on our website](https://spatie.be/opensource). 275 | 276 | ## License 277 | 278 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 279 | --------------------------------------------------------------------------------