javascript Date library repeating October - javascript

While trying to find out why I was having issues while working on a calendar, I ran into this issue. When setting the month to 8, the date is set to October, when the month is set to 9, the date is set to October.
Code to test
var d = new Date();
document.write(d.getMonth());
d.setMonth(8);
document.write(d.getMonth());
d.setMonth(9);
document.write(d.getMonth());
output:
799
The current date is August 31st 2012, the month number should be 7, since the javascript months are 0 based.
Can someone explain this? I have been able to reproduce it on more than one computer.

September only has 30 days - when you set the day to 31 (or create a date on the 31st of some month) and then change the month to one with fewer than 31 days JavaScript rolls the date over into the next month (in this case October). In other words, the date overflows.
> var d = new Date()
> d
Fri Aug 31 2012 22:53:50 GMT-0400 (EDT)
// Set the month to September, leaving the day set to the 31st
> d.setMonth(8)
> d
Mon Oct 01 2012 22:53:50 GMT-0400 (EDT)
// Doing the same thing, changing the day first
> var d = new Date()
> d
Fri Aug 31 2012 22:53:50 GMT-0400 (EDT)
> d.setDate(30)
> d
Thu Aug 30 2012 22:53:50 GMT-0400 (EDT)
> d.setMonth(8)
Sun Sep 30 2012 22:53:50 GMT-0400 (EDT)
So the simple answer is, because the date for today is the 31st of August and the 31st of September is October 1st.

Related

Google Apps Script add month to a date until specific date is reached

