41

is there a way to have all the days of a month or of a year? I am looking for this in order to disable some specific days in a datepicker, i would have a page in the back-office to select these days to disable.

So i would need to show all the days in a month, and add a "activate or deactive" button below each day. Is there a way to find these days with the Date object? I found this link for example : Displaying all the days of a month but i don't really understand it, plus it is Java, i am trying to find a solution in javascript.

Thank you for your help

Joshua Wade
  • 4,755
  • 2
  • 24
  • 44
Paul
  • 6,108
  • 14
  • 72
  • 128

10 Answers10

114

To get a list of all days in a month, you can start with a Date on the first day of a month, increase the day until the month changes.

/**
 * @param {int} The month number, 0 based
 * @param {int} The year, not zero based, required to account for leap years
 * @return {Date[]} List with date objects for each day of the month
 */
function getDaysInMonth(month, year) {
  var date = new Date(year, month, 1);
  var days = [];
  while (date.getMonth() === month) {
    days.push(new Date(date));
    date.setDate(date.getDate() + 1);
  }
  return days;
}

UTC Version

In response to some comments, I've created a version that uses UTC methods in case you want to call UTC methods instead of the standard methods that return the localized time zone.

I suspect this is the culprit of the comments saying this didn't work. You typically want to make sure you call getUTCMonth/Day/Hours methods if you instantiated it with Date.UTC, and vice-versa, unless you are trying to convert time zones and show differences.

function getDaysInMonthUTC(month, year) {
  var date = new Date(Date.UTC(year, month, 1));
  var days = [];
  while (date.getUTCMonth() === month) {
    days.push(new Date(date));
    date.setUTCDate(date.getUTCDate() + 1);
  }
  return days;
}

Editing This Answer

If you think there's a problem with this script, please feel free to:

  • First see existing unit tests below
  • Write a test case that proves it's broken.
  • Fix the code, making sure existing tests pass.

Unit Tests

/**
 * @param {int} The month number, 0 based
 * @param {int} The year, not zero based, required to account for leap years
 * @return {Date[]} List with date objects for each day of the month
 */
function getDaysInMonthUTC(month, year) {
  var date = new Date(Date.UTC(year, month, 1));
  var days = [];
  while (date.getUTCMonth() === month) {
    days.push(new Date(date));
    date.setUTCDate(date.getUTCDate() + 1);
  }
  return days;
}

function getDaysInMonth(month, year) {
  var date = new Date(year, month, 1);
  var days = [];
  while (date.getMonth() === month) {
    days.push(new Date(date));
    date.setDate(date.getDate() + 1);
  }
  return days;
}

const days2020 = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
const days2021 = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];

describe("getDaysInMonthUTC", function() {
  it("gets day counts for leap years", function() {
    const actual = days2020.map(
      (day, index) => getDaysInMonthUTC(index, 2020).length
    );
    expect(actual).toEqual(days2020);
  });

  it("gets day counts for non-leap years", function() {
    const actual = days2021.map(
      (day, index) => getDaysInMonthUTC(index, 2021).length
    );
    expect(actual).toEqual(days2021);
  });
});


describe("getDaysInMonth", function() {
  it("gets day counts for leap years", function() {
    const actual = days2020.map(
      (day, index) => getDaysInMonth(index, 2020).length
    );
    expect(actual).toEqual(days2020);
  });

  it("gets day counts for non-leap years", function() {
    const actual = days2021.map(
      (day, index) => getDaysInMonth(index, 2021).length
    );
    expect(actual).toEqual(days2021);
  });
});

