diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..6387cfb --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,50 @@ +name: CI Tests + +on: + pull_request: + types: [opened, synchronize, reopened] + push: + branches: + - master + +jobs: + lint: + runs-on: ubuntu-latest + + name: Lint on node 12.x and ubuntu-latest + + steps: + - uses: actions/checkout@v1 + - name: Use Node.js 12.x + uses: actions/setup-node@v1 + with: + node-version: 12.x + + - name: Install deps and build + run: yarn install + + - name: Lint codebase + run: yarn lint + + test: + runs-on: ${{ matrix.os }} + + strategy: + matrix: + node: ['10.x', '12.x', '13.x'] + os: [ubuntu-latest, windows-latest, macOS-latest] + + name: Test on node ${{ matrix.node }} and ${{ matrix.os }} + + steps: + - uses: actions/checkout@v1 + - name: Use Node.js ${{ matrix.node }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node }} + + - name: Install deps and build + run: yarn install + + - name: Test package + run: yarn test --runInBand diff --git a/.gitignore b/.gitignore index b512c09..af4be02 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,6 @@ -node_modules \ No newline at end of file +*.log +.DS_Store +node_modules +dist +package-lock.json +yarn.lock \ No newline at end of file diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index a84d5f0..0000000 --- a/.travis.yml +++ /dev/null @@ -1,7 +0,0 @@ -language: node_js -node_js: - - "node" - - "6" - - "5" - - "4" - - "0.12" diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..5be4a2c --- /dev/null +++ b/LICENSE @@ -0,0 +1,18 @@ +Copyright © Wes Souza + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the “Software”), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index ea318e1..7b4f5fa 100644 --- a/README.md +++ b/README.md @@ -1,54 +1,71 @@ -# Calendar Base [![Build Status](https://travis-ci.org/WesleydeSouza/calendar-base.svg?branch=master)](https://travis-ci.org/WesleydeSouza/calendar-base) +# Calendar Base -[![NPM](https://nodei.co/npm/calendar-base.png)](https://nodei.co/npm/calendar-base/) +Install, lint, test and build status badge -Base methods for generating calendars using JavaScript. +[![npm](https://nodei.co/npm/calendar-base.png)](https://nodei.co/npm/calendar-base/) -Supports IE 6+, Chrome 1+, Firefox 3+, Safari 4+. +Base methods for generating calendars using JavaScript. +Output is ES5 compatible. ## Installation ```bash +# using npm npm install calendar-base -``` - -Or manually copy `dist/calendar-base.min.js` to your project. +# or yarn +yarn add calendar-base +``` ## Usage -```js -var Calendar = require('calendar-base').Calendar, - cal = new Calendar(); -cal.getCalendar(2015, 0); -// Returns an Array with the calendar for January 2015. +```js +const Calendar = require('calendar-base').Calendar; +const cal = new Calendar(); + +cal.getCalendar(2020, 0); +/* +Returns an Array with the calendar for January 2020, including empty spaces for +days from the previous and next months: + +[ + false, + false, + { day: 1, weekDay: 3, month: 0, year: 2020 }, + { day: 2, weekDay: 4, month: 0, year: 2020 }, + { day: 3, weekDay: 5, month: 0, year: 2020 }, + { day: 4, weekDay: 6, month: 0, year: 2020 }, + { day: 5, weekDay: 0, month: 0, year: 2020 }, + ... +] +*/ ``` -Usage with AMD and global variables is available through `dist/calendar-base.min.js`. - -[Check an online example](https://tonicdev.com/npm/calendar-base) or browse the `examples` folder for some simple use cases. - +[Check an online example](https://npm.runkit.com/calendar-base) or browse the +[`examples`](./examples/) folder for some simple use cases. ### Date object notation Every returned day or date argument follows this notation: + ```js { - day: 14, - month: 9, - year: 1986, - weekDay: 4, - selected: false, - siblingMonth: false, - weekNumber: 42 + day: 14, + month: 9, + year: 1986, + weekDay: 4, + selected: false, + siblingMonth: false, + weekNumber: 42 } ``` -Properties `month` and `weekDay` respect JavaScript’s [`Date.prototype`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/prototype). - -Only `day`, `month`, and `year` are necessary as input parameters for methods that require a date. +Properties `month` and `weekDay` respect JavaScript’s +[`Date.prototype`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/prototype). +Only `day`, `month`, and `year` are necessary as input parameters for methods +that require a date. #### `Calendar(options)` @@ -56,12 +73,13 @@ Constructor for a new calendar generator. The object `options` may have the following properties: -* `startDate`: current selected starting date (default `undefined`) -* `endDate`: current selected ending date (default `undefined`) -* `siblingMonths`: whether to include the previous and next months’ days before and after the current month when generating a calendar (default `false`) -* `weekNumbers`: whether to include the week number on each day -* `weekStart`: day of the week, respects [`Date.prototype.getDay`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getDay) (default `0`, Sunday) - +- `startDate`: current selected starting date (default `undefined`) +- `endDate`: current selected ending date (default `undefined`) +- `siblingMonths`: whether to include the previous and next months’ days before + and after the current month when generating a calendar (default `false`) +- `weekNumbers`: whether to include the week number on each day +- `weekStart`: day of the week, respects + [`Date.prototype.getDay`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getDay) (default `0`, Sunday) #### `Calendar.diff(dateOne, dateTwo)` @@ -72,7 +90,6 @@ Returns the difference in days between `dateOne` and `dateTwo` as a `Number`. -9 ``` - #### `Calendar.interval(dateOne, dateTwo)` Returns the amount of days between `dateOne` and `dateTwo` as a `Number`. @@ -82,13 +99,12 @@ Returns the amount of days between `dateOne` and `dateTwo` as a `Number`. 10 ``` - #### `Calendar.compare(leftDate, rightDate)` Compares two date objects, returns: - `-1` if `leftDate` < `rightDate` -- `0` if `leftDate` == `rightDate` +- `0` if `leftDate` == `rightDate` - `1` if `leftDate` > `rightDate` Useful for quick comparisons such as sorting an array of dates. @@ -98,7 +114,6 @@ Useful for quick comparisons such as sorting an array of dates. 1 ``` - #### `Calendar.daysInMonth(year, month)` Returns the amount of days in the given month as a `Number`. @@ -108,7 +123,6 @@ Returns the amount of days in the given month as a `Number`. 31 ``` - #### `Calendar.isLeapYear(year)` Returns whether the given year is a leap year, as a `Boolean`. @@ -118,7 +132,6 @@ Returns whether the given year is a leap year, as a `Boolean`. false ``` - #### `Calendar.calculateWeekNumber(date)` Returns the week number for the specified date. @@ -128,12 +141,14 @@ Returns the week number for the specified date. 42 ``` - #### `Calendar.prototype.getCalendar(year, month)` -Returns an `Array` of dates with the days from the given month, always starting at the configured week day. +Returns an `Array` of dates with the days from the given month, always starting +at the configured week day. -If sibling months is disabled, paddings are added as `false` to align the week days, otherwise the respective days from the previous or next months are included. +If sibling months is disabled, paddings are added as `false` to align the week +days, otherwise the respective days from the previous or next months are +included. ```js > var cal = new Calendar({ siblingMonths: true }); @@ -145,12 +160,10 @@ If sibling months is disabled, paddings are added as `false` to align the week d { day: 4, weekDay: 6, month: 6, year: 2015, siblingMonth: true } ] ``` - #### `Calendar.prototype.setDate(date)` Alias to `Calendar.prototype.setStartDate`. - #### `Calendar.prototype.setStartDate(date)` Sets the current selected starting date. @@ -159,7 +172,6 @@ Sets the current selected starting date. > cal.setStartDate({ year: 2015, month: 0, day: 1 }); ``` - #### `Calendar.prototype.setEndDate(date)` Sets the current selected ending date. @@ -168,22 +180,22 @@ Sets the current selected ending date. > cal.setEndDate({ year: 2015, month: 0, day: 31 }); ``` - #### `Calendar.prototype.isDateSelected(date)` -Checks wheter the given date is inside the selected dates interval, returns a `Boolean`. +Checks whether the given date is inside the selected dates interval, returns a +`Boolean`. ```js > cal.isDateSelected({ year: 2015, month: 0, day: 10 }); true ``` - ## Important note on week numbers -Week numbers are calculated based on the ISO 8601 standard, which assumes calculations based on weeks starting on Mondays. Be extra careful displaying the week number if your calendar doesn't start on a Monday. - +Week numbers are calculated based on the ISO 8601 standard, which assumes +calculations based on weeks starting on Mondays. Be extra careful displaying the +week number if your calendar doesn't start on a Monday. ## License -MIT, http://wesleydesouza.mit-license.org/ +MIT, https://wes.dev/LICENSE.txt diff --git a/dist/calendar-base.min.js b/dist/calendar-base.min.js deleted file mode 100644 index 8b975f1..0000000 --- a/dist/calendar-base.min.js +++ /dev/null @@ -1 +0,0 @@ -(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.calendarBase=f()}})(function(){var define,module,exports;module={exports:exports={}};function Calendar(options){options=options||{};this.startDate=options.startDate;this.endDate=options.endDate;this.siblingMonths=options.siblingMonths;this.weekNumbers=options.weekNumbers;this.weekStart=options.weekStart;if(this.weekStart===undefined){this.weekStart=0}}Calendar.prototype.getCalendar=function(year,month){var date=new Date(Date.UTC(year,month,1,0,0,0,0));year=date.getUTCFullYear();month=date.getUTCMonth();var calendar=[],firstDay=date.getUTCDay(),firstDate=-((7-this.weekStart+firstDay)%7),lastDate=Calendar.daysInMonth(year,month),lastDay=(lastDate-firstDate)%7,lastDatePreviousMonth=Calendar.daysInMonth(year,month-1),i=firstDate,max=lastDate-i+(lastDay!=0?7-lastDay:0)+firstDate,currentDay,currentDate,currentDateObject,currentWeekNumber=null,otherMonth,otherYear;while(ilastDate){if(this.siblingMonths){if(currentDate<1){otherMonth=month-1;otherYear=year;if(otherMonth<0){otherMonth=11;otherYear--}currentDate=lastDatePreviousMonth+currentDate}else if(currentDate>lastDate){otherMonth=month+1;otherYear=year;if(otherMonth>11){otherMonth=0;otherYear++}currentDate=i-lastDate+1}currentDateObject={day:currentDate,weekDay:currentDay,month:otherMonth,year:otherYear,siblingMonth:true}}else{currentDateObject=false}}else{currentDateObject={day:currentDate,weekDay:currentDay,month:month,year:year}}if(currentDateObject&&this.weekNumbers){if(currentWeekNumber===null){currentWeekNumber=Calendar.calculateWeekNumber(currentDateObject)}else if(currentDay==1&¤tWeekNumber==52){currentWeekNumber=1}else if(currentDay==1){currentWeekNumber++}currentDateObject.weekNumber=currentWeekNumber}if(currentDateObject&&this.startDate){currentDateObject.selected=this.isDateSelected(currentDateObject)}calendar.push(currentDateObject);i++}return calendar};Calendar.prototype.isDateSelected=function(date){if(date.year==this.startDate.year&&date.month==this.startDate.month&&date.day==this.startDate.day){return true}else if(this.endDate){if(date.year==this.startDate.year&&date.month==this.startDate.month&&date.daythis.endDate.day){return false}else if(date.year==this.startDate.year&&date.monththis.endDate.month){return false}else if(date.yearthis.endDate.year){return false}return true}return false};Calendar.prototype.setStartDate=function(date){this.startDate=date};Calendar.prototype.setEndDate=function(date){this.endDate=date};Calendar.prototype.setDate=Calendar.prototype.setStartDate;Calendar.diff=function(date1,date2){date1=new Date(Date.UTC(date1.year,date1.month,date1.day,0,0,0,0));date2=new Date(Date.UTC(date2.year,date2.month,date2.day,0,0,0,0));return Math.ceil((date1.getTime()-date2.getTime())/864e5)};Calendar.interval=function(date1,date2){return Math.abs(Calendar.diff(date1,date2))+1};Calendar.compare=function(leftDate,rightDate){if(typeof leftDate!="object"||typeof rightDate!="object"||leftDate===null||rightDate===null){throw new TypeError("dates must be objects")}if(leftDate.yearrightDate.year){return 1}else if(leftDate.monthrightDate.month){return 1}else if(leftDate.dayrightDate.day){return 1}return 0};Calendar.daysInMonth=function(year,month){return new Date(year,month+1,0).getDate()};Calendar.isLeapYear=function(year){return year%4==0&&year%100!=0||year%400==0};Calendar.calculateWeekNumber=function(date){var current=new Date(Date.UTC(date.year,date.month,date.day,0,0,0,0));var target=new Date(current.valueOf());var dayNr=(current.getUTCDay()+6)%7;target.setUTCDate(target.getUTCDate()-dayNr+3);var firstThursday=target.valueOf();target.setUTCMonth(0,1);if(target.getUTCDay()!=4){target.setUTCMonth(0,1+(4-target.getUTCDay()+7)%7)}return 1+Math.ceil((firstThursday-target)/6048e5)};module.exports={Calendar:Calendar};return module.exports}); diff --git a/examples/browser/index.html b/examples/browser/index.html index 3901fb0..ae9440a 100644 --- a/examples/browser/index.html +++ b/examples/browser/index.html @@ -1,26 +1,24 @@ - - Simple Calendar - - - - + + Simple Calendar + + + + +

