116

I need to calculate a JS date given year=2014 and month=9 (September 2014).

I tried this:

var moment = require('moment');
var startDate = moment( year+'-'+month+'-'+01 + ' 00:00:00' );
            var endDate = startDate.endOf('month');
            console.log(startDate.toDate());
            console.log(endDate.toDate());

Both of logs show:

Tue Sep 30 2014 23:59:59 GMT+0200 (CEST)
Tue Sep 30 2014 23:59:59 GMT+0200 (CEST)

End date is correct but... why the start date is not?

Fabio B.
  • 9,138
  • 25
  • 105
  • 177

12 Answers12

206

That's because endOf mutates the original value.

Relevant quote:

Mutates the original moment by setting it to the end of a unit of time.

Here's an example function that gives you the output you want:

function getMonthDateRange(year, month) {
    var moment = require('moment');

    // month in moment is 0 based, so 9 is actually october, subtract 1 to compensate
    // array is 'year', 'month', 'day', etc
    var startDate = moment([year, month - 1]);

    // Clone the value before .endOf()
    var endDate = moment(startDate).endOf('month');

    // just for demonstration:
    console.log(startDate.toDate());
    console.log(endDate.toDate());

    // make sure to call toDate() for plain JavaScript date type
    return { start: startDate, end: endDate };
}

References:

klyd
  • 3,939
  • 3
  • 24
  • 34
  • 5
    `moment` is idempotent so you could also use `endDate = moment(starDate).endOf("month")` **^.^** – Mulan Sep 30 '14 at 22:33
  • 1
    Absolutely, in fact the default way to clone an object in the documentation is `moment()`. Updated the example to use some of the shorter functions. – klyd Sep 30 '14 at 22:39
  • 1
    Thank you. I spent two hours trying to figure out why it wasnt working. – Leon Sep 30 '15 at 00:44
  • 1
    first time I've ever seen the word idempotent used on the web!! well done naomik – Mike Dec 18 '15 at 14:30
  • `add(-1,"month")` doesn't work when its January and you want to get the last year's month. – Akhoy Jan 19 '17 at 13:31
  • Good stuff, but last comment happens to me too. – hugocarlmartin Jan 24 '17 at 15:46
  • Looks like `add(-1,"month")` was added in an edit. I've removed it, looks like the code works properly now. In general though, if you use this (or any code from stack overflow), please rewrite and test drive it! (and then let me know what I screwed up so I can fix the answer :)) – klyd Jan 24 '17 at 17:26
32

you can use this directly for the end or start date of the month

new moment().startOf('month').format("YYYY-DD-MM");
new moment().endOf("month").format("YYYY-DD-MM");

you can change the format by defining a new format

candidJ
  • 4,289
  • 1
  • 22
  • 32
Shakti Jadon
  • 421
  • 4
  • 2
17

When you use .endOf() you are mutating the object it's called on, so startDate becomes Sep 30

You should use .clone() to make a copy of it instead of changing it

var startDate = moment(year + '-' + month + '-' + 01 + ' 00:00:00');
            var endDate = startDate.clone().endOf('month');
            console.log(startDate.toDate());
            console.log(endDate.toDate());

Mon Sep 01 2014 00:00:00 GMT+0700 (ICT) 
Tue Sep 30 2014 23:59:59 GMT+0700 (ICT) 
bakkal
  • 54,350
  • 12
  • 131
  • 107
6

Try the following code:

const moment=require('moment');
console.log("startDate=>",moment().startOf('month').format("YYYY-DD-MM"));
console.log("endDate=>",moment().endOf('month').format("YYYY-DD-MM"));
Valdi_Bo
  • 30,023
  • 4
  • 23
  • 41
Sanjay Singh
  • 61
  • 2
  • 4
3

Don't really think there is some direct method to get the last day but you could do something like this:

var dateInst = new moment();
/**
 * adding 1 month from the present month and then subtracting 1 day, 
 * So you would get the last day of this month 
 */
dateInst.add(1, 'months').date(1).subtract(1, 'days');
/* printing the last day of this month's date */
console.log(dateInst.format('YYYY MM DD'));
Community
  • 1
  • 1
Sandeep Gantait
  • 837
  • 8
  • 9
2

your startDate is first-day-of-month, In this case we can use

var endDate = moment(startDate).add(1, 'months').subtract(1, 'days');

Hope this helps!!

nikhil
  • 203
  • 1
  • 10
0
var d = new moment();
var startMonth = d.clone().startOf('month');
var endMonth = d.clone().endOf('month');
console.log(startMonth, endMonth);

doc

IfThenElse
  • 485
  • 5
  • 13
0

const year = 2014;
const month = 09;

// months start at index 0 in momentjs, so we subtract 1
const startDate = moment([year, month - 1, 01]).format("YYYY-MM-DD");

// get the number of days for this month
const daysInMonth = moment(startDate).daysInMonth();