I have the following code using Google Apps Script, but when I log it out I get the following results. I want GAS to log the next month and stop once it gets to "lastDateofYear ". For whatever reason, the year doesn't change in my results, it just keeps repeating the current year. Please help.
var thisDate = "Mon Dec 20 00:00:00 GMT-06:00 2021";
var nextYear = Number(currentYear)+1;
var lastDateofYear = new Date("12-31-"+nextYear);
for(var i=thisDate; i <= lastDateofYear; ){
var currentiDate = new Date(i);
var month = currentiDate.getMonth()+1;
i.setMonth((month) % 12);
i.setDate(currentiDate.getDate());
Logger.log(currentiDate);
}
RESULTS:
Mon Dec 20 00:00:00 GMT-06:00 2021
Wed Jan 20 00:00:00 GMT-06:00 2021
Sat Feb 20 00:00:00 GMT-06:00 2021
Sat Mar 20 00:00:00 GMT-05:00 2021
Tue Apr 20 00:00:00 GMT-05:00 2021
Thu May 20 00:00:00 GMT-05:00 2021
Sun Jun 20 00:00:00 GMT-05:00 2021
Tue Jul 20 00:00:00 GMT-05:00 2021
Fri Aug 20 00:00:00 GMT-05:00 2021
Mon Sep 20 00:00:00 GMT-05:00 2021
Wed Oct 20 00:00:00 GMT-05:00 2021
Sat Nov 20 00:00:00 GMT-06:00 2021
Mon Dec 20 00:00:00 GMT-06:00 2021
Wed Jan 20 00:00:00 GMT-06:00 2021
Sat Feb 20 00:00:00 GMT-06:00 2021
Sat Mar 20 00:00:00 GMT-05:00 2021
Tue Apr 20 00:00:00 GMT-05:00 2021
As I understand it, you want to print each month from the given date to the last month of the next year of the given date in the log.
You can do this in the following code:
let start = new Date("Mon Dec 20 00:00:00 GMT-06:00 2021");
let currentYear = new Date().getFullYear();
let nextYear = currentYear + 1;
let end = new Date(nextYear, 11, 31);
while (start <= end) {
// You can use Logger.log() here if you want. I use console.log() for demo purpose
console.log(new Date(start).toDateString());
start.setMonth(start.getMonth() + 1);
}
If I got any part wrong, feel free to point it out to me in the comments.
There is a lot to say about your code:
var thisDate = "Mon Dec 20 00:00:00 GMT-06:00 2021";
That timestamp format is not supported by ECMA-262, so don't use the built–in parser to parse it, see Why does Date.parse give incorrect results?
var nextYear = Number(currentYear)+1;
Where does currentYear come from?
var lastDateofYear = new Date("12-31-"+nextYear);
Parsing of an unsupported format, see above. In Safari it returns an invalid date.
for(var i=thisDate; i <= lastDateofYear; ){
Sets i to the string value assigned to thisDate. Since lastDateOfYear is an invalid date in Safari and Firefox, so the test i <= NaN is never true and the loop is never entered.
var currentiDate = new Date(i);
Parses i, see above.
var month = currentiDate.getMonth()+1;
i.setMonth((month) % 12);
i is a string, which doesn't have a setMonth method so I'd expect a Type error like "i.setMonth is not a function" if the loop actually runs.
i.setDate(currentiDate.getDate());
Another Type error as above (but it won't get this far).
Logger.log(currentiDate);
}
It seems you want to sequentially add 1 month to a date until it reaches the same date in the following year. Trivially, you can just add 1 month until you get to the same date next year, something like:
let today = new Date();
let nextYear = new Date(today.getFullYear() + 1, today.getMonth(), today.getDate());
let result = [];
do {
result.push(today.toString());
today.setMonth(today.getMonth() + 1);
} while (today <= nextYear)
However, adding months is not that simple. If you add 1 month to 1 Jan, you'll get 2 or 3 Mar depending on whether it's a leap year or not. And adding 1 month to 31 Aug will return 1 Oct.
Many "add month" functions check to see if the date rolls over an extra month and if it does, set the date back to the end of the previous month by setting the date to 0, so 31 Jan + 1 month gives 28 or 29 Feb.
But if you cycle over a year using that algorithm, you'll get say 31 Jan, 28 Feb, 28 Mar, 28 Apr etc. rather than 31 Jan, 28 Feb, 31 Mar, 30 Apr, etc.
See JavaScript function to add X months to a date and How to add months to a date in JavaScript?
A more robust way is to have a function that adds n months to a date and increment the months to add rather than the date itself so the month–end problem can be dealt with separately for each addition, e.g.
/* Add n months to a date. If date rolls over an extra month,
* set to last day of previous month, e.g.
* 31 Jan + 1 month => 2 Mar, roll back => 28 Feb
*
* #param {number} n - months to add
* #param {Date} date - date to add months to, default today
* #returns {Date} new Date object, doesn't modify passed Date
*/
function addMonths(n, date = new Date()) {
let d = new Date(+date);
let day = d.getDate();
d.setMonth(d.getMonth() + n);
if (d.getDate() != day) d.setDate(0);
return d;
}
/* return array of n dates at 1 month intervals. List is
* inclusive so n + 1 Dates returned.
*
* #param {Date} start - start date
* #param {number} n - number of months to return
* #returns {Array} array of Dates
*/
function getMonthArray(n, start = new Date()) {
let result = [];
for (let i=0; i<n; i++) {
result.push(addMonths(i, start));
}
return result;
}
// Examples
// Start on 1 Dec
getMonthArray(12, new Date(2021,11,1)).forEach(
d => console.log(d.toDateString())
);
// Start on 31 Dec
getMonthArray(12, new Date(2021,11,31)).forEach(
d => console.log(d.toDateString())
);
The functions don't attempt to parse timestamps to Dates, that responsibility is left to the caller.

Why is getDate() a month off?

I'm trying to iterate over objects that have a date within a specific time frame. These time frames are days in the past week bounded by startDate and endDate.
I have a for loop that sets the startDate to the beginning of the day, and endDate will be the end of the day.
let startDate = new Date(); // startDate: Start bound of average execution time calculation
let endDate = new Date(); // endDate: End bound of average execution time calculation
for (let i = 0; i < 7; i++) {
// i is used to decrement the startDate to i days from today
// set startDate to beginning of the day
startDate = new Date();
startDate.setDate(startDate.getDate() - i);
startDate.setHours(0, 0, 0, 0);
console.log(i + ": " + startDate);
// set endDate to end of the day
endDate.setDate(startDate.getDate());
endDate.setHours(23, 59, 59, 999);
console.log(i + ": " + endDate);
However, even though I'm setting the endDate to the startDate, the console tells me that the endDate is one month off. Why is this happening?
The console shows this:
0: Sat Aug 01 2020 00:00:00 GMT-0700 (Mountain Standard Time)
0: Sat Aug 01 2020 23:59:59 GMT-0700 (Mountain Standard Time)
1: Fri Jul 31 2020 00:00:00 GMT-0700 (Mountain Standard Time)
1: Mon Aug 31 2020 23:59:59 GMT-0700 (Mountain Standard Time)
2: Thu Jul 30 2020 00:00:00 GMT-0700 (Mountain Standard Time)
2: Sun Aug 30 2020 23:59:59 GMT-0700 (Mountain Standard Time)
3: Wed Jul 29 2020 00:00:00 GMT-0700 (Mountain Standard Time)
3: Sat Aug 29 2020 23:59:59 GMT-0700 (Mountain Standard Time)
4: Tue Jul 28 2020 00:00:00 GMT-0700 (Mountain Standard Time)
4: Fri Aug 28 2020 23:59:59 GMT-0700 (Mountain Standard Time)
5: Mon Jul 27 2020 00:00:00 GMT-0700 (Mountain Standard Time)
5: Thu Aug 27 2020 23:59:59 GMT-0700 (Mountain Standard Time)
Think like arrays, where the first element is 0. The same is true here. The months of the year will be 0 - 11, rather than 1 - 12. The getMonth() method returns the month in the specified date according to local time, as a zero-based value (where zero indicates the first month of the year).
Also, keep this in mind: With setDate() the expected values are 1-31, but other values are allowed: 0 will result in the last day of the previous month. -1 will result in the day before the last day of the previous month.
So, I ended up just fixing it by not referring to startDate at all. I'm not sure why I can't call getDate() without getting the wrong date, but for now, I'll just set endDate by repeating whatever I did to startDate.
// set startDate to beginning of the day
startDate = new Date();
startDate.setDate(startDate.getDate() - i);
startDate.setHours(0, 0, 0, 0);
console.log(i + ": " + startDate);
// set endDate to end of the day
endDate = new Date();
endDate.setDate(endDate.getDate() - i);
endDate.setHours(23, 59, 59, 59);
console.log(i + ": " + endDate);
The reason it happens is because you are setting the date but not the month, so when the loop crosses a month boundary, the start goes to the previous month but end stays in the current month.
When run on 1 Aug, in the first iteration both start and end are set to 1 Aug.
In the next iteration, 1 is subtracted from the start so it's 31 July, but then just the date is set for end, so it goes to 31 Aug, and so on…
A reworking of the code:
// Start at random time on 1 Aug
let d = new Date(2020,7,1,15,23,51,3);
for (let start, end, i=0; i<7; i++) {
start = new Date(d.setHours(0,0,0,0));
console.log(i + ' : ' + start.toString());
end = new Date(d.setHours(23,59,59,999));
console.log(i + ' : ' + end.toString());
d.setDate(d.getDate() - 1);
}

Does Javascript recognise leap years

I have the following snippet of code (actually I am using new Date() to get today (4th March 2016), but it won't be March for ever, so to be a sensible test I had made the date explicitly.
var n = new Date(2016,2,4);
var d = new Date (
n.getFullYear(),
n.getMonth(),
-1,
6,0,0);
console.log(d.toString());
when n is now (except it isn't) and d is a new date which I want to be the last day of the preceding month. I am NOT getting 29th February 2016 6:00am UTC, which is what I would have expected, instead I am getting 28th February.
This gives the same result in both Chrome and Iceweasel (Firefox). How should I find the last day of the previous month (especially, like this year when it is a leap year)
If it matters, I am in the GMT timezone.
That's because days are 1 based, not 0 based.
var march4 = new Date(2016, 2, 4);
var feb29 = new Date(
march4.getFullYear(),
march4.getMonth(),
0); // <-- go to the day before the first of the given month
console.log(feb29); // Mon Feb 29 2016 00:00:00 GMT-0700 (Mountain Standard Time)
For reference, if you pull the same trick for April to March, you'll get March 31st.
var april = new Date(2016, 3, 4);
var march = new Date(
april.getFullYear(),
april.getMonth(),
0);
console.log(march); // Thu Mar 31 2016 06:00:00 GMT-0600 (Mountain Daylight Time)
In fact, it recognizes
If you try this, it works:
Date (2016, 2, 0);
It brings to me Mon Feb 29 2016 00:00:00 GMT-0300
Instead of -1, try 0:
var n = new Date(2016,2,1);
var d = new Date (
n.getFullYear(),
n.getMonth(),
0,
6,0,0);
console.log(d.toString());

javascript sometimes CET sometimes CEST

I've one script where I create two Date instance, the first return the date in CET offset timestamp and the second in CEST. I can't understand why.
var start_date = new Date(2014, 1, 26, 12, 0 , 0, 0);
var first_start_date = new Date(2014, 3, 1, 12, 0 , 0, 0);
return: Wed Feb 26 2014 12:00:00 GMT+0100 (CET) Tue Apr 01 2014 12:00:00 GMT+0200 (CEST)
I've also create a jsfiddle example
This is due to DST.
Also, see that CEST is Central European Summer Time.
It's just because April 1 is in Daylight Savings time (starts March 9th in the US this year), and February 26th is not in Daylight Savings time.

31 days in February in Date object

This code should log all days for given month:
var date = new Date(2012,2,1);
var thisMonth = date.getMonth();
while(date.getMonth()==thisMonth) { // 31 steps ???
console.log(date.getMonth(),date.getDate());
date.setDate(date.getDate()+1);
}
It works well for every month but February. Any ideas where is the catch?
Note the month parameter is 0-indexed, so your code is about March not February.
The doc:
month
Integer value representing the month, beginning with 0 for January to
11 for December.
Use new Date(2012,1,1); month is zero-based ;-)
This is pretty interesting:
new Date('2014-02-28'); // Fri Feb 28 2014 01:00:00 GMT+0100
new Date('2014-02-29'); // Sat Mar 01 2014 01:00:00 GMT+0100
new Date('2014-02-30'); // Sun Mar 02 2014 01:00:00 GMT+0100
new Date('2014-02-31'); // Mon Mar 03 2014 01:00:00 GMT+0100
new Date('2014-02-32'); // Invalid Date

Categories

Resources