// load jasmine htmlReporter
(function() {
  var env = jasmine.getEnv();
  env.addReporter(new jasmine.HtmlReporter());
  env.execute();
}());
<script src="https://cdn.jsdelivr.net/jasmine/1.3.1/jasmine.js"></script>
<script src="https://cdn.jsdelivr.net/jasmine/1.3.1/jasmine-html.js"></script>
<link href="https://cdn.jsdelivr.net/jasmine/1.3.1/jasmine.css" rel="stylesheet"/>
Ruan Mendes
  • 90,375
  • 31
  • 153
  • 217
  • 3
    Minor correction to the code date.setDate(date.getDate() + 1); should go before date.push array call – Timothy Mugayi Jan 08 '18 at 13:56
  • @Timothy What's the test case that this doesn't work? – Ruan Mendes Jan 08 '18 at 14:53
  • @Timothy Only if you want to exclude the first day (1 January or wherever you start the script). – Janus Bahs Jacquet Jul 19 '18 at 06:56
  • 1
    @Timothy was right that the script does not always work. It only works in certain timezones. I've edited the answer to fix it. – Diego Faria Jul 23 '19 at 09:39
  • @DiegoFaria Your fix made the problem a worse and both you and Timothy are misunderstanding something :) You forgot to update `setDate` and `getDate` to also use UTC methods. I understand that using UTC methods is usually the best option. typically, if you keep your calls consistent in terms of `UTC`ness. I wrote some tests to prove it. Feel free to go in and create new test cases that explain where you were seeing a problem. I believe staying consistent in how you instantiate the Date will make it work, so use the correct `getDays`, depending on what methods you're calling – Ruan Mendes Jan 02 '20 at 14:57
  • It should be days.push(date); instead of days.push(new Date(date)); or else it will generate n-1 days for the month with n days. – chris Jul 05 '21 at 07:49
  • @chris you should post a unit test showing what you mean because my tests prove they do work for the cases posted – Ruan Mendes Jul 06 '21 at 12:14
13

One liner to get all days as Date object in a month

const getDaysInMonth = (month, year) => (new Array(31)).fill('').map((v,i)=>new Date(year,month-1,i+1)).filter(v=>v.getMonth()===month-1)
chickens
  • 19,976
  • 6
  • 58
  • 55
13

Using ES6 Array Initializer

You can get the number of days in a specified month, and then create a new array with that length and each of the days as items.

const getAllDaysInMonth = (month, year) =>
  Array.from(
    { length: new Date(year, month, 0).getDate() },
    (_, i) => new Date(year, month - 1, i + 1)
  );

Demo in Stack Snippets

const getAllDaysInMonth = (month, year) =>
  Array.from(
    {length: new Date(year, month, 0).getDate()}, // get next month, zeroth's (previous) day
    (_, i) => new Date(year, month - 1, i + 1)    // get current month (0 based index)
  );

const allDatesInOctober = getAllDaysInMonth(10, 2021)

console.log(allDatesInOctober.map(x => x.toLocaleDateString([], { month: "short", day: "numeric" })))

// ['Oct 1', 'Oct 2', 'Oct 3', 'Oct 4', 'Oct 5', 'Oct 6', 'Oct 7', 'Oct 8', 'Oct 9', 'Oct 10', 'Oct 11', 'Oct 12', 'Oct 13', 'Oct 14', 'Oct 15', 'Oct 16', 'Oct 17', 'Oct 18', 'Oct 19', 'Oct 20', 'Oct 21', 'Oct 22', 'Oct 23', 'Oct 24', 'Oct 25', 'Oct 26', 'Oct 27', 'Oct 28', 'Oct 29', 'Oct 30', 'Oct 31']
naveen
  • 53,448
  • 46
  • 161
  • 251
KyleMit
  • 30,350
  • 66
  • 462
  • 664
4

I'm not sure from your description if the standard disable dates datepicker will work with you, so I'll answer you question directly.

You can construct an array of days for a month fairly easily by doing this:

var numOfDays = new Date(2012, 10, 0).getDate(); //use 0 here and the actual month
var days = new Array();

//This will construct an array with all the elements represent the day of the week 
//(i.e. Oct 30th would be days[30-1] or days[29]) and the value would be the actual 
//day of the week (i.e. Tuesday which is representing by the number 2)
for(var i=0;i<=numOfDays;i++)
{
    days[i] = new Date(2012,9,i+1).getDay(); //use month-1 here            
}
//This will give you a number from 0 - 6 which represents (Sunday - Saturday)
alert(days[29]); 

​ Using that array of days you can pretty much do whatever you want with it and know the day of the week as well.

1

Here's a loopp that runs through each month to determine the last day of that month. Javascript Date object indexes months starting at zero and if you set the day to zero it reverts back to last day of prior month. Handy for determining leap year last day for February

