How to get list of days in a month with Moment.js
Asked Answered
B

12

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.

Bristol answered 31/8, 2014 at 2:27 Comment(4)
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?Infuscate
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...Bristol
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.Infuscate
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.Bristol
I
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.

Infuscate answered 31/8, 2014 at 2:52 Comment(0)
P
26

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"));
});
Paulita answered 14/12, 2015 at 19:30 Comment(0)
L
20

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.

Lesialesion answered 3/1, 2019 at 12:3 Comment(2)
Your code work only current date, if i pass on format for example "'2020-01', 'YYYY-MM'", date calculate not rightDerek
@Derek 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.Lesialesion
B
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/[email protected]/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
Breeding answered 6/1, 2016 at 17:51 Comment(1)
Maybe you can use this instead, daysInMonth.push(monthDate.format('DD-ddd')); to get proper expected formatRonen
V
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')));
Vegetarian answered 22/10, 2018 at 11:33 Comment(5)
property range doesn't exist on type 'Moment'Massive
@Ahmed, you have to intall range-moment package and extend it in your code: github.com/rotaready/moment-rangeSuspensoid
@AntoineRucquoy, that's what I have already did. Thanks man for your help !Massive
@nicolas, is there any way to use it on react native?Knighton
Looks like some people did :) github.com/rotaready/moment-range/issues/251Vegetarian
N
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>
Napolitano answered 29/7, 2019 at 20:9 Comment(0)
T
3
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');
    });
}
Terribly answered 19/10, 2019 at 18:0 Comment(2)
Your can explain please what in your code doing const addDays?Derek
The mDate initially has the first day of the month. So the const addDays says increase the day from the second iteration.Terribly
F
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() );
Fomalhaut answered 5/2, 2019 at 14:53 Comment(0)
R
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;
}
Racism answered 29/3, 2019 at 21:39 Comment(0)
P
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>
Platinize answered 6/5, 2020 at 19:53 Comment(0)
H
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))
Horsefaced answered 21/9, 2022 at 7:24 Comment(0)
N
-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.

Nikos answered 5/6, 2016 at 12:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.