Why is getDate() a month off? - javascript

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

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.

How to increase the date when moving to the other month

I have a date set which I am filling it with the number of current week and year:
dateSets(week, year) {
let fistDayOfTheWeek = '';
if(this.currentWeekNumber === this.getWeekNumber(new Date())) {
fistDayOfTheWeek = new Date();
} else {
fistDayOfTheWeek = this.getDateOfWeek(week, year);
}
let sunday = new Date(fistDayOfTheWeek);
sunday.setDate(sunday.getDate() - sunday.getDay() + 7);
const dates = [];
const diff = sunday.getDate() - fistDayOfTheWeek.getDate();
for (let i = 0; i <= diff; i++) {
const upDate = new Date();
upDate.setDate(fistDayOfTheWeek.getDate() + i);
dates.push(upDate);
}
console.log(dates)
return dates;
},
So apperantly my dateSet function works like if it is not monday then show the dates from today to sunday and from next week from monday to sunday. But what is wrong in this function is it doesnt push when the month is changed. So for 4 weeks console.log(dates) displays:
[Tue Aug 10 2021 16:22:43 GMT+0200 (Central European Summer Time),
Wed Aug 11 2021 16:22:43 GMT+0200 (Central European Summer Time), Thu
Aug 12 2021 16:22:43 GMT+0200 (Central European Summer Time), Fri Aug
13 2021 16:22:43 GMT+0200 (Central European Summer Time), Sat Aug 14
2021 16:22:43 GMT+0200 (Central European Summer Time), Sun Aug 15
2021 16:22:43 GMT+0200 (Central European Summer Time)]
[Mon Aug 16 2021 16:22:46 GMT+0200 (Central European Summer Time),
Tue Aug 17 2021 16:22:46 GMT+0200 (Central European Summer Time), Wed
Aug 18 2021 16:22:46 GMT+0200 (Central European Summer Time), Thu Aug
19 2021 16:22:46 GMT+0200 (Central European Summer Time), Fri Aug 20
2021 16:22:46 GMT+0200 (Central European Summer Time), Sat Aug 21
2021 16:22:46 GMT+0200 (Central European Summer Time), Sun Aug 22
2021 16:22:46 GMT+0200 (Central European Summer Time)]
[Mon Aug 23 2021 16:22:47 GMT+0200 (Central European Summer Time),
Tue Aug 24 2021 16:22:47 GMT+0200 (Central European Summer Time), Wed
Aug 25 2021 16:22:47 GMT+0200 (Central European Summer Time), Thu Aug
26 2021 16:22:47 GMT+0200 (Central European Summer Time), Fri Aug 27
2021 16:22:47 GMT+0200 (Central European Summer Time), Sat Aug 28
2021 16:22:47 GMT+0200 (Central European Summer Time), Sun Aug 29
2021 16:22:47 GMT+0200 (Central European Summer Time)]
[]
As you see since after 3 weeks, the month will be changed to september and I think that's why it comes to an empty array.
I dont know if it is necessary but in any case here are the other functions that I used:
getDateOfWeek(w, y) {
var simple = new Date(y, 0, 1 + (w - 1) * 7);
var dow = simple.getDay();
var ISOweekStart = simple;
if (dow <= 4)
ISOweekStart.setDate(simple.getDate() - simple.getDay() + 1);
else
ISOweekStart.setDate(simple.getDate() + 8 - simple.getDay());
return ISOweekStart;
}
getWeekNumber(date) {
const temp_date = new Date(date.valueOf());
const dayn = (date.getDay() + 6) % 7;
temp_date.setDate(temp_date.getDate() - dayn + 3);
const firstThursday = temp_date.valueOf();
temp_date.setMonth(0, 1);
if (temp_date.getDay() !== 4)
{
temp_date.setMonth(0, 1 + ((4 - temp_date.getDay()) + 7) % 7);
}
return 1 + Math.ceil((firstThursday - temp_date) / 604800000);
},
PS: currentWeekNumber is increasing everytime when the button is clicked.
Your issue is here:
const diff = sunday.getDate() - fistDayOfTheWeek.getDate();
when you get to the end of the month of say August, the next Sunday is 5 Sep and the first day of the week is 30 August, so diff is -25 and in the test:
for (let i = 0; i <= diff; i++) {
i is less than diff from the start so nothing is added to the array.
One fix is to get the number of days until the next Sunday and iterate for that many days, e.g.
// Return an array of dates from tomorrow until the
// following Sunday.
function getDatesToSunday(date = new Date()) {
// Copy date so don't affect original
let d = new Date(+date);
// Get the number of days until the next Sunday
let count = 7 - d.getDay();
// Create array of Dates
let dates = [];
while (count--) { 
dates.push (new Date(d.setDate(d.getDate() + 1)));
}
return dates;
}
console.log('Given Sun 29 Aug 2021:');
getDatesToSunday(new Date(2021, 7, 29))
.forEach(d => console.log(d.toDateString()));
console.log('Rest of this week, or next if today is Sunday:');
getDatesToSunday()
.forEach(d => console.log(d.toDateString()));
If the supplied date is Saturday, the above returns an array of just Sunday. If the supplied date is Sunday, it returns an array of the following Monday to Sunday, etc.
If you want to get multiple weeks of dates, add a second parameter, say weeks that defaults to 1, then add (weeks - 1) * 7 to count before the while loop. Test weeks first to ensure it's 1 or greater (starting a decrementing while loop with a negative number is not a good idea).
Or you can just keep adding days until Sunday:
const getDatesToSunday = (date = new Date()) => {
// Setup
let year = date.getFullYear(),
month = date.getMonth(),
day = date.getDate(),
dates = [];
// Add dates from tomorrow until Sunday
do {
dates.push(new Date(year, month, ++day));
} while (dates[dates.length - 1].getDay());
return dates;
};
getDatesToSunday().forEach(d=>console.log(d.toDateString()));

creating a date range from 2 dates with linq.js and momentjs

I want to get all dates between a startDate and an endDate.
I wrap the startDate/endDate with moment() again to clone the start/endDate because they must not be changed.
But still the getDateRange gives me odd results about dates:
testCase.startDate = moment(new Date(2014, 0, 1));
testCase.endDate = moment(new Date(2014, 0, 27));
Although both dates are in 2014 I get a dateRange from december 2013 days?
Why is that?
function getDateRange(startDate, endDate) {
return Enumerable.range(0, moment(endDate).diff(moment(startDate), 'days') + 1)
.select(function (offset) {
return moment(startDate).add(offset, 'days')
})
.toArray();
}
UPDATE
Your query looks like it should work. Maybe you're interpreting the dates incorrectly. Remember, only the month starts at 0. Maybe you offset the year too when you looked at the values.
Here's an alternate way you can write the query:
function getDateRange(startDate, endDate) {
return Enumerable.Unfold(startDate, "moment($).add(1, 'd')")
.TakeWhile(function (d) { return d <= endDate; })
.ToArray();
}
Based on what I'm seeing in the comments, it appears you're using methods which mutates the dates. You'll either want to avoid using these methods or clone the date first and manipulate the clones.
// without cloning
var date1 = moment.utc([2014, 0, 1]);
console.log(String(date1)); // Wed Jan 01 2014 00:00:00 GMT+0000
var startOfDate1 = date1.startOf('week'); // mutated
console.log(String(date1)); // Sun Dec 29 2013 00:00:00 GMT+0000
// using moment()
var date2 = moment.utc([2014, 0, 1]);
console.log(String(date2)); // Wed Jan 01 2014 00:00:00 GMT+0000
var startOfDate2 = moment(date2).startOf('week'); // not mutated
console.log(String(date2)); // Wed Jan 01 2014 00:00:00 GMT+0000
// using clone()
var date3 = moment.utc([2014, 0, 1]);
console.log(String(date3)); // Wed Jan 01 2014 00:00:00 GMT+0000
var startOfDate3 = date3.clone().startOf('week'); // not mutated
console.log(String(date3)); // Wed Jan 01 2014 00:00:00 GMT+0000

Getting first and last day of three consecutive month in javascript

I want to get the first date and last date of three consecutive month starting from current moth and moving towards past,i.e. if current month is November,my output will be first and last of Nov,followed by first and last date of October,followed by first and last date of September. I have written the code as follows:
<script type="text/javascript">
function calculatingMonthRange(){
console.log('calculatingMonthRange() got called');
var date = new Date();
var currdate=date;
for(i=1;i<=3;i++){
var firstDay = new Date(date.getFullYear(), date.getMonth(), 1);
var lastDay = new Date(date.getFullYear(), date.getMonth() + 1, 0);
console.log('FirstDay='+firstDay+' LastDay='+lastDay+"\n");
date.setDate(currdate.getDate()-(30*i));
}
}
</script>
this is the output what I'm getting:::
FirstDay=Fri Nov 01 2013 00:00:00 GMT+0530 (India Standard Time) LastDay=Sat Nov 30 2013 00:00:00 GMT+0530 (India Standard Time)
FirstDay=Tue Oct 01 2013 00:00:00 GMT+0530 (India Standard Time) LastDay=Thu Oct 31 2013 00:00:00 GMT+0530 (India Standard Time)
FirstDay=Thu Aug 01 2013 00:00:00 GMT+0530 (India Standard Time) LastDay=Sat Aug 31 2013 00:00:00 GMT+0530 (India Standard Time)
where is the month September is going????why is it printing August instead of September?????
This works:
function calculatingMonthRange(){
console.log('calculatingMonthRange() got called');
var date = new Date();
var currdate=date;
for(i=1;i<=3;i++){
var firstDay = new Date(date.getFullYear(), date.getMonth(), 1);
var lastDay = new Date(date.getFullYear(), date.getMonth() + 1, 0);
console.log('FirstDay='+firstDay+' LastDay='+lastDay+"\n");
date = new Date(date.getFullYear(), date.getMonth() - 1, 1);
}
}
You can play with the code here: http://jsbin.com/uPaVOXI/1/edit?js,console

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