40

Using Moment.js I would like to get all days in a month of specific year in an array. For example:

January-2014:
[
"01-wed",
"02-thr",
"03-fri",
"04-sat"
]

any suggestions? I looked through Moment.js docs but couldn't find anything. The closet I got was this:

moment("2012-02", "YYYY-MM").daysInMonth() 

But this only return an int with total days for specific month not an array with each day.

valdeci
  • 13,962
  • 6
  • 55
  • 80
ecorvo
  • 3,559
  • 4
  • 24
  • 35
  • I assume that should be `"04-sat"` rather than `"04-say"`, and followed by `"05-sun", "06-mon", "07-tue", "08-wed"` and so on? Why do you need this? – Mark Reed Aug 31 '14 at 02:45
  • Yes, say was a typo. I need this to display in a drop down so user can pick a year then month then a day inside the year-month conbination. But rather than showing 1,2,3... for the days I would also like to show the day name 1-mon, 2-tues, 3-wed... – ecorvo Aug 31 '14 at 02:51
  • See my answer below. For the purpose of having someone pick a date, though, I would recommend using one of the many available JavaScript calendar date pickers. – Mark Reed Aug 31 '14 at 02:55
  • I will be using date picker for other stuff in this Calendar Plugin I am working on, but for this specific part of the application it need to be a drop down. Thanks for the answer. – ecorvo Aug 31 '14 at 02:57

12 Answers12

60

Here's a function that will do the trick (not using Moment, but just vanilla JavaScript):

var getDaysArray = function(year, month) {
  var monthIndex = month - 1; // 0..11 instead of 1..12
  var names = [ 'sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat' ];
  var date = new Date(year, monthIndex, 1);
  var result = [];
  while (date.getMonth() == monthIndex) {
    result.push(date.getDate() + '-' + names[date.getDay()]);
    date.setDate(date.getDate() + 1);
  }
  return result;
}

For example:

js> getDaysArray(2012,2)
["1-wed", "2-thu", "3-fri", "4-sat", "5-sun", "6-mon", "7-tue",
 "8-wed", "9-thu", "10-fri", "11-sat", "12-sun", "13-mon", "14-tue",
"15-wed", "16-thu", "17-fri", "18-sat", "19-sun", "20-mon", "21-tue", 
"22-wed", "23-thu", "24-fri", "25-sat", "26-sun", "27-mon", "28-tue",
"29-wed"]

ES2015+ version - also hid the array of names behind a closure so it's only initialized once:

const getDaysArray = (function() {
  const names = Object.freeze([ 'sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat' ]);
  return (year, month) => {
    const monthIndex = month - 1
    const date = new Date(year, monthIndex, 1);
    const result = [];
    while (date.getMonth() == monthIndex) {
      result.push(`${date.getDate()}-${names[date.getDay()]}`);
      date.setDate(date.getDate() + 1);
    }
    return result;
  }
})();

As a side note, you can see that declaring the date const doesn't keep us from mutating it (nor would Object.freeze, used to make the weekday names array immutable, do anything to a Date). We're taking advantage of the mutability here, but if we actually wanted an immutable Date with the language enforcing that immutability in current Javascript, we'd have to go to some length.

Also note that the solutions above don't zero-pad dates before the 10th, unlike the sample output included in the question. With ES2017+ that's pretty easy to fix:

    result.push(`${date.getDate()}`.padStart(2,'0') + `-${names[date.getDay()]}`);

Doing it in older versions of JS requires rolling your own zero-padding logic, which isn't hard but is also not really the focus of the question.

Mark Reed
  • 91,912
  • 16
  • 138
  • 175
25

Alternative with momentjs, working for me

function getDaysArrayByMonth() {
  var daysInMonth = moment().daysInMonth();
  var arrDays = [];

  while(daysInMonth) {
    var current = moment().date(daysInMonth);
    arrDays.push(current);
    daysInMonth--;
  }

  return arrDays;
}

And you can check

var schedule = getDaysArrayByMonth();
schedule.forEach(function(item) {
  console.log(item.format("DD/MM"));
});
victorkurauchi
  • 1,390
  • 18
  • 23
19

Below are two nice functional approaches with no external dependency other than Moment:

const currentMonthDates = new Array(moment().daysInMonth()).fill(null).map((x, i) => moment().startOf('month').add(i, 'days'));
const currentMonthDates = Array.from({length: moment().daysInMonth()}, (x, i) => moment().startOf('month').add(i, 'days'));

This returns an array of Moment objects, you can then run whatever format method on it that you wish.

For further reading Creating and filling Arrays of arbitrary lengths in JavaScript, also note that in the first example you have to fill the array with null before mapping over it, as it is still classed as empty before doing so and therefore the map function would not run.