// we are adding the days in this month to the start date (minus the first day)
const endDate = moment(startDate).add(daysInMonth - 1, 'days').format("YYYY-MM-DD");

console.log(`start date: ${startDate}`);
console.log(`end date:   ${endDate}`);
<script
src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.20.1/moment.min.js">
</script>
JSON C11
  • 11,272
  • 7
  • 78
  • 65
0
const dates = getDatesFromDateRange("2014-05-02", "2018-05-12", "YYYY/MM/DD", 1);           
console.log(dates);
// you get the whole from-to date ranges as per parameters
var onlyStartDates = dates.map(dateObj => dateObj["to"]);
console.log(onlyStartDates);
// moreover, if you want only from dates then you can grab by "map" function

function getDatesFromDateRange( startDate, endDate, format, counter ) {
    startDate = moment(startDate, format);
    endDate = moment(endDate, format);

    let dates = [];
    let fromDate = startDate.clone();
    let toDate = fromDate.clone().add(counter, "month").startOf("month").add(-1, "day");
    do {
        dates.push({
            "from": fromDate.format(format),
            "to": ( toDate < endDate ) ? toDate.format(format) : endDate.format(format)
        });
        fromDate = moment(toDate, format).add(1, "day").clone();
        toDate = fromDate.clone().add(counter, "month").startOf("month").add(-1, "day");
    } while ( fromDate < endDate );
    return dates;
}

Please note, .clone() is essential in momentjs else it'll override the value. It seems in your case.

It's more generic, to get bunch of dates that fall between dates.

-1

Here is a concise & exact answer:

  // month in moment is 0 based, so 0 is actually january, subtract 1 to compensate.
  var startDate = moment([year, month - 1]).format()    
  var endDate = moment(startDate).clone().endOf('month').format()

Example

let month = 1         // January   
let year = 2021  

var startDate = moment([year, month - 1]).format()

var endDate = moment(startDate).clone().endOf('month').format()

console.log(startDate)
//2021-01-01T00:00:00-07:00

console.log(endDate)
//2021-01-31T23:59:59-07:00 
Ibad Shaikh
  • 2,704
  • 3
  • 15
  • 27
  • This is exactly the same as the accepted answer, except for the unnecessary step of formatting as a string, and the step of parsing that string to a moment. – Heretic Monkey Apr 29 '21 at 15:56
  • Dear @HereticMonkey. The endDate of accepted answer was coming the first date of the next month like for example if the selected month is January, it was displaying the last date as the 1st of February. So I simplified it! – Ibad Shaikh Apr 29 '21 at 16:23
-2

The following code should work:

$('#reportrange').daterangepicker({
                startDate: start,
                endDate: end,
                ranges: {
                    'Hoy': [moment(), moment()],
                    'Ayer': [moment().subtract(1, 'days'), moment().subtract(1, 'days')],
                    'Ultimos 7 dias': [moment().subtract(6, 'days'), moment()],
                    'Ultimos 30 dias': [moment().subtract(29, 'days'), moment()],
                    'Mes actual': [moment().startOf('month'), moment().endOf('month')],
                    'Ultimo mes': [moment().subtract(1, 'month').startOf('month'), moment().subtract(1, 'month').endOf('month')],
                    'Enero': [moment().month(0).startOf('month') , moment().month(0).endOf('month')],
                    'Febrero': [moment().month(1).startOf('month') , moment().month(1).endOf('month')],
                    'Marzo': [moment().month(2).startOf('month') , moment().month(2).endOf('month')],
                    'Abril': [moment().month(3).startOf('month') , moment().month(3).endOf('month')],
                    'Mayo': [moment().month(4).startOf('month') , moment().month(4).endOf('month')],
                    'Junio': [moment().month(5).startOf('month') , moment().month(5).endOf('month')],
                    'Julio': [moment().month(6).startOf('month') , moment().month(6).endOf('month')],
                    'Agosto': [moment().month(7).startOf('month') , moment().month(7).endOf('month')],
                    'Septiembre': [moment().month(8).startOf('month') , moment().month(8).endOf('month')],
                    'Octubre': [moment().month(9).startOf('month') , moment().month(9).endOf('month')],
                    'Noviembre': [moment().month(10).startOf('month') , moment().month(10).endOf('month')],
                    'Diciembre': [moment().month(11).startOf('month') , moment().month(11).endOf('month')]
                }
            }, cb);
Joel
  • 1,564
  • 7
  • 12
  • 20
-2

Try the following code:

moment(startDate).startOf('months')
moment(startDate).endOf('months')
sacmii
  • 19
  • 2
    Welcome to Stack Overflow. There are ten other answers to this question; it would be good of you to explain why yours is better or preferable than the others. – chb May 30 '19 at 05:32
  • it is not giving expected o/p – gkd Mar 02 '20 at 06:27