Date( 2012, 12, 0) will return Dec 31, 2012

Date (2012,0,0) will return Dec 31,2011

and the all important one to figure out is February with

Date ( 2012,3,0) Returns Feb 29 since leap year this year

var mos=['jan','feb','mar','apr','may','jun','jul','aug','sep','oct','nov','dec']

for (i = 0; i < 12; i++) {
    var lastDate = new Date(2012, i+1, 0);
    $('body').append('Last day of ' + mos[i] + ' is ' + lastDate.getDate()+'<br>')
}

DEMO: http://jsfiddle.net/5k8sn/1/

charlietfl
  • 170,828
  • 13
  • 121
  • 150
1

I have implemented the functionality you requested using a jQuery datepicker.

First, add all the dates selected in the back office to be disabled into an array

// format yyyy-mm-dd
var disabledDates = [
    "2012-10-01",
    "2012-10-02",
    "2012-10-30",
    "2012-09-12"
];

Second, specify the datepicker with two functions

$("#datepicker").datepicker({

    // only enable date if dateEnabled returns [true]
    beforeShowDay: dateEnabled,

    // once a date has been selected call dateSelected
    onSelect: dateSelected
});

Here is the definition of the required functions

function dateEnabled( d ) {

    // if date found in array disable date
    if( disabledDates.indexOf( getDate( d ) ) > -1 ) {

        return [false];

    } else {

        return [true] ;

    }
}  

Convert date to string for comparison with dates in array

function getDate( d ) {
    var day,
        month,
        year;

    day = d.getDate( );
    month = d.getMonth( ) + 1; // add 1 as getMonth returns 0 - 11
    year = d.getFullYear( );

    if( month < 10 ) month = "0" + month;
    if( day < 10 ) day = "0" + day;
    return year + "-" + month + "-" + day;
}

Once a date has been selected process it

function dateSelected( d ) { 
   // do stuff with string representation of date                                          
}

Here is a fiddle http://jsfiddle.net/KYzaR/7/

Just thought it would be worth mentioning that Array.indexOf is a recent addition to ECMA-262 standard and so in the case of IE7 and IE8 it is not supported. The following MDN page provides code that implements Array.indexOf for these browsers https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/indexOf

Bruno
  • 5,772
  • 1
  • 26
  • 43
  • @Juan Mendes I'm not sure to understand what you mean, how should we do if we don't use indexOf? – Paul Oct 31 '12 at 00:09
1

This part "new Date(year, month , 0)" will get last day of month, so you need only iterate from this days creating all days fron 1 until last day.

public getAllDaysOfMonth(year:number, month: number){
   const lastDayOfMonth = new Date(year, month , 0).getDate();
   for (let i = 1; i < lastDayOfMonth + 1; i++) {
     console.log('day', new Date(year, month - 1, i)) //Here will print all days
   }
}
0

To disable dates in a datepicker, you can use the answer described here:
https://stackoverflow.com/a/12061715/48082

To choose multiple dates (as in the back-office app), you can use this plugin:
http://multidatespickr.sourceforge.net/

Community
  • 1
  • 1
Cheeso
  • 189,189
  • 101
  • 473
  • 713
0

I have a solution. Happy coding ❤️ !! Note: 0=January, 1=February etc. example w3schools

const getDays = (month, year) => {
    let date = new Date(`${year}-${parseInt(month)+1}-01`);
    let days = [];
    while (date.getMonth() === parseInt(month)) {
        days.push(date.getDate());
        date.setDate(date.getDate() + 1);
    }
    return days;
}
0

Why don't you get all days in a month in array like this.

 const getDaysInMonth = (month,year,index=1,result=[]) =>{
            const date = new Date(year,month,index)
            return month == date.getMonth() ? getDaysInMonth(month,year,index+1,[...result,date]) : result
        }

then count them

const countDaysOfMonth = daysInMonth => daysInMonth.reduce((acc,value) => acc+1 ,0)

And then divide the total using Math.ceil 7 to get the number of rows for the number of weeks

const countWeeksInMonth = numberOfDays => Math.ceil(numberOfDays / 7)
ktertz
  • 1
  • 1