tomhughes
  • 4,597
  • 2
  • 24
  • 33
  • 1
    Your code work only current date, if i pass on format for example "'2020-01', 'YYYY-MM'", date calculate not right – RavenTheX Feb 24 '20 at 22:36
  • @RavenTheX You can pass in any date, simply replace instances of moment() with moment(date, format). Your format will have to include a day (not YYYY-MM) as otherwise you do not have a starting point to add days on. If you are hardcoding the date you can always set it to the 1st of the desired month and omit the .startOf(month) call. – tomhughes Mar 05 '20 at 17:20
13

You could use _.times helper from lodash alongside moment like so:

    var daysInMonth = [];

    var monthDate = moment().startOf('month'); // change to a date in the month of interest

    _.times(monthDate.daysInMonth(), function (n) {
      daysInMonth.push(monthDate.format('DD-ddd'));  // your format
      monthDate.add(1, 'day');
    });
    
    console.log(daysInMonth)
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.15/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
Deano
  • 11,582
  • 18
  • 69
  • 119
vinjenzo
  • 1,490
  • 13
  • 13
  • Maybe you can use this instead, `daysInMonth.push(monthDate.format('DD-ddd')); ` to get proper expected format – hamdanjz4 Nov 27 '18 at 06:32
4

Alternatively you might now use moment range to achieve this :

const month = moment('2012-02', 'YYYY-MM');
const range = moment().range(moment(month).startOf('month'), moment(month).endOf('month'));
const days = range.by('days');

console.log([...days].map(date => date.format('DD-ddd')));
nicolas
  • 712
  • 4
  • 15
3

I think that using the method moment(month).daysInMonth() to get the number of days in a month together with Array.from() to generate the array is the cleaner and performative way.

const getDaysByMonth = (month) => {
  const daysInMonth = moment(month).daysInMonth();
  return Array.from({length: daysInMonth}, (v, k) => k + 1)
};

let month = '2019-02';
console.log(`February => ${getDaysByMonth(month)}`);

month = '2019-06';
console.log(`June => ${getDaysByMonth(month)}`);

month = '2019-07';
console.log(`July => ${getDaysByMonth(month)}`);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
valdeci
  • 13,962
  • 6
  • 55
  • 80
2

To get days in a month with moment.js i use this one :

  function daysInMonth(month) {
    var count =  moment().month(month).daysInMonth();
    var days = [];
    for (var i = 1; i < count+1; i++) {
      days.push(moment().month(month).date(i));
    }
    return days;
  }

Then to call the function

var days = daysInMonth( moment().month() );
mchev
  • 713
  • 1
  • 8
  • 22
2

Came to this post making a date picker (yeah...) - I went with a similar approach to the top answer but I think the for loop is a bit more intuitive/readable personally. This does use JS 0 based date so 5 = June, 1 = February, etc. - you can just omit the "+1" in the date for 1 based date.

var getDaysInMonth = function(year, month) {
  var names = [ 'sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat' ];
  var date = new Date(year, month + 1, 0);
  var days = date.getDate();
  var dayList = [];
  for (i = days; days > 0; days--) {      
    date.setDate(date.getDate() + 1);
    dayList.push((dayList.length + 1) + '-' + names[date.getDay()]);
  }
  return dayList;
}
MrRobboto
  • 722
  • 3
  • 10
2
function getAllDatesOfMonth(date) {
    const mDate = moment(date, "YYYY-MM");
    const daysCount = mDate.daysInMonth();
    return Array(daysCount).fill(null).map((v,index)=>{
        const addDays = index === 0 ? 0 : 1;
        return mDate.add(addDays, 'days').format('YYYY-MM-DD');
    });
}
Dennis T
  • 109
  • 4
1

you can do it using for loop with moment

var daysInMonth = [];

 var monthDate = moment().startOf('month'); 

 for(let i=0;i<monthDate.daysInMonth();i++){
    let newDay=monthDate.clone().add(i,'days');
    daysInMonth.push(newDay.format('DD-ddd')); 
}
    
console.log(daysInMonth)
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
Saurabh Mistry
  • 12,833
  • 5
  • 50
  • 71
0

This is a little different way to do it but can be used for a list of days in a month:

const getListOfDays = (year, month) => {
  const list = [];
  const date = `${year}-${('0'+month).slice(-2)}`
  const from = moment(date);
  const to = moment(date).add(1, 'months');
  for (let m = moment(from); m.isBefore(to); m.add(1, 'days')) {
   list.push(m.format('YYYY-MM-DD'));
  }
  return list;
};

console.log(getListOfDays(2022,9))
Przemek Nowicki
  • 572
  • 4
  • 7
-5

As of moment.js version 2.1.0, when you set a date like:

    moment([2012, 0, 31]).month(1).format("YYYY-MM-DD"); // 2012-02-29

Then you just need to parse the date and you have the number of days in a month.

ale
  • 6,369
  • 7
  • 55
  • 65