-

+
    +
  • Mo
  • +
  • Tu
  • +
  • We
  • +
  • Th
  • +
  • Fr
  • +
  • Sa
  • +
  • Su
  • +
-
    -
  • Mo
  • -
  • Tu
  • -
  • We
  • -
  • Th
  • -
  • Fr
  • -
  • Sa
  • -
  • Su
  • -
- - - - - - \ No newline at end of file + + + + diff --git a/examples/browser/my-calendar.js b/examples/browser/my-calendar.js index fe4b7f0..00dcbda 100644 --- a/examples/browser/my-calendar.js +++ b/examples/browser/my-calendar.js @@ -1,22 +1,38 @@ -(function () { - 'use strict' +'use strict'; - var months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'] +const months = [ + 'January', + 'February', + 'March', + 'April', + 'May', + 'June', + 'July', + 'August', + 'September', + 'October', + 'November', + 'December', +]; - var calendar = new calendarBase.Calendar({ siblingMonths: true, weekStart: true }) - var today = new Date() - var $calendarMonth = document.querySelector('.js-calendar-month'), - $calendar = document.querySelector('.js-calendar') +const calendar = new CalendarBase.Calendar({ + siblingMonths: true, + weekStart: true, +}); +const today = new Date(); +const $calendarMonth = document.querySelector('.js-calendar-month'), + $calendar = document.querySelector('.js-calendar'); - $calendarMonth.innerHTML = months[today.getUTCMonth()] +$calendarMonth.innerHTML = months[today.getUTCMonth()]; - calendar.getCalendar(today.getUTCFullYear(), today.getUTCMonth()).forEach(function (date) { - var div = document.createElement('li') - if (date) { - div.className = 'calendar-day'+ (date.siblingMonth ? ' -sibling-month': '') - div.innerHTML = date.day - } - $calendar.appendChild(div) - }) - -}()) +calendar + .getCalendar(today.getUTCFullYear(), today.getUTCMonth()) + .forEach(function(date) { + const div = document.createElement('li'); + if (date) { + div.className = + 'calendar-day' + (date.siblingMonth ? ' -sibling-month' : ''); + div.innerHTML = date.day; + } + $calendar.appendChild(div); + }); diff --git a/examples/node-js/simple-calendar.js b/examples/node-js/simple-calendar.js index cf2fc7a..f0550f6 100644 --- a/examples/node-js/simple-calendar.js +++ b/examples/node-js/simple-calendar.js @@ -1,20 +1,21 @@ -var Calendar = require('calendar-base').Calendar +const Calendar = require('calendar-base').Calendar; -var calendar = new Calendar({ siblingMonths: false, weekStart: 1 }) -var today = new Date() +const calendar = new Calendar({ siblingMonths: false, weekStart: 1 }); +const today = new Date(); -var table = [' Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su', '\n'] +const table = [' Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su', '\n']; -calendar.getCalendar(today.getUTCFullYear(), today.getUTCMonth()).forEach(function (date) { - if (date) { - table.push((date.day < 10 ? ' ' : '') + date.day) - if (date.weekDay == 0) { - table.push('\n') - } - } - else { - table.push(' ') - } -}) +calendar + .getCalendar(today.getUTCFullYear(), today.getUTCMonth()) + .forEach(function(date) { + if (date) { + table.push((date.day < 10 ? ' ' : '') + date.day); + if (date.weekDay == 0) { + table.push('\n'); + } + } else { + table.push(' '); + } + }); -console.log('This month’s calendar\n', table.join(' ')) +console.log('This month’s calendar\n', table.join(' ')); diff --git a/lib/calendar-base.js b/lib/calendar-base.js deleted file mode 100644 index 2435395..0000000 --- a/lib/calendar-base.js +++ /dev/null @@ -1,298 +0,0 @@ -/** - * Calendar constructor - * - * @param {Object} options Calendar options - * @param {Object} options.startDate Date object indicating the selected start date - * @param {Object} options.endDate Date object indicating the selected end date - * @param {Boolean} options.siblingMonths Calculate dates from sibling months (before and after the current month, based on weekStart) - * @param {Boolean} options.weekNumbers Caclulate the week days - * @param {Number} options.weekStart Day of the week to start the calendar, respects `Date.prototype.getDay` (defaults to `0`, Sunday) - */ -function Calendar (options) { - options = options || {}; - - this.startDate = options.startDate; - this.endDate = options.endDate; - this.siblingMonths = options.siblingMonths; - this.weekNumbers = options.weekNumbers; - this.weekStart = options.weekStart; - - if (this.weekStart === undefined) { - this.weekStart = 0; - } -} - -/** - * Calculate a calendar month - * - * @param {Number} year Year - * @param {Number} month Month [0-11] - * @return {Array} Calendar days - */ -Calendar.prototype.getCalendar = function (year, month) { - var date = new Date(Date.UTC(year, month, 1, 0, 0, 0, 0)); - - year = date.getUTCFullYear(); - month = date.getUTCMonth(); - - var calendar = [], - firstDay = date.getUTCDay(), - - firstDate = - (((7 - this.weekStart) + firstDay) % 7), - lastDate = Calendar.daysInMonth(year, month), - lastDay = ((lastDate - firstDate) % 7), - lastDatePreviousMonth = Calendar.daysInMonth(year, month - 1), - i = firstDate, - max = (lastDate - i) + (lastDay != 0 ? 7 - lastDay : 0) + firstDate, - currentDay, - currentDate, - currentDateObject, - currentWeekNumber = null, - otherMonth, - otherYear; - - while (i < max) { - currentDate = i + 1; - currentDay = ((i < 1 ? 7 + i : i) + firstDay) % 7; - if (currentDate < 1 || currentDate > lastDate) { - if (this.siblingMonths) { - if (currentDate < 1) { - otherMonth = month - 1; - otherYear = year; - if (otherMonth < 0) { - otherMonth = 11; - otherYear --; - } - currentDate = lastDatePreviousMonth + currentDate; - } - else if (currentDate > lastDate) { - otherMonth = month + 1; - otherYear = year; - if (otherMonth > 11) { - otherMonth = 0; - otherYear ++; - } - currentDate = i - lastDate + 1; - } - currentDateObject = { - day: currentDate, - weekDay: currentDay, - month: otherMonth, - year: otherYear, - siblingMonth: true - }; - } - else { - currentDateObject = false; - } - } - else { - currentDateObject = { - day: currentDate, - weekDay: currentDay, - month: month, - year: year - }; - } - - if (currentDateObject && this.weekNumbers) { - if (currentWeekNumber === null) { - currentWeekNumber = Calendar.calculateWeekNumber(currentDateObject); - } - else if (currentDay == 1 && currentWeekNumber == 52) { - currentWeekNumber = 1; - } - else if (currentDay == 1) { - currentWeekNumber ++; - } - currentDateObject.weekNumber = currentWeekNumber; - } - - if (currentDateObject && this.startDate) { - currentDateObject.selected = this.isDateSelected(currentDateObject); - } - - calendar.push(currentDateObject); - i ++; - } - - return calendar; -}; - -/** - * Checks if a date is selected - * - * @param {Object} date Date object - * @return {Boolean} Selected status of the date - */ -Calendar.prototype.isDateSelected = function (date) { - if (date.year == this.startDate.year && date.month == this.startDate.month && date.day == this.startDate.day) { - return true; - } - else if (this.endDate) { - if (date.year == this.startDate.year && date.month == this.startDate.month && date.day < this.startDate.day) { - return false; - } - else if (date.year == this.endDate.year && date.month == this.endDate.month && date.day > this.endDate.day) { - return false; - } - else if (date.year == this.startDate.year && date.month < this.startDate.month) { - return false; - } - else if (date.year == this.endDate.year && date.month > this.endDate.month) { - return false; - } - else if (date.year < this.startDate.year) { - return false; - } - else if (date.year > this.endDate.year) { - return false; - } - return true; - } - return false; -}; - -/** - * Sets the selected period start - * - * @param {Object} date Date object - */ -Calendar.prototype.setStartDate = function (date) { - this.startDate = date; -}; - -/** - * Sets the selected period end - * - * @param {Object} date Date object - */ -Calendar.prototype.setEndDate = function (date) { - this.endDate = date; -}; - -/** - * Sets one selected date - * - * @param {Object} date Date object - */ -Calendar.prototype.setDate = Calendar.prototype.setStartDate; - -/** - * Calculates the difference between two dates (date1 - date2), in days - * - * @param {Object} date1 Date object - * @param {Object} date2 Date object - * @return {Number} Days between the dates - */ -Calendar.diff = function (date1, date2) { - date1 = new Date(Date.UTC(date1.year, date1.month, date1.day, 0, 0, 0, 0)); - date2 = new Date(Date.UTC(date2.year, date2.month, date2.day, 0, 0, 0, 0)); - return Math.ceil((date1.getTime() - date2.getTime()) / 86400000); -}; - -/** - * Calculates the interval between two dates - * - * @param {Object} date1 Date object - * @param {Object} date2 Date object - * @return {Number} Number of days - */ -Calendar.interval = function (date1, date2) { - return Math.abs(Calendar.diff(date1, date2)) + 1; -}; - -/** - * Quickly compare two dates - * - * @param {Object} leftDate Left date - * @param {Object} rightDate Right date - * @return {Number} Comparison result: -1 (left < right), 0 (equal) or 1 (left > right) - */ -Calendar.compare = function (leftDate, rightDate) { - if (typeof leftDate != 'object' || typeof rightDate != 'object' || leftDate === null || rightDate === null) { - throw new TypeError('dates must be objects'); - } - - if (leftDate.year < rightDate.year) { - return -1; - } else if (leftDate.year > rightDate.year) { - return 1; - } else if (leftDate.month < rightDate.month) { - return -1; - } else if (leftDate.month > rightDate.month) { - return 1; - } else if (leftDate.day < rightDate.day) { - return -1; - } else if (leftDate.day > rightDate.day) { - return 1; - } - - return 0; -} - -/** - * Calculates the number of days in a month - * - * @param {Number} year Year - * @param {Number} month Month [0-11] - * @return {Number} Length of the month - */ -Calendar.daysInMonth = function (year, month) { - return new Date(year, month + 1, 0).getDate(); -}; - -/** - * Calculates if a given year is a leap year - * - * @param {Number} year Year - * @return {Boolean} Leap year or not - */ -Calendar.isLeapYear = function (year) { - return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0); -} - -/** - * Calculates the week number for a given date - * - * @param {Object} date Date object - * @return {Number} Week number - */ -// Adapted from http://techblog.procurios.nl/k/news/view/33796/14863/calculate-iso-8601-week-and-year-in-javascript.html -Calendar.calculateWeekNumber = function (date) { - // Creates the requested date - var current = new Date(Date.UTC(date.year, date.month, date.day, 0, 0, 0, 0)); - - // Create a copy of the object - var target = new Date(current.valueOf()); - - // ISO week date weeks start on monday so correct the day number - var dayNr = (current.getUTCDay() + 6) % 7; - - // ISO 8601 states that week 1 is the week with the first thursday of that - // year. Set the target date to the thursday in the target week. - target.setUTCDate(target.getUTCDate() - dayNr + 3); - - // Store the millisecond value of the target date - var firstThursday = target.valueOf(); - - // Set the target to the first thursday of the year - - // First set the target to january first - target.setUTCMonth(0, 1); - - // Not a thursday? Correct the date to the next thursday - if (target.getUTCDay() != 4) { - target.setUTCMonth(0, 1 + ((4 - target.getUTCDay()) + 7) % 7); - } - - // The weeknumber is the number of weeks between the first thursday of the - // year and the thursday in the target week. - // 604800000 = 7 * 24 * 3600 * 1000 - return 1 + Math.ceil((firstThursday - target) / 604800000); -} - -/** - * Exports the Calendar - */ -module.exports = { Calendar: Calendar }; diff --git a/package.json b/package.json index 72df284..9b152ce 100644 --- a/package.json +++ b/package.json @@ -1,23 +1,72 @@ { "name": "calendar-base", - "version": "0.3.0", "description": "Base methods for generating calendars using JavaScript.", - "keywords": [ "calendar", "generation", "base", "core" ], - "main": "lib/calendar-base.js", - "scripts": { - "build": "cat lib/calendar-base.js | umd calendar-base --commonJS | uglifyjs > dist/calendar-base.min.js", - "test": "mocha --reporter spec test/index.js" - }, + "version": "1.0.0", + "author": "Wes Souza (https://wes.dev/)", + "license": "MIT", + "keywords": [ + "calendar", + "generation", + "base", + "core" + ], "repository": { "type": "git", "url": "https://github.com/WesleydeSouza/calendar-base" }, - "tonicExampleFilename": "examples/node-js/simple-calendar.js", - "author": "Wesley de Souza ", - "license": "MIT", + "main": "dist/index.js", + "module": "dist/calendar-base.esm.js", + "typings": "dist/index.d.ts", + "files": [ + "dist" + ], + "scripts": { + "build": "tsdx build --name CalendarBase --format cjs,esm,umd", + "lint": "tsdx lint src test", + "prepare": "yarn run build", + "start": "tsdx watch", + "test": "tsdx test" + }, + "dependencies": {}, "devDependencies": { - "mocha": "^2.1.0", - "uglify-js": "^2.4.16", - "umd": "^3.0.0" + "@types/jest": "^25.1.3", + "tsdx": "^0.12.3", + "tslib": "^1.11.1", + "typescript": "^3.8.3" + }, + "peerDependencies": {}, + "eslintConfig": { + "parser": "@typescript-eslint/parser", + "extends": [ + "plugin:@typescript-eslint/recommended", + "prettier/@typescript-eslint", + "plugin:prettier/recommended" + ], + "parserOptions": { + "ecmaVersion": 2018, + "sourceType": "module" + }, + "rules": { + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/no-empty-function": "off", + "@typescript-eslint/no-use-before-define": "off", + "no-duplicate-imports": "error", + "curly": "error" + } + }, + "jest": { + "globals": { + "ts-jest": { + "diagnostics": { + "warnOnly": true + } + } + } + }, + "prettier": { + "printWidth": 80, + "semi": true, + "singleQuote": true, + "trailingComma": "es5" } -} +} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..f05f9ac --- /dev/null +++ b/src/index.ts @@ -0,0 +1,390 @@ +export interface CalendarDate { + day: number; + month: number; + selected?: boolean; + siblingMonth?: boolean; + weekDay?: number; + weekNumber?: number; + year: number; +} + +/** + * Calendar object + */ +class Calendar { + startDate: CalendarDate | null; + endDate: CalendarDate | null; + siblingMonths: boolean; + weekNumbers: boolean; + weekStart: number; + + /** + * Calendar constructor + * + * @param options Calendar options + */ + constructor({ + startDate = null, + endDate = null, + siblingMonths = false, + weekNumbers = false, + weekStart = 0, + }: { + /** + * Date object indicating the selected start date + */ + startDate?: CalendarDate | null; + + /** + * Date object indicating the selected end date + */ + endDate?: CalendarDate | null; + + /** + * Calculate dates from sibling months (before and after the current month, based on weekStart) + */ + siblingMonths?: boolean; + + /** + * Calculate the week days + */ + weekNumbers?: boolean; + + /** + * Day of the week to start the calendar, respects `Date.prototype.getDay` (defaults to `0`, Sunday) + */ + weekStart?: number; + } = {}) { + this.startDate = startDate; + this.endDate = endDate; + this.siblingMonths = siblingMonths; + this.weekNumbers = weekNumbers; + this.weekStart = weekStart; + } + + /** + * Calculate a calendar month + * + * @param year Year + * @param month Month [0-11] + * @return Calendar days + */ + getCalendar(year: number, month: number) { + const date = new Date(Date.UTC(year, month, 1, 0, 0, 0, 0)); + + year = date.getUTCFullYear(); + month = date.getUTCMonth(); + + const calendar: (CalendarDate | false)[] = []; + const firstDay = date.getUTCDay(); + const firstDate = -((7 - this.weekStart + firstDay) % 7); + const lastDate = Calendar.daysInMonth(year, month); + const lastDay = (lastDate - firstDate) % 7; + const lastDatePreviousMonth = Calendar.daysInMonth(year, month - 1); + + let i = firstDate; + let currentDay; + let currentDate; + let currentDateObject: CalendarDate | false = false; + let currentWeekNumber = null; + let otherMonth; + let otherYear; + + const max = lastDate - i + (lastDay !== 0 ? 7 - lastDay : 0) + firstDate; + + while (i < max) { + currentDate = i + 1; + currentDay = ((i < 1 ? 7 + i : i) + firstDay) % 7; + if (currentDate < 1 || currentDate > lastDate) { + if (this.siblingMonths) { + if (currentDate < 1) { + otherMonth = month - 1; + otherYear = year; + if (otherMonth < 0) { + otherMonth = 11; + otherYear--; + } + currentDate = lastDatePreviousMonth + currentDate; + } else if (currentDate > lastDate) { + otherMonth = month + 1; + otherYear = year; + if (otherMonth > 11) { + otherMonth = 0; + otherYear++; + } + currentDate = i - lastDate + 1; + } + + if (otherMonth !== undefined && otherYear !== undefined) { + currentDateObject = { + day: currentDate, + weekDay: currentDay, + month: otherMonth, + year: otherYear, + siblingMonth: true, + }; + } + } else { + currentDateObject = false; + } + } else { + currentDateObject = { + day: currentDate, + weekDay: currentDay, + month: month, + year: year, + }; + } + + if (currentDateObject && this.weekNumbers) { + if (currentWeekNumber === null) { + currentWeekNumber = Calendar.calculateWeekNumber(currentDateObject); + } else if (currentDay === 1 && currentWeekNumber === 52) { + currentWeekNumber = 1; + } else if (currentDay === 1) { + currentWeekNumber++; + } + currentDateObject.weekNumber = currentWeekNumber; + } + + if (currentDateObject && this.startDate) { + currentDateObject.selected = this.isDateSelected(currentDateObject); + } + + calendar.push(currentDateObject); + i++; + } + + return calendar; + } + + /** + * Checks if a date is selected + * + * @param date Date object + * @return Selected status of the date + */ + isDateSelected(date: CalendarDate) { + if (!this.startDate) { + return false; + } + + if ( + date.year === this.startDate.year && + date.month === this.startDate.month && + date.day === this.startDate.day + ) { + return true; + } + + if (!this.endDate) { + return false; + } + + if ( + date.year === this.startDate.year && + date.month === this.startDate.month && + date.day < this.startDate.day + ) { + return false; + } + + if ( + date.year === this.endDate.year && + date.month === this.endDate.month && + date.day > this.endDate.day + ) { + return false; + } + + if ( + date.year === this.startDate.year && + date.month < this.startDate.month + ) { + return false; + } + + if (date.year === this.endDate.year && date.month > this.endDate.month) { + return false; + } + + if (date.year < this.startDate.year) { + return false; + } + + if (date.year > this.endDate.year) { + return false; + } + + return true; + } + + /** + * Sets the selected period start + * + * @param date Date object + */ + setStartDate(date: CalendarDate) { + this.startDate = date; + } + + /** + * Sets the selected period end + * + * @param date Date object + */ + setEndDate(date: CalendarDate) { + this.endDate = date; + } + + /** + * Sets one selected date + * + * @param date Date object + */ + setDate(date: CalendarDate) { + return this.setStartDate(date); + } + + /** + * Calculates the difference between two dates (date1 - date2), in days + * + * @param dateLeft Date object + * @param dateRight Date object + * @return Days between the dates + */ + static diff(dateLeft: CalendarDate, dateRight: CalendarDate) { + const dateLeftDate = new Date( + Date.UTC(dateLeft.year, dateLeft.month, dateLeft.day, 0, 0, 0, 0) + ); + const dateRightDate = new Date( + Date.UTC(dateRight.year, dateRight.month, dateRight.day, 0, 0, 0, 0) + ); + return Math.ceil( + (dateLeftDate.getTime() - dateRightDate.getTime()) / 86400000 + ); + } + + /** + * Calculates the interval between two dates + * + * @param dateLeft Date object + * @param dateRight Date object + * @return Number of days between dates + */ + static interval(dateLeft: CalendarDate, dateRight: CalendarDate) { + return Math.abs(Calendar.diff(dateLeft, dateRight)) + 1; + } + + /** + * Quickly compare two dates + * + * @param dateLeft Left `CalendarDate` object + * @param dateRight Right `CalendarDate` object + * @return Comparison result: -1 (left < right), 0 (equal) or 1 (left > right) + */ + static compare(dateLeft: CalendarDate, dateRight: CalendarDate) { + if ( + typeof dateLeft !== 'object' || + typeof dateRight !== 'object' || + dateLeft === null || + dateRight === null + ) { + throw new TypeError('dates must be objects'); + } + + if (dateLeft.year < dateRight.year) { + return -1; + } + + if (dateLeft.year > dateRight.year) { + return 1; + } + + if (dateLeft.month < dateRight.month) { + return -1; + } + + if (dateLeft.month > dateRight.month) { + return 1; + } + + if (dateLeft.day < dateRight.day) { + return -1; + } + + if (dateLeft.day > dateRight.day) { + return 1; + } + + return 0; + } + + /** + * Calculates the number of days in a month + * + * @param year Year + * @param month Month [0-11] + * @return Length of the month + */ + static daysInMonth(year: number, month: number) { + return new Date(year, month + 1, 0).getDate(); + } + + /** + * Calculates if a given year is a leap year + * + * @param year Year + * @return Leap year or not + */ + static isLeapYear(year: number) { + return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; + } + + /** + * Calculates the week number for a given date + * + * @param date Date object + * @return Week number + */ + // Adapted from http://techblog.procurios.nl/k/news/view/33796/14863/calculate-iso-8601-week-and-year-in-javascript.html + static calculateWeekNumber(date: CalendarDate) { + // Creates the requested date + const current = new Date( + Date.UTC(date.year, date.month, date.day, 0, 0, 0, 0) + ); + + // Create a copy of the object + const target = new Date(current.valueOf()); + + // ISO week date weeks start on monday so correct the day number + const dayNr = (current.getUTCDay() + 6) % 7; + + // ISO 8601 states that week 1 is the week with the first thursday of that + // year. Set the target date to the thursday in the target week. + target.setUTCDate(target.getUTCDate() - dayNr + 3); + + // Store the millisecond value of the target date + const firstThursday = target.valueOf(); + + // Set the target to the first thursday of the year + + // First set the target to january first + target.setUTCMonth(0, 1); + + // Not a thursday? Correct the date to the next thursday + if (target.getUTCDay() !== 4) { + target.setUTCMonth(0, 1 + ((4 - target.getUTCDay() + 7) % 7)); + } + + // The week number is the number of weeks between the first thursday of the + // year and the thursday in the target week. + // 604800000 = 7 * 24 * 3600 * 1000 + return 1 + Math.ceil((firstThursday - target.getTime()) / 604800000); + } +} + +/** + * Exports the Calendar + */ +export { Calendar }; diff --git a/test/index.js b/test/index.js deleted file mode 100644 index 748c6bb..0000000 --- a/test/index.js +++ /dev/null @@ -1,176 +0,0 @@ -var assert = require('assert'), - Calendar = require('..').Calendar; - -describe('calendar-base', function () { - - it('should return a valid calendar', function (done) { - var calendar = new Calendar(), - calendarDays = calendar.getCalendar(1986, 9); - assert.deepEqual(calendarDays, [ false, false, false, { day: 1, weekDay: 3, month: 9, year: 1986 }, { day: 2, weekDay: 4, month: 9, year: 1986 }, { day: 3, weekDay: 5, month: 9, year: 1986 }, { day: 4, weekDay: 6, month: 9, year: 1986 }, { day: 5, weekDay: 0, month: 9, year: 1986 }, { day: 6, weekDay: 1, month: 9, year: 1986 }, { day: 7, weekDay: 2, month: 9, year: 1986 }, { day: 8, weekDay: 3, month: 9, year: 1986 }, { day: 9, weekDay: 4, month: 9, year: 1986 }, { day: 10, weekDay: 5, month: 9, year: 1986 }, { day: 11, weekDay: 6, month: 9, year: 1986 }, { day: 12, weekDay: 0, month: 9, year: 1986 }, { day: 13, weekDay: 1, month: 9, year: 1986 }, { day: 14, weekDay: 2, month: 9, year: 1986 }, { day: 15, weekDay: 3, month: 9, year: 1986 }, { day: 16, weekDay: 4, month: 9, year: 1986 }, { day: 17, weekDay: 5, month: 9, year: 1986 }, { day: 18, weekDay: 6, month: 9, year: 1986 }, { day: 19, weekDay: 0, month: 9, year: 1986 }, { day: 20, weekDay: 1, month: 9, year: 1986 }, { day: 21, weekDay: 2, month: 9, year: 1986 }, { day: 22, weekDay: 3, month: 9, year: 1986 }, { day: 23, weekDay: 4, month: 9, year: 1986 }, { day: 24, weekDay: 5, month: 9, year: 1986 }, { day: 25, weekDay: 6, month: 9, year: 1986 }, { day: 26, weekDay: 0, month: 9, year: 1986 }, { day: 27, weekDay: 1, month: 9, year: 1986 }, { day: 28, weekDay: 2, month: 9, year: 1986 }, { day: 29, weekDay: 3, month: 9, year: 1986 }, { day: 30, weekDay: 4, month: 9, year: 1986 }, { day: 31, weekDay: 5, month: 9, year: 1986 }, false ]); - done(); - }); - - it('should return a valid calendar with sibling months', function (done) { - var calendar = new Calendar({ siblingMonths: true }), - calendarDays = calendar.getCalendar(1986, 9); - assert.deepEqual(calendarDays, [ { day: 28, weekDay: 0, month: 8, year: 1986, siblingMonth: true }, { day: 29, weekDay: 1, month: 8, year: 1986, siblingMonth: true }, { day: 30, weekDay: 2, month: 8, year: 1986, siblingMonth: true }, { day: 1, weekDay: 3, month: 9, year: 1986 }, { day: 2, weekDay: 4, month: 9, year: 1986 }, { day: 3, weekDay: 5, month: 9, year: 1986 }, { day: 4, weekDay: 6, month: 9, year: 1986 }, { day: 5, weekDay: 0, month: 9, year: 1986 }, { day: 6, weekDay: 1, month: 9, year: 1986 }, { day: 7, weekDay: 2, month: 9, year: 1986 }, { day: 8, weekDay: 3, month: 9, year: 1986 }, { day: 9, weekDay: 4, month: 9, year: 1986 }, { day: 10, weekDay: 5, month: 9, year: 1986 }, { day: 11, weekDay: 6, month: 9, year: 1986 }, { day: 12, weekDay: 0, month: 9, year: 1986 }, { day: 13, weekDay: 1, month: 9, year: 1986 }, { day: 14, weekDay: 2, month: 9, year: 1986 }, { day: 15, weekDay: 3, month: 9, year: 1986 }, { day: 16, weekDay: 4, month: 9, year: 1986 }, { day: 17, weekDay: 5, month: 9, year: 1986 }, { day: 18, weekDay: 6, month: 9, year: 1986 }, { day: 19, weekDay: 0, month: 9, year: 1986 }, { day: 20, weekDay: 1, month: 9, year: 1986 }, { day: 21, weekDay: 2, month: 9, year: 1986 }, { day: 22, weekDay: 3, month: 9, year: 1986 }, { day: 23, weekDay: 4, month: 9, year: 1986 }, { day: 24, weekDay: 5, month: 9, year: 1986 }, { day: 25, weekDay: 6, month: 9, year: 1986 }, { day: 26, weekDay: 0, month: 9, year: 1986 }, { day: 27, weekDay: 1, month: 9, year: 1986 }, { day: 28, weekDay: 2, month: 9, year: 1986 }, { day: 29, weekDay: 3, month: 9, year: 1986 }, { day: 30, weekDay: 4, month: 9, year: 1986 }, { day: 31, weekDay: 5, month: 9, year: 1986 }, { day: 1, weekDay: 6, month: 10, year: 1986, siblingMonth: true } ]); - done(); - }); - - it('should return a valid calendar with sibling months and week starting on a different day', function (done) { - var calendar = new Calendar({ siblingMonths: true, weekStart: 1 }), - calendarDays = calendar.getCalendar(1986, 9); - assert.deepEqual(calendarDays, [ { day: 29, weekDay: 1, month: 8, year: 1986, siblingMonth: true }, { day: 30, weekDay: 2, month: 8, year: 1986, siblingMonth: true }, { day: 1, weekDay: 3, month: 9, year: 1986 }, { day: 2, weekDay: 4, month: 9, year: 1986 }, { day: 3, weekDay: 5, month: 9, year: 1986 }, { day: 4, weekDay: 6, month: 9, year: 1986 }, { day: 5, weekDay: 0, month: 9, year: 1986 }, { day: 6, weekDay: 1, month: 9, year: 1986 }, { day: 7, weekDay: 2, month: 9, year: 1986 }, { day: 8, weekDay: 3, month: 9, year: 1986 }, { day: 9, weekDay: 4, month: 9, year: 1986 }, { day: 10, weekDay: 5, month: 9, year: 1986 }, { day: 11, weekDay: 6, month: 9, year: 1986 }, { day: 12, weekDay: 0, month: 9, year: 1986 }, { day: 13, weekDay: 1, month: 9, year: 1986 }, { day: 14, weekDay: 2, month: 9, year: 1986 }, { day: 15, weekDay: 3, month: 9, year: 1986 }, { day: 16, weekDay: 4, month: 9, year: 1986 }, { day: 17, weekDay: 5, month: 9, year: 1986 }, { day: 18, weekDay: 6, month: 9, year: 1986 }, { day: 19, weekDay: 0, month: 9, year: 1986 }, { day: 20, weekDay: 1, month: 9, year: 1986 }, { day: 21, weekDay: 2, month: 9, year: 1986 }, { day: 22, weekDay: 3, month: 9, year: 1986 }, { day: 23, weekDay: 4, month: 9, year: 1986 }, { day: 24, weekDay: 5, month: 9, year: 1986 }, { day: 25, weekDay: 6, month: 9, year: 1986 }, { day: 26, weekDay: 0, month: 9, year: 1986 }, { day: 27, weekDay: 1, month: 9, year: 1986 }, { day: 28, weekDay: 2, month: 9, year: 1986 }, { day: 29, weekDay: 3, month: 9, year: 1986 }, { day: 30, weekDay: 4, month: 9, year: 1986 }, { day: 31, weekDay: 5, month: 9, year: 1986 }, { day: 1, weekDay: 6, month: 10, year: 1986, siblingMonth: true }, { day: 2, weekDay: 0, month: 10, year: 1986, siblingMonth: true } ]); - done(); - }); - - it('should return a valid calendar with sibling months and selected dates', function (done) { - var calendar = new Calendar({ siblingMonths: true, startDate: { day: 5, month: 10, year: 2010 }, endDate: { day: 20, month: 10, year: 2010 } }), - calendarDays = calendar.getCalendar(2010, 10); - assert.deepEqual(calendarDays, [ { day: 31, weekDay: 0, month: 9, year: 2010, siblingMonth: true, selected: false }, { day: 1, weekDay: 1, month: 10, year: 2010, selected: false }, { day: 2, weekDay: 2, month: 10, year: 2010, selected: false }, { day: 3, weekDay: 3, month: 10, year: 2010, selected: false }, { day: 4, weekDay: 4, month: 10, year: 2010, selected: false }, { day: 5, weekDay: 5, month: 10, year: 2010, selected: true }, { day: 6, weekDay: 6, month: 10, year: 2010, selected: true }, { day: 7, weekDay: 0, month: 10, year: 2010, selected: true }, { day: 8, weekDay: 1, month: 10, year: 2010, selected: true }, { day: 9, weekDay: 2, month: 10, year: 2010, selected: true }, { day: 10, weekDay: 3, month: 10, year: 2010, selected: true }, { day: 11, weekDay: 4, month: 10, year: 2010, selected: true }, { day: 12, weekDay: 5, month: 10, year: 2010, selected: true }, { day: 13, weekDay: 6, month: 10, year: 2010, selected: true }, { day: 14, weekDay: 0, month: 10, year: 2010, selected: true }, { day: 15, weekDay: 1, month: 10, year: 2010, selected: true }, { day: 16, weekDay: 2, month: 10, year: 2010, selected: true }, { day: 17, weekDay: 3, month: 10, year: 2010, selected: true }, { day: 18, weekDay: 4, month: 10, year: 2010, selected: true }, { day: 19, weekDay: 5, month: 10, year: 2010, selected: true }, { day: 20, weekDay: 6, month: 10, year: 2010, selected: true }, { day: 21, weekDay: 0, month: 10, year: 2010, selected: false }, { day: 22, weekDay: 1, month: 10, year: 2010, selected: false }, { day: 23, weekDay: 2, month: 10, year: 2010, selected: false }, { day: 24, weekDay: 3, month: 10, year: 2010, selected: false }, { day: 25, weekDay: 4, month: 10, year: 2010, selected: false }, { day: 26, weekDay: 5, month: 10, year: 2010, selected: false }, { day: 27, weekDay: 6, month: 10, year: 2010, selected: false }, { day: 28, weekDay: 0, month: 10, year: 2010, selected: false }, { day: 29, weekDay: 1, month: 10, year: 2010, selected: false }, { day: 30, weekDay: 2, month: 10, year: 2010, selected: false }, { day: 1, weekDay: 3, month: 11, year: 2010, siblingMonth: true, selected: false }, { day: 2, weekDay: 4, month: 11, year: 2010, siblingMonth: true, selected: false }, { day: 3, weekDay: 5, month: 11, year: 2010, siblingMonth: true, selected: false }, { day: 4, weekDay: 6, month: 11, year: 2010, siblingMonth: true, selected: false } ]); - done(); - }); - - it('should return a valid calendar with week numbers for Jan 2012', function (done) { - var calendar = new Calendar({ siblingMonths: true, weekNumbers: true }), - calendarDays = calendar.getCalendar(2012, 0); - assert.deepEqual(calendarDays, [{day:1,weekDay:0,month:0,year:2012,weekNumber:52},{day:2,weekDay:1,month:0,year:2012,weekNumber:1},{day:3,weekDay:2,month:0,year:2012,weekNumber:1},{day:4,weekDay:3,month:0,year:2012,weekNumber:1},{day:5,weekDay:4,month:0,year:2012,weekNumber:1},{day:6,weekDay:5,month:0,year:2012,weekNumber:1},{day:7,weekDay:6,month:0,year:2012,weekNumber:1},{day:8,weekDay:0,month:0,year:2012,weekNumber:1},{day:9,weekDay:1,month:0,year:2012,weekNumber:2},{day:10,weekDay:2,month:0,year:2012,weekNumber:2},{day:11,weekDay:3,month:0,year:2012,weekNumber:2},{day:12,weekDay:4,month:0,year:2012,weekNumber:2},{day:13,weekDay:5,month:0,year:2012,weekNumber:2},{day:14,weekDay:6,month:0,year:2012,weekNumber:2},{day:15,weekDay:0,month:0,year:2012,weekNumber:2},{day:16,weekDay:1,month:0,year:2012,weekNumber:3},{day:17,weekDay:2,month:0,year:2012,weekNumber:3},{day:18,weekDay:3,month:0,year:2012,weekNumber:3},{day:19,weekDay:4,month:0,year:2012,weekNumber:3},{day:20,weekDay:5,month:0,year:2012,weekNumber:3},{day:21,weekDay:6,month:0,year:2012,weekNumber:3},{day:22,weekDay:0,month:0,year:2012,weekNumber:3},{day:23,weekDay:1,month:0,year:2012,weekNumber:4},{day:24,weekDay:2,month:0,year:2012,weekNumber:4},{day:25,weekDay:3,month:0,year:2012,weekNumber:4},{day:26,weekDay:4,month:0,year:2012,weekNumber:4},{day:27,weekDay:5,month:0,year:2012,weekNumber:4},{day:28,weekDay:6,month:0,year:2012,weekNumber:4},{day:29,weekDay:0,month:0,year:2012,weekNumber:4},{day:30,weekDay:1,month:0,year:2012,weekNumber:5},{day:31,weekDay:2,month:0,year:2012,weekNumber:5},{day:1,weekDay:3,month:1,year:2012,siblingMonth:true,weekNumber:5},{day:2,weekDay:4,month:1,year:2012,siblingMonth:true,weekNumber:5},{day:3,weekDay:5,month:1,year:2012,siblingMonth:true,weekNumber:5},{day:4,weekDay:6,month:1,year:2012,siblingMonth:true,weekNumber:5}]); - done(); - }); - - it('should return a valid calendar with week numbers for Dec 2019', function (done) { - var calendar = new Calendar({ siblingMonths: true, weekNumbers: true }), - calendarDays = calendar.getCalendar(2019, 11); - assert.deepEqual(calendarDays, [{day:1,weekDay:0,month:11,year:2019,weekNumber:48},{day:2,weekDay:1,month:11,year:2019,weekNumber:49},{day:3,weekDay:2,month:11,year:2019,weekNumber:49},{day:4,weekDay:3,month:11,year:2019,weekNumber:49},{day:5,weekDay:4,month:11,year:2019,weekNumber:49},{day:6,weekDay:5,month:11,year:2019,weekNumber:49},{day:7,weekDay:6,month:11,year:2019,weekNumber:49},{day:8,weekDay:0,month:11,year:2019,weekNumber:49},{day:9,weekDay:1,month:11,year:2019,weekNumber:50},{day:10,weekDay:2,month:11,year:2019,weekNumber:50},{day:11,weekDay:3,month:11,year:2019,weekNumber:50},{day:12,weekDay:4,month:11,year:2019,weekNumber:50},{day:13,weekDay:5,month:11,year:2019,weekNumber:50},{day:14,weekDay:6,month:11,year:2019,weekNumber:50},{day:15,weekDay:0,month:11,year:2019,weekNumber:50},{day:16,weekDay:1,month:11,year:2019,weekNumber:51},{day:17,weekDay:2,month:11,year:2019,weekNumber:51},{day:18,weekDay:3,month:11,year:2019,weekNumber:51},{day:19,weekDay:4,month:11,year:2019,weekNumber:51},{day:20,weekDay:5,month:11,year:2019,weekNumber:51},{day:21,weekDay:6,month:11,year:2019,weekNumber:51},{day:22,weekDay:0,month:11,year:2019,weekNumber:51},{day:23,weekDay:1,month:11,year:2019,weekNumber:52},{day:24,weekDay:2,month:11,year:2019,weekNumber:52},{day:25,weekDay:3,month:11,year:2019,weekNumber:52},{day:26,weekDay:4,month:11,year:2019,weekNumber:52},{day:27,weekDay:5,month:11,year:2019,weekNumber:52},{day:28,weekDay:6,month:11,year:2019,weekNumber:52},{day:29,weekDay:0,month:11,year:2019,weekNumber:52},{day:30,weekDay:1,month:11,year:2019,weekNumber:1},{day:31,weekDay:2,month:11,year:2019,weekNumber:1},{day:1,weekDay:3,month:0,year:2020,siblingMonth:true,weekNumber:1},{day:2,weekDay:4,month:0,year:2020,siblingMonth:true,weekNumber:1},{day:3,weekDay:5,month:0,year:2020,siblingMonth:true,weekNumber:1},{day:4,weekDay:6,month:0,year:2020,siblingMonth:true,weekNumber:1}]); - done(); - }); - - it('should return a valid Feb 1990', function (done) { - var calendar = new Calendar(), - calendarDays = calendar.getCalendar(1990, 1); - assert.equal(calendarDays[32], false); - done(); - }); - - it('should return a valid Feb 1996', function (done) { - var calendar = new Calendar(), - calendarDays = calendar.getCalendar(1996, 1); - assert.deepEqual(calendarDays[32], { day: 29, weekDay: 4, month: 1, year: 1996 }); - done(); - }); - - it('should return a valid Feb 2000', function (done) { - var calendar = new Calendar(), - calendarDays = calendar.getCalendar(2000, 1); - assert.deepEqual(calendarDays[30], { day: 29, weekDay: 2, month: 1, year: 2000 }); - done(); - }); - - it('should return a valid Feb 2100', function (done) { - var calendar = new Calendar(), - calendarDays = calendar.getCalendar(2100, 1); - assert.equal(calendarDays[29], false); - done(); - }); - - it('should adjust the month number', function (done) { - var calendar = new Calendar(), - calendarDays = calendar.getCalendar(2010, 12); - assert.equal(calendarDays[15].month, 0); - assert.equal(calendarDays[15].year, 2011); - done(); - }); - - it('should return valid date selection states for same month', function (done) { - var calendar = new Calendar(); - calendar.setStartDate({ year: 2010, month: 0, day: 15 }); - calendar.setEndDate({ year: 2010, month: 0, day: 17 }); - assert.equal(calendar.isDateSelected({ year: 2010, month: 0, day: 14 }), false); - assert.equal(calendar.isDateSelected({ year: 2010, month: 0, day: 15 }), true); - assert.equal(calendar.isDateSelected({ year: 2010, month: 0, day: 16 }), true); - assert.equal(calendar.isDateSelected({ year: 2010, month: 0, day: 17 }), true); - assert.equal(calendar.isDateSelected({ year: 2010, month: 0, day: 18 }), false); - done(); - }); - - it('should return valid date selection states for same year', function (done) { - var calendar = new Calendar(); - calendar.setStartDate({ year: 2010, month: 1, day: 15 }); - calendar.setEndDate({ year: 2010, month: 3, day: 15 }); - assert.equal(calendar.isDateSelected({ year: 2010, month: 0, day: 15 }), false); - assert.equal(calendar.isDateSelected({ year: 2010, month: 1, day: 14 }), false); - assert.equal(calendar.isDateSelected({ year: 2010, month: 1, day: 15 }), true); - assert.equal(calendar.isDateSelected({ year: 2010, month: 1, day: 16 }), true); - assert.equal(calendar.isDateSelected({ year: 2010, month: 2, day: 15 }), true); - assert.equal(calendar.isDateSelected({ year: 2010, month: 3, day: 15 }), true); - assert.equal(calendar.isDateSelected({ year: 2010, month: 3, day: 16 }), false); - assert.equal(calendar.isDateSelected({ year: 2010, month: 4, day: 15 }), false); - done(); - }); - - it('should return valid date selection states for multiple years', function (done) { - var calendar = new Calendar(); - calendar.setStartDate({ year: 2010, month: 1, day: 15 }); - calendar.setEndDate({ year: 2012, month: 1, day: 15 }); - assert.equal(calendar.isDateSelected({ year: 2010, month: 0, day: 15 }), false); - assert.equal(calendar.isDateSelected({ year: 2010, month: 1, day: 14 }), false); - assert.equal(calendar.isDateSelected({ year: 2010, month: 1, day: 15 }), true); - assert.equal(calendar.isDateSelected({ year: 2010, month: 11, day: 31 }), true); - assert.equal(calendar.isDateSelected({ year: 2011, month: 0, day: 1 }), true); - assert.equal(calendar.isDateSelected({ year: 2011, month: 1, day: 15 }), true); - assert.equal(calendar.isDateSelected({ year: 2011, month: 11, day: 31 }), true); - assert.equal(calendar.isDateSelected({ year: 2012, month: 1, day: 15 }), true); - assert.equal(calendar.isDateSelected({ year: 2012, month: 1, day: 16 }), false); - done(); - }); - - it('should return valid date diffs', function (done) { - assert.equal(Calendar.diff({ year: 2016, month: 2, day: 1 }, { year: 2016, month: 1, day: 1 }), 29); - assert.equal(Calendar.diff({ year: 2010, month: 0, day: 1 }, { year: 2011, month: 0, day: 1 }), -365); - done(); - }); - - it('should return valid date intervals', function (done) { - assert.equal(Calendar.interval({ year: 1986, month: 1, day: 16 }, { year: 1986, month: 1, day: 16 }), 1); - assert.equal(Calendar.interval({ year: 1986, month: 1, day: 10 }, { year: 1986, month: 2, day: 10 }), 29); - assert.equal(Calendar.interval({ year: 1986, month: 0, day: 1 }, { year: 1986, month: 11, day: 31 }), 365); - assert.equal(Calendar.interval({ year: 1990, month: 0, day: 1 }, { year: 1990, month: 11, day: 31 }), 365); - assert.equal(Calendar.interval({ year: 1996, month: 0, day: 1 }, { year: 1996, month: 11, day: 31 }), 366); - assert.equal(Calendar.interval({ year: 2000, month: 0, day: 1 }, { year: 2000, month: 11, day: 31 }), 366); - assert.equal(Calendar.interval({ year: 2100, month: 0, day: 1 }, { year: 2100, month: 11, day: 31 }), 365); - done(); - }); - - it('should return valid date comparisons', function (done) { - assert.equal(Calendar.compare({ year: 2000, month: 0, day: 1 }, { year: 2000, month: 0, day: 1 }), 0); - assert.equal(Calendar.compare({ year: 2000, month: 0, day: 1 }, { year: 2000, month: 0, day: 2 }), -1); - assert.equal(Calendar.compare({ year: 2000, month: 0, day: 2 }, { year: 2000, month: 0, day: 1 }), 1); - assert.equal(Calendar.compare({ year: 2000, month: 0, day: 1 }, { year: 2000, month: 1, day: 1 }), -1); - assert.equal(Calendar.compare({ year: 2000, month: 1, day: 1 }, { year: 2000, month: 0, day: 1 }), 1); - assert.equal(Calendar.compare({ year: 2001, month: 0, day: 1 }, { year: 2000, month: 0, day: 1 }), 1); - assert.equal(Calendar.compare({ year: 2000, month: 0, day: 1 }, { year: 2001, month: 0, day: 1 }), -1); - done(); - }); - - it('should set starting date', function (done) { - var calendar = new Calendar(); - calendar.setStartDate({ year: 2010, month: 1, day: 15 }); - assert.deepEqual(calendar.startDate, { year: 2010, month: 1, day: 15 }); - done(); - }); - - it('should set ending date', function (done) { - var calendar = new Calendar(); - calendar.setEndDate({ year: 2010, month: 1, day: 15 }); - assert.deepEqual(calendar.endDate, { year: 2010, month: 1, day: 15 }); - done(); - }); - - it('should return valid days in month', function (done) { - assert.equal(Calendar.daysInMonth(1988, 1), 29); - assert.equal(Calendar.daysInMonth(1988, 7), 31); - assert.equal(Calendar.daysInMonth(2015, 10), 30); - done(); - }); - -}); diff --git a/test/index.test.ts b/test/index.test.ts new file mode 100644 index 0000000..a59aeea --- /dev/null +++ b/test/index.test.ts @@ -0,0 +1,600 @@ +import { Calendar } from '../src/index'; + +describe('calendar-base', () => { + it('should return a valid calendar', function() { + const calendar = new Calendar(); + const calendarDays = calendar.getCalendar(1986, 9); + + expect(calendarDays).toEqual([ + false, + false, + false, + { day: 1, weekDay: 3, month: 9, year: 1986 }, + { day: 2, weekDay: 4, month: 9, year: 1986 }, + { day: 3, weekDay: 5, month: 9, year: 1986 }, + { day: 4, weekDay: 6, month: 9, year: 1986 }, + { day: 5, weekDay: 0, month: 9, year: 1986 }, + { day: 6, weekDay: 1, month: 9, year: 1986 }, + { day: 7, weekDay: 2, month: 9, year: 1986 }, + { day: 8, weekDay: 3, month: 9, year: 1986 }, + { day: 9, weekDay: 4, month: 9, year: 1986 }, + { day: 10, weekDay: 5, month: 9, year: 1986 }, + { day: 11, weekDay: 6, month: 9, year: 1986 }, + { day: 12, weekDay: 0, month: 9, year: 1986 }, + { day: 13, weekDay: 1, month: 9, year: 1986 }, + { day: 14, weekDay: 2, month: 9, year: 1986 }, + { day: 15, weekDay: 3, month: 9, year: 1986 }, + { day: 16, weekDay: 4, month: 9, year: 1986 }, + { day: 17, weekDay: 5, month: 9, year: 1986 }, + { day: 18, weekDay: 6, month: 9, year: 1986 }, + { day: 19, weekDay: 0, month: 9, year: 1986 }, + { day: 20, weekDay: 1, month: 9, year: 1986 }, + { day: 21, weekDay: 2, month: 9, year: 1986 }, + { day: 22, weekDay: 3, month: 9, year: 1986 }, + { day: 23, weekDay: 4, month: 9, year: 1986 }, + { day: 24, weekDay: 5, month: 9, year: 1986 }, + { day: 25, weekDay: 6, month: 9, year: 1986 }, + { day: 26, weekDay: 0, month: 9, year: 1986 }, + { day: 27, weekDay: 1, month: 9, year: 1986 }, + { day: 28, weekDay: 2, month: 9, year: 1986 }, + { day: 29, weekDay: 3, month: 9, year: 1986 }, + { day: 30, weekDay: 4, month: 9, year: 1986 }, + { day: 31, weekDay: 5, month: 9, year: 1986 }, + false, + ]); + }); + + it('should return a valid calendar with sibling months', () => { + const calendar = new Calendar({ siblingMonths: true }); + const calendarDays = calendar.getCalendar(1986, 9); + expect(calendarDays).toEqual([ + { day: 28, weekDay: 0, month: 8, year: 1986, siblingMonth: true }, + { day: 29, weekDay: 1, month: 8, year: 1986, siblingMonth: true }, + { day: 30, weekDay: 2, month: 8, year: 1986, siblingMonth: true }, + { day: 1, weekDay: 3, month: 9, year: 1986 }, + { day: 2, weekDay: 4, month: 9, year: 1986 }, + { day: 3, weekDay: 5, month: 9, year: 1986 }, + { day: 4, weekDay: 6, month: 9, year: 1986 }, + { day: 5, weekDay: 0, month: 9, year: 1986 }, + { day: 6, weekDay: 1, month: 9, year: 1986 }, + { day: 7, weekDay: 2, month: 9, year: 1986 }, + { day: 8, weekDay: 3, month: 9, year: 1986 }, + { day: 9, weekDay: 4, month: 9, year: 1986 }, + { day: 10, weekDay: 5, month: 9, year: 1986 }, + { day: 11, weekDay: 6, month: 9, year: 1986 }, + { day: 12, weekDay: 0, month: 9, year: 1986 }, + { day: 13, weekDay: 1, month: 9, year: 1986 }, + { day: 14, weekDay: 2, month: 9, year: 1986 }, + { day: 15, weekDay: 3, month: 9, year: 1986 }, + { day: 16, weekDay: 4, month: 9, year: 1986 }, + { day: 17, weekDay: 5, month: 9, year: 1986 }, + { day: 18, weekDay: 6, month: 9, year: 1986 }, + { day: 19, weekDay: 0, month: 9, year: 1986 }, + { day: 20, weekDay: 1, month: 9, year: 1986 }, + { day: 21, weekDay: 2, month: 9, year: 1986 }, + { day: 22, weekDay: 3, month: 9, year: 1986 }, + { day: 23, weekDay: 4, month: 9, year: 1986 }, + { day: 24, weekDay: 5, month: 9, year: 1986 }, + { day: 25, weekDay: 6, month: 9, year: 1986 }, + { day: 26, weekDay: 0, month: 9, year: 1986 }, + { day: 27, weekDay: 1, month: 9, year: 1986 }, + { day: 28, weekDay: 2, month: 9, year: 1986 }, + { day: 29, weekDay: 3, month: 9, year: 1986 }, + { day: 30, weekDay: 4, month: 9, year: 1986 }, + { day: 31, weekDay: 5, month: 9, year: 1986 }, + { day: 1, weekDay: 6, month: 10, year: 1986, siblingMonth: true }, + ]); + }); + + it('should return a valid calendar with sibling months and week starting on a different day', () => { + const calendar = new Calendar({ siblingMonths: true, weekStart: 1 }); + const calendarDays = calendar.getCalendar(1986, 9); + expect(calendarDays).toEqual([ + { day: 29, weekDay: 1, month: 8, year: 1986, siblingMonth: true }, + { day: 30, weekDay: 2, month: 8, year: 1986, siblingMonth: true }, + { day: 1, weekDay: 3, month: 9, year: 1986 }, + { day: 2, weekDay: 4, month: 9, year: 1986 }, + { day: 3, weekDay: 5, month: 9, year: 1986 }, + { day: 4, weekDay: 6, month: 9, year: 1986 }, + { day: 5, weekDay: 0, month: 9, year: 1986 }, + { day: 6, weekDay: 1, month: 9, year: 1986 }, + { day: 7, weekDay: 2, month: 9, year: 1986 }, + { day: 8, weekDay: 3, month: 9, year: 1986 }, + { day: 9, weekDay: 4, month: 9, year: 1986 }, + { day: 10, weekDay: 5, month: 9, year: 1986 }, + { day: 11, weekDay: 6, month: 9, year: 1986 }, + { day: 12, weekDay: 0, month: 9, year: 1986 }, + { day: 13, weekDay: 1, month: 9, year: 1986 }, + { day: 14, weekDay: 2, month: 9, year: 1986 }, + { day: 15, weekDay: 3, month: 9, year: 1986 }, + { day: 16, weekDay: 4, month: 9, year: 1986 }, + { day: 17, weekDay: 5, month: 9, year: 1986 }, + { day: 18, weekDay: 6, month: 9, year: 1986 }, + { day: 19, weekDay: 0, month: 9, year: 1986 }, + { day: 20, weekDay: 1, month: 9, year: 1986 }, + { day: 21, weekDay: 2, month: 9, year: 1986 }, + { day: 22, weekDay: 3, month: 9, year: 1986 }, + { day: 23, weekDay: 4, month: 9, year: 1986 }, + { day: 24, weekDay: 5, month: 9, year: 1986 }, + { day: 25, weekDay: 6, month: 9, year: 1986 }, + { day: 26, weekDay: 0, month: 9, year: 1986 }, + { day: 27, weekDay: 1, month: 9, year: 1986 }, + { day: 28, weekDay: 2, month: 9, year: 1986 }, + { day: 29, weekDay: 3, month: 9, year: 1986 }, + { day: 30, weekDay: 4, month: 9, year: 1986 }, + { day: 31, weekDay: 5, month: 9, year: 1986 }, + { day: 1, weekDay: 6, month: 10, year: 1986, siblingMonth: true }, + { day: 2, weekDay: 0, month: 10, year: 1986, siblingMonth: true }, + ]); + }); + + it('should return a valid calendar with sibling months and selected dates', () => { + const calendar = new Calendar({ + siblingMonths: true, + startDate: { day: 5, month: 10, year: 2010 }, + endDate: { day: 20, month: 10, year: 2010 }, + }); + const calendarDays = calendar.getCalendar(2010, 10); + expect(calendarDays).toEqual([ + { + day: 31, + weekDay: 0, + month: 9, + year: 2010, + siblingMonth: true, + selected: false, + }, + { day: 1, weekDay: 1, month: 10, year: 2010, selected: false }, + { day: 2, weekDay: 2, month: 10, year: 2010, selected: false }, + { day: 3, weekDay: 3, month: 10, year: 2010, selected: false }, + { day: 4, weekDay: 4, month: 10, year: 2010, selected: false }, + { day: 5, weekDay: 5, month: 10, year: 2010, selected: true }, + { day: 6, weekDay: 6, month: 10, year: 2010, selected: true }, + { day: 7, weekDay: 0, month: 10, year: 2010, selected: true }, + { day: 8, weekDay: 1, month: 10, year: 2010, selected: true }, + { day: 9, weekDay: 2, month: 10, year: 2010, selected: true }, + { day: 10, weekDay: 3, month: 10, year: 2010, selected: true }, + { day: 11, weekDay: 4, month: 10, year: 2010, selected: true }, + { day: 12, weekDay: 5, month: 10, year: 2010, selected: true }, + { day: 13, weekDay: 6, month: 10, year: 2010, selected: true }, + { day: 14, weekDay: 0, month: 10, year: 2010, selected: true }, + { day: 15, weekDay: 1, month: 10, year: 2010, selected: true }, + { day: 16, weekDay: 2, month: 10, year: 2010, selected: true }, + { day: 17, weekDay: 3, month: 10, year: 2010, selected: true }, + { day: 18, weekDay: 4, month: 10, year: 2010, selected: true }, + { day: 19, weekDay: 5, month: 10, year: 2010, selected: true }, + { day: 20, weekDay: 6, month: 10, year: 2010, selected: true }, + { day: 21, weekDay: 0, month: 10, year: 2010, selected: false }, + { day: 22, weekDay: 1, month: 10, year: 2010, selected: false }, + { day: 23, weekDay: 2, month: 10, year: 2010, selected: false }, + { day: 24, weekDay: 3, month: 10, year: 2010, selected: false }, + { day: 25, weekDay: 4, month: 10, year: 2010, selected: false }, + { day: 26, weekDay: 5, month: 10, year: 2010, selected: false }, + { day: 27, weekDay: 6, month: 10, year: 2010, selected: false }, + { day: 28, weekDay: 0, month: 10, year: 2010, selected: false }, + { day: 29, weekDay: 1, month: 10, year: 2010, selected: false }, + { day: 30, weekDay: 2, month: 10, year: 2010, selected: false }, + { + day: 1, + weekDay: 3, + month: 11, + year: 2010, + siblingMonth: true, + selected: false, + }, + { + day: 2, + weekDay: 4, + month: 11, + year: 2010, + siblingMonth: true, + selected: false, + }, + { + day: 3, + weekDay: 5, + month: 11, + year: 2010, + siblingMonth: true, + selected: false, + }, + { + day: 4, + weekDay: 6, + month: 11, + year: 2010, + siblingMonth: true, + selected: false, + }, + ]); + }); + + it('should return a valid calendar with week numbers for Jan 2012', () => { + const calendar = new Calendar({ siblingMonths: true, weekNumbers: true }); + const calendarDays = calendar.getCalendar(2012, 0); + expect(calendarDays).toEqual([ + { day: 1, weekDay: 0, month: 0, year: 2012, weekNumber: 52 }, + { day: 2, weekDay: 1, month: 0, year: 2012, weekNumber: 1 }, + { day: 3, weekDay: 2, month: 0, year: 2012, weekNumber: 1 }, + { day: 4, weekDay: 3, month: 0, year: 2012, weekNumber: 1 }, + { day: 5, weekDay: 4, month: 0, year: 2012, weekNumber: 1 }, + { day: 6, weekDay: 5, month: 0, year: 2012, weekNumber: 1 }, + { day: 7, weekDay: 6, month: 0, year: 2012, weekNumber: 1 }, + { day: 8, weekDay: 0, month: 0, year: 2012, weekNumber: 1 }, + { day: 9, weekDay: 1, month: 0, year: 2012, weekNumber: 2 }, + { day: 10, weekDay: 2, month: 0, year: 2012, weekNumber: 2 }, + { day: 11, weekDay: 3, month: 0, year: 2012, weekNumber: 2 }, + { day: 12, weekDay: 4, month: 0, year: 2012, weekNumber: 2 }, + { day: 13, weekDay: 5, month: 0, year: 2012, weekNumber: 2 }, + { day: 14, weekDay: 6, month: 0, year: 2012, weekNumber: 2 }, + { day: 15, weekDay: 0, month: 0, year: 2012, weekNumber: 2 }, + { day: 16, weekDay: 1, month: 0, year: 2012, weekNumber: 3 }, + { day: 17, weekDay: 2, month: 0, year: 2012, weekNumber: 3 }, + { day: 18, weekDay: 3, month: 0, year: 2012, weekNumber: 3 }, + { day: 19, weekDay: 4, month: 0, year: 2012, weekNumber: 3 }, + { day: 20, weekDay: 5, month: 0, year: 2012, weekNumber: 3 }, + { day: 21, weekDay: 6, month: 0, year: 2012, weekNumber: 3 }, + { day: 22, weekDay: 0, month: 0, year: 2012, weekNumber: 3 }, + { day: 23, weekDay: 1, month: 0, year: 2012, weekNumber: 4 }, + { day: 24, weekDay: 2, month: 0, year: 2012, weekNumber: 4 }, + { day: 25, weekDay: 3, month: 0, year: 2012, weekNumber: 4 }, + { day: 26, weekDay: 4, month: 0, year: 2012, weekNumber: 4 }, + { day: 27, weekDay: 5, month: 0, year: 2012, weekNumber: 4 }, + { day: 28, weekDay: 6, month: 0, year: 2012, weekNumber: 4 }, + { day: 29, weekDay: 0, month: 0, year: 2012, weekNumber: 4 }, + { day: 30, weekDay: 1, month: 0, year: 2012, weekNumber: 5 }, + { day: 31, weekDay: 2, month: 0, year: 2012, weekNumber: 5 }, + { + day: 1, + weekDay: 3, + month: 1, + year: 2012, + siblingMonth: true, + weekNumber: 5, + }, + { + day: 2, + weekDay: 4, + month: 1, + year: 2012, + siblingMonth: true, + weekNumber: 5, + }, + { + day: 3, + weekDay: 5, + month: 1, + year: 2012, + siblingMonth: true, + weekNumber: 5, + }, + { + day: 4, + weekDay: 6, + month: 1, + year: 2012, + siblingMonth: true, + weekNumber: 5, + }, + ]); + }); + + it('should return a valid calendar with week numbers for Dec 2019', () => { + const calendar = new Calendar({ siblingMonths: true, weekNumbers: true }); + const calendarDays = calendar.getCalendar(2019, 11); + expect(calendarDays).toEqual([ + { day: 1, weekDay: 0, month: 11, year: 2019, weekNumber: 48 }, + { day: 2, weekDay: 1, month: 11, year: 2019, weekNumber: 49 }, + { day: 3, weekDay: 2, month: 11, year: 2019, weekNumber: 49 }, + { day: 4, weekDay: 3, month: 11, year: 2019, weekNumber: 49 }, + { day: 5, weekDay: 4, month: 11, year: 2019, weekNumber: 49 }, + { day: 6, weekDay: 5, month: 11, year: 2019, weekNumber: 49 }, + { day: 7, weekDay: 6, month: 11, year: 2019, weekNumber: 49 }, + { day: 8, weekDay: 0, month: 11, year: 2019, weekNumber: 49 }, + { day: 9, weekDay: 1, month: 11, year: 2019, weekNumber: 50 }, + { day: 10, weekDay: 2, month: 11, year: 2019, weekNumber: 50 }, + { day: 11, weekDay: 3, month: 11, year: 2019, weekNumber: 50 }, + { day: 12, weekDay: 4, month: 11, year: 2019, weekNumber: 50 }, + { day: 13, weekDay: 5, month: 11, year: 2019, weekNumber: 50 }, + { day: 14, weekDay: 6, month: 11, year: 2019, weekNumber: 50 }, + { day: 15, weekDay: 0, month: 11, year: 2019, weekNumber: 50 }, + { day: 16, weekDay: 1, month: 11, year: 2019, weekNumber: 51 }, + { day: 17, weekDay: 2, month: 11, year: 2019, weekNumber: 51 }, + { day: 18, weekDay: 3, month: 11, year: 2019, weekNumber: 51 }, + { day: 19, weekDay: 4, month: 11, year: 2019, weekNumber: 51 }, + { day: 20, weekDay: 5, month: 11, year: 2019, weekNumber: 51 }, + { day: 21, weekDay: 6, month: 11, year: 2019, weekNumber: 51 }, + { day: 22, weekDay: 0, month: 11, year: 2019, weekNumber: 51 }, + { day: 23, weekDay: 1, month: 11, year: 2019, weekNumber: 52 }, + { day: 24, weekDay: 2, month: 11, year: 2019, weekNumber: 52 }, + { day: 25, weekDay: 3, month: 11, year: 2019, weekNumber: 52 }, + { day: 26, weekDay: 4, month: 11, year: 2019, weekNumber: 52 }, + { day: 27, weekDay: 5, month: 11, year: 2019, weekNumber: 52 }, + { day: 28, weekDay: 6, month: 11, year: 2019, weekNumber: 52 }, + { day: 29, weekDay: 0, month: 11, year: 2019, weekNumber: 52 }, + { day: 30, weekDay: 1, month: 11, year: 2019, weekNumber: 1 }, + { day: 31, weekDay: 2, month: 11, year: 2019, weekNumber: 1 }, + { + day: 1, + weekDay: 3, + month: 0, + year: 2020, + siblingMonth: true, + weekNumber: 1, + }, + { + day: 2, + weekDay: 4, + month: 0, + year: 2020, + siblingMonth: true, + weekNumber: 1, + }, + { + day: 3, + weekDay: 5, + month: 0, + year: 2020, + siblingMonth: true, + weekNumber: 1, + }, + { + day: 4, + weekDay: 6, + month: 0, + year: 2020, + siblingMonth: true, + weekNumber: 1, + }, + ]); + }); + + it('should return a valid Feb 1990', () => { + const calendar = new Calendar(); + const calendarDays = calendar.getCalendar(1990, 1); + expect(calendarDays[32]).toEqual(false); + }); + + it('should return a valid Feb 1996', () => { + const calendar = new Calendar(); + const calendarDays = calendar.getCalendar(1996, 1); + expect(calendarDays[32]).toEqual({ + day: 29, + weekDay: 4, + month: 1, + year: 1996, + }); + }); + + it('should return a valid Feb 2000', () => { + const calendar = new Calendar(); + const calendarDays = calendar.getCalendar(2000, 1); + expect(calendarDays[30]).toEqual({ + day: 29, + weekDay: 2, + month: 1, + year: 2000, + }); + }); + + it('should return a valid Feb 2100', () => { + const calendar = new Calendar(); + const calendarDays = calendar.getCalendar(2100, 1); + expect(calendarDays[29]).toEqual(false); + }); + + it('should adjust the month number', () => { + const calendar = new Calendar(); + const calendarDays = calendar.getCalendar(2010, 12); + const fifteenthDate = calendarDays[15]; + expect(fifteenthDate && fifteenthDate.month).toEqual(0); + expect(fifteenthDate && fifteenthDate.year).toEqual(2011); + }); + + it('should return valid date selection states for same month', () => { + const calendar = new Calendar(); + calendar.setStartDate({ year: 2010, month: 0, day: 15 }); + calendar.setEndDate({ year: 2010, month: 0, day: 17 }); + expect(calendar.isDateSelected({ year: 2010, month: 0, day: 14 })).toEqual( + false + ); + expect(calendar.isDateSelected({ year: 2010, month: 0, day: 15 })).toEqual( + true + ); + expect(calendar.isDateSelected({ year: 2010, month: 0, day: 16 })).toEqual( + true + ); + expect(calendar.isDateSelected({ year: 2010, month: 0, day: 17 })).toEqual( + true + ); + expect(calendar.isDateSelected({ year: 2010, month: 0, day: 18 })).toEqual( + false + ); + }); + + it('should return valid date selection states for same year', () => { + const calendar = new Calendar(); + calendar.setStartDate({ year: 2010, month: 1, day: 15 }); + calendar.setEndDate({ year: 2010, month: 3, day: 15 }); + expect(calendar.isDateSelected({ year: 2010, month: 0, day: 15 })).toEqual( + false + ); + expect(calendar.isDateSelected({ year: 2010, month: 1, day: 14 })).toEqual( + false + ); + expect(calendar.isDateSelected({ year: 2010, month: 1, day: 15 })).toEqual( + true + ); + expect(calendar.isDateSelected({ year: 2010, month: 1, day: 16 })).toEqual( + true + ); + expect(calendar.isDateSelected({ year: 2010, month: 2, day: 15 })).toEqual( + true + ); + expect(calendar.isDateSelected({ year: 2010, month: 3, day: 15 })).toEqual( + true + ); + expect(calendar.isDateSelected({ year: 2010, month: 3, day: 16 })).toEqual( + false + ); + expect(calendar.isDateSelected({ year: 2010, month: 4, day: 15 })).toEqual( + false + ); + }); + + it('should return valid date selection states for multiple years', () => { + const calendar = new Calendar(); + calendar.setStartDate({ year: 2010, month: 1, day: 15 }); + calendar.setEndDate({ year: 2012, month: 1, day: 15 }); + expect(calendar.isDateSelected({ year: 2010, month: 0, day: 15 })).toEqual( + false + ); + expect(calendar.isDateSelected({ year: 2010, month: 1, day: 14 })).toEqual( + false + ); + expect(calendar.isDateSelected({ year: 2010, month: 1, day: 15 })).toEqual( + true + ); + expect(calendar.isDateSelected({ year: 2010, month: 11, day: 31 })).toEqual( + true + ); + expect(calendar.isDateSelected({ year: 2011, month: 0, day: 1 })).toEqual( + true + ); + expect(calendar.isDateSelected({ year: 2011, month: 1, day: 15 })).toEqual( + true + ); + expect(calendar.isDateSelected({ year: 2011, month: 11, day: 31 })).toEqual( + true + ); + expect(calendar.isDateSelected({ year: 2012, month: 1, day: 15 })).toEqual( + true + ); + expect(calendar.isDateSelected({ year: 2012, month: 1, day: 16 })).toEqual( + false + ); + }); + + it('should return valid date diffs', () => { + expect( + Calendar.diff( + { year: 2016, month: 2, day: 1 }, + { year: 2016, month: 1, day: 1 } + ) + ).toEqual(29); + expect( + Calendar.diff( + { year: 2010, month: 0, day: 1 }, + { year: 2011, month: 0, day: 1 } + ) + ).toEqual(-365); + }); + + it('should return valid date intervals', () => { + expect( + Calendar.interval( + { year: 1986, month: 1, day: 16 }, + { year: 1986, month: 1, day: 16 } + ) + ).toEqual(1); + expect( + Calendar.interval( + { year: 1986, month: 1, day: 10 }, + { year: 1986, month: 2, day: 10 } + ) + ).toEqual(29); + expect( + Calendar.interval( + { year: 1986, month: 0, day: 1 }, + { year: 1986, month: 11, day: 31 } + ) + ).toEqual(365); + expect( + Calendar.interval( + { year: 1990, month: 0, day: 1 }, + { year: 1990, month: 11, day: 31 } + ) + ).toEqual(365); + expect( + Calendar.interval( + { year: 1996, month: 0, day: 1 }, + { year: 1996, month: 11, day: 31 } + ) + ).toEqual(366); + expect( + Calendar.interval( + { year: 2000, month: 0, day: 1 }, + { year: 2000, month: 11, day: 31 } + ) + ).toEqual(366); + expect( + Calendar.interval( + { year: 2100, month: 0, day: 1 }, + { year: 2100, month: 11, day: 31 } + ) + ).toEqual(365); + }); + + it('should return valid date comparisons', () => { + expect( + Calendar.compare( + { year: 2000, month: 0, day: 1 }, + { year: 2000, month: 0, day: 1 } + ) + ).toEqual(0); + expect( + Calendar.compare( + { year: 2000, month: 0, day: 1 }, + { year: 2000, month: 0, day: 2 } + ) + ).toEqual(-1); + expect( + Calendar.compare( + { year: 2000, month: 0, day: 2 }, + { year: 2000, month: 0, day: 1 } + ) + ).toEqual(1); + expect( + Calendar.compare( + { year: 2000, month: 0, day: 1 }, + { year: 2000, month: 1, day: 1 } + ) + ).toEqual(-1); + expect( + Calendar.compare( + { year: 2000, month: 1, day: 1 }, + { year: 2000, month: 0, day: 1 } + ) + ).toEqual(1); + expect( + Calendar.compare( + { year: 2001, month: 0, day: 1 }, + { year: 2000, month: 0, day: 1 } + ) + ).toEqual(1); + expect( + Calendar.compare( + { year: 2000, month: 0, day: 1 }, + { year: 2001, month: 0, day: 1 } + ) + ).toEqual(-1); + }); + + it('should set starting date', () => { + const calendar = new Calendar(); + calendar.setStartDate({ year: 2010, month: 1, day: 15 }); + expect(calendar.startDate).toEqual({ year: 2010, month: 1, day: 15 }); + }); + + it('should set ending date', () => { + const calendar = new Calendar(); + calendar.setEndDate({ year: 2010, month: 1, day: 15 }); + expect(calendar.endDate).toEqual({ year: 2010, month: 1, day: 15 }); + }); + + it('should return valid days in month', () => { + expect(Calendar.daysInMonth(1988, 1)).toEqual(29); + expect(Calendar.daysInMonth(1988, 7)).toEqual(31); + expect(Calendar.daysInMonth(2015, 10)).toEqual(30); + }); +}); diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..b6e40f6 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "alwaysStrict": true, + "baseUrl": "./", + "declaration": true, + "esModuleInterop": true, + "importHelpers": true, + "lib": [ + "dom", + "esnext" + ], + "module": "esnext", + "moduleResolution": "node", + "noFallthroughCasesInSwitch": true, + "noImplicitAny": true, + "noImplicitReturns": true, + "noImplicitThis": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "rootDir": "./", + "sourceMap": true, + "strict": true, + "strictFunctionTypes": true, + "strictNullChecks": true, + "strictPropertyInitialization": true, + "target": "es5" + }, + "include": [ + "src", + "types", + "test" + ] +} \ No newline at end of file