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

60,723

Solution 1

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.

Solution 2

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"));
});

Solution 3

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.

Solution 4

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>

Solution 5

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')));
Share:
60,723
ecorvo
Author by

ecorvo

Hi, I am a Software Engineer passionate about web development and open source...

Updated on August 19, 2021

Comments

  • ecorvo
    ecorvo over 2 years

    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.

  • hamdanjz4
    hamdanjz4 over 5 years
    Maybe you can use this instead, daysInMonth.push(monthDate.format('DD-ddd')); to get proper expected format
  • Ahmed Elbatt
    Ahmed Elbatt almost 5 years
    property range doesn't exist on type 'Moment'
  • Antoine Rucquoy
    Antoine Rucquoy over 4 years
    @Ahmed, you have to intall range-moment package and extend it in your code: github.com/rotaready/moment-range
  • Ahmed Elbatt
    Ahmed Elbatt over 4 years
    @AntoineRucquoy, that's what I have already did. Thanks man for your help !
  • RavenTheX
    RavenTheX about 4 years
    Your code work only current date, if i pass on format for example "'2020-01', 'YYYY-MM'", date calculate not right
  • RavenTheX
    RavenTheX about 4 years
    Your can explain please what in your code doing const addDays?
  • Dennis T
    Dennis T about 4 years
    The mDate initially has the first day of the month. So the const addDays says increase the day from the second iteration.
  • tomhughes
    tomhughes about 4 years
    @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.
  • MRPMOHIBURRAHMAN
    MRPMOHIBURRAHMAN over 2 years
    @nicolas, is there any way to use it on react native?
  • nicolas
    nicolas over 2 years
    Looks like some people did :) github.com/rotaready/moment-range/issues/251