Dates not incrementing correctly - javascript

I have a function that when called, it will add 7 days to the inputted date. The format for the date is YYYY-MM-DD (i.e. 2022-03-02)
for(let i = 0; i < repeatCount; i++)
{
date = addWeek(date);
}
function addWeek(date)
{
let temp = new Date(date);
//console.log("Old Date: ");
//console.log(temp.toISOString().split('T')[0])
//console.log(temp.getDate());
temp.setDate(temp.getDate() + 7);
console.log("New Date: ");
console.log(temp.toISOString().split('T')[0])
//console.log("returning date");
return temp.toISOString().split('T')[0];
}
For some reason, when the function is called as part of a repeat (React Web Application that involves recurring events), the addWeek function will not increment correctly a single time but then increment correctly the rest of the time.
Here's the input from my most recent log when I set repeatCount to 5:
Old Date:
2022-03-04
New Date:
2022-03-11
Old Date:
2022-03-11
New Date:
2022-03-17
Old Date:
2022-03-17
New Date:
2022-03-24
Old Date:
2022-03-24
New Date:
2022-03-31
Old Date:
2022-03-31
New Date:
2022-04-07
As you've probably noticed, it increments the week correctly with the exception of the second repeat. I've tested this multiple times with different dates, and each time, it is only the second iteration that is incremented incorrectly. Everything else works fine.
Please help. I'm losing my mind over this.
I forgot to add earlier: addWeek takes the date as a string input.

This is a Daylight Savings Time problem. Dates in JavaScript are inherently local, so when you use setDate() it tries to keep the same time of day on the new date, accounting for shifts in Daylight Savings Time. But that means the time of day will be different when compared to UTC time (which toISOString() converts to). The actual value of temp on the second output in your example is 2022-03-17T23:00Z, one hour before the date you were looking for. But your code strips off the time element so you end up one day off instead.
Instead of using setDate(), use the Date constructor:
temp = new Date(temp.getFullYear(), temp.getMonth(), temp.getDate() + 7);
var date = new Date('2022-03-02');
const repeatCount = 5;
for(let i = 0; i < repeatCount; i++)
{
date = addWeek(date);
}
function addWeek(date)
{
let temp = new Date(date);
temp = new Date(temp.getFullYear(), temp.getMonth(), temp.getDate() + 7);
console.log("New Date: ", temp);
console.log(temp.toISOString().split('T')[0])
//console.log("returning date");
return temp.toISOString().split('T')[0];
}

https://jsfiddle.net/4wm1vz9d/1/
function addWeek(date)
{
date.setDate(date.getDate()+7)
}
let date = new Date();
console.log(date)
for(let i = 0; i < 5; i++)
{
addWeek(date)
console.log(date)
}

Phew. Javascript is sometimes weird. Seems like the date get's inaccurate because of the conversion to a ISO String. Try returning the temp Date object instead of the string. Then convert it after adding the weeks. It may have something to do with the other values which the Object provides...

Related

MomentJS and JS Date objects not referring to the same hour

I've got a server instance (NodeJS) that receives a set of objects, and schedules them for sending push notifications to users.
Some of these objects, are periodic, and this periodicity is handled by a string like this:
90=>Mon&Tue&Thu=>16:00
Which is read as:
offset_minutes=>days_of_the_week=>initial_hour
Then, what I do is to check whether the current day matches one of the given days in the string, and then, modify the date to the given hour in the "initial_hour", and finally, substract the "offset_minutes" amount of minutes from the Date object.
Seems straightforward until now, right? Well, not that much. Let's first see the code:
const isToday = weekDays.split("&")
.map(a => {
switch (a) {
case 'Mon': return 1;
case 'Tue': return 2;
case 'Wed': return 3;
case 'Thu': return 4;
case 'Fri': return 5;
case 'Sat': return 6;
case 'Sun': return 7;
}
})
.some(v => v == currentDay);
if (isToday) {
let finalDate = moment(today)
.set("hour", Number(hour))
.set("minute", Number(mins));
if (offset) {
finalDate.subtract('minutes', Number(offset));
}
return finalDate.toDate();
Everything works well, until I do the MomentJS transformations. When I output a Date object with the ".toDate()" method, this object is always set to 2 hours before the expected time. But if I use the .toISOString() method, I get the proper time for all the occurrencies.
I guess that something is wrong with my Date objects, setting them up at a different timezone than the one I have. A couple of examples:
For the string 90=>Mon&Tue&Thu=>16:00 I get the Date object: 2019-10-14T14:00:11.852Z
For the string 30=>Mon&Tue&Wed&Thu&Fri&Sat&Sun=>18:30 I get the Date object: 2019-10-14T16:30:11.866Z
I would like to know what's the explanation for such a behavior, and if I can do something to change it so the normal Javascript Date object points to the same hour than my momentjs object, or the .toISOString() output.
Thank you!
The posted code is incomplete and doesn't demonstrate the issue described.
I've reimplemented the code without moment.js as best I can and simplified it. It seems to work fine:
function parseThing(s) {
// Parse input string
let b = s.split('=>');
let offset = +b[0];
let days = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'];
let weekDays = b[1].split('&').map(day => days.indexOf(day));
let [hr, min] = b[2].split(':');
// Get a date for today
let date = new Date();
// If today included, return an adjusted date
if (weekDays.includes(date.getDay())) {
date.setHours(hr, min, 0, 0);
if (offset) {
date.setMinutes(date.getMinutes()+ Number(offset));
}
return date;
}
// If today isn't included, return null
return null;
}
let s0 = '90=>Mon&Tue&Thu=>16:00';
let s1 = '0=>Mon&Tue&Wed&Thu&Fri&Sat&Sun=>18:30';
console.log(parseThing(s0).toString());
console.log(parseThing(s1).toString());
Where the local day is one of those in the string (Mon, Tue, Thu) it returns a Date equivalent to a local time of 17:30, which is 90 minutes offset from 16:00, which seems to be correct.
PS I've changed Sunday to 0 as I can't see any rationale for it to be 7. Also seconds and milliseconds are zeroed too.

Trying to remove all the passed dates

I have an array with many dates, they are not in the date type but string like: "2016-08-12" for example. Then what I would like to do is to remove all dates that we already have passed. So therefor im trying to compare them to todays date and then remove it if its passed. Using typescript by the way.
my array, named datoArray, looks like this:
["2016-08-02", "2016-08-11", "2016-08-22", "2016-09-10"]
just with a lot more of the same...
then here's what I try to do:
for(var i = 0; i < this.datoArray.length; i++){
this.skoleAar = parseInt(this.datoArray[i].slice(0,4))
this.skoleMaaned = parseInt(this.datoArray[i].slice(5,8))
this.skoleDag = parseInt(this.datoArray[i].slice(8,10))
if(this.skoleAar < dagensAar){
this.datoArray.splice(i, 1);
}
if(this.skoleAar == dagensAar && this.skoleMaaned < dagensMaaned){
this.datoArray.splice(i, 1);
}
if(this.skoleAar == dagensAar && this.skoleMaaned == dagensMaaned && this.skoleDag < dagensDag){
this.datoArray.splice(i, 1);
}
}
the "dagensAar", "dagensMaaned" and "dagensDag" variables im getting from another function that works. If i "console.log" the variables it prints out int values like 2016 for the year and 8 for the month if i take from the start of the array, and for the "dagensAar", "dagensMaaned" and "dagensDag" it prints 2016 11 20, which is todays year, month and day. all is in Int type, so what im not getting here is why my "if" doesnt work? It seems like there is something wrong with the way i compare the, but i thought this was the way to compare int values?
If the dates are in ISO-8601 format then you can simply filter using Date.parse().
var dates = ["2016-08-02", "2016-08-11", "2016-08-22", "2016-09-10", "2016-12-15"];
function removePastDates(data) {
var today = new Date();
console.log('Initial state: ' + data);
var modified = dates.filter(function(dateString) {
return Date.parse(dateString) >= today;
});
console.log('Final state: ' + modified);
return modified;
}
var newDates = removePastDates(dates);
Your dates seem to be RFC compliant, meaning they can be directly fed into a new Date object. Simply compare to today and filter by that:
var today = new Date()
var futureDates = this.datoArray.filter(d => new Date(d) >= today)
(pre-ECMA6:)
var today = new Date()
var futureDates = this.datoArray.filter(function (d) {
return new Date(d) >= today;
})
I think the problem is not related to the dates.
I think the problem is that you are removing items from the array while looping the same exact array.
You should maybe try looping from the end of the array to the beginning or just save the indexes that you need to remove and later do the actual removing.
Keep in mind that when you remove an item you change the index of every item in the remaining of the array - maybe you should start removing from the greatest index so it will not confuse you.

Javascript Date Comparison not behaving as expected

I am getting a SQL date - NOT datetime - object pushed into my Javascript code, and I need to see whether it's before today or not. Here is the code I have (the relevant part):
todaysDate = new Date();
todaysDate.setHours(0,0,0,0);
var date = Date.parse(row[3]);
// date.setHours(0,0,0,0);
if (date < todaysDate) {
alert("date is before today");
dueDate = '<small class="text-danger">';
} else {
alert("date is after today");
dueDate = '<small class="text-muted">';
}
row[3] is the source of the SQL date. So, this works fine for everything except dates that are today. Without the commented line, it thinks that anything with today's date is in the past. With the commented line, my code breaks. Any thoughts as to how to fix this? Not sure what I'm doing wrong.
Thanks!
If your date string is like "2016-04-10" and your time zone is west of GMT, say -04:00, then in browsers compliant with ECMAScript 2016 you will get a Date for "2016-04-09T19:00:00-0400".
When you create a Date using new Date() and set the hours to zero (assuming it's 10 April where you are), you'll get a Date for "2016-04-10T00:00:00-0400".
So when compared they have different time values.
What you need is to either treat the string you get from the database as local, or get the UCT date where you are, so:
var dateString = '2016-04-10';
var parsedDate = new Date(dateString);
var todayUTCDate = new Date();
todayUTCDate.setUTCHours(0,0,0,0);
document.write(parsedDate + '<br>' + todayUTCDate);
But not all browsers parse strings according to ECMAScript 2015 so they should always be manually parsed. Use a library, or write a small function, e.g.
// Parse date string in format 'yyyy-mm-dd' as local date
function parseISOLocal(s) {
var b = s.split(/\D/);
return new Date(b[0], b[1]-1, b[2]);
}
and replace:
var date = Date.parse(row[3]);
with:
var date = parseISOLocal(row[3]);
and then in the comparison, compare the time values:
if (+date < +todaysDate) {
or
if (date.getTime() < todaysDate.getTime()) {
Use getTime() of date object.
The getTime() method returns the number of milliseconds between midnight of January 1, 1970 and the specified date.
You can compare miliseconds and do your operations
date.getTime() > todaysDate.getTime()
Also be sure that Date.parse is returning a valid date.

javascript - compare dates in different formats

I have 2 dates which I need to compare to see if one is greater than the other but they are in different formats and I'm not sure of the best way to compare the 2.
The formats are:
1381308375118 (this is var futureDate)
which is created by
var today = new Date(); today.setHours(0, 0, 0, 0); var futureDate = new Date().setDate(today.getDate() + 56); //56 days in the future...
And the other format is
2013/08/26
Any ideas how I can compare the 2?
Without using a 3rd party library, you can create new Date objects using both those formats, retrieve the number of milliseconds (since midnight Jan 1, 1970) using getTime() and then simply use >:
new Date("2013/08/26").getTime() > new Date(1381308375118).getTime()
I strongly recommend using datejs library.
Thus this can be written in one single line:
Date.today().isAfter(Date.parse('2013/08/26'))
I would make sure that I am comparing the "date" element of each format and exclude any "time" element. Then with both dates converted to milliseconds, simply compare the values. You could do something like this. If dates are equal it returns 0, if the first date is less that the second then return -1, otherwise return 1.
Javascript
function compareDates(milliSeconds, dateString) {
var year,
month,
day,
tempDate1,
tempDate2,
parts;
tempDate1 = new Date(milliSeconds);
year = tempDate1.getFullYear();
month = tempDate1.getDate();
day = tempDate1.getDay();
tempDate1 = new Date(year, month, day).getTime();
parts = dateString.split("/");
tempDate2 = new Date(parts[0], parts[1] - 1, parts[2]).getTime();
if (tempDate1 === tempDate2) {
return 0;
}
if (tempDate1 < tempDate2) {
return -1;
}
return 1;
}
var format1 = 1381308375118,
format2 = "2013/08/26";
console.log(compareDates(format1, format2));
On jsfiddle
Maybe you can use Date.parse("2013/08/26") and compare with former one
Follow these steps to compare dates
Each of your date must to passed through Date object i.e. new Date(yourDate).
Now dates will have same format and these will be comparable
let date1 = new Date()
let date2 = "Jan 1, 2019"
console.log(`Date 1: ${date1}`)
console.log(`Date 2: ${date2}`)
let first_date = new Date(date1)
let second_date = new Date(date2)
// pass each of the date to 'new Date(yourDate)'
// and get the similar format dates
console.log(`first Date: ${first_date}`)
console.log(`second Date: ${second_date}`)
// now these dates are comparable
if(first_date > second_date) {
console.log(`${date2} has been passed`)
}

Need explanation of this Date Processing function

Could anyone please explain the below code to me?
For example, i would like to set Today's date to today (21st of November, 2012) and the end date to the 3rd of December.
The reason for this is because i want to loop through a list of items, determine whether they are in the "past", "present" or "future" and assign a class to them accordingly.
I hope this makes sense! Any help is greatly appreciated and much welcomed!
function daysTilDate(expiredate){
expiredate ="12/"+expiredate+"/2012";
var thisDay=new Date(expiredate);
var CurrentDate = new Date();
var thisYear=CurrentDate.getFullYear();
thisDay.getFullYear(thisYear);
var DayCount=(thisDay-CurrentDate)/(1000*60*60*24);
DayCount=Math.round(DayCount);
return DayCount;
}
You can simplify the method like below if you want to calculate the days to an expire date. Please note that if you don't specify a test date, it'll take the current date as the test date.
​function ​daysTilData(expireDate, testDate) {
if(typeof testDate === "undefined"){
testDate = new Date(); // now
}
var diff = expireDate - testDate;
// minus value meaning expired days
return Math.round(diff/(1000*60*60*24));
}
alert(daysTilData(new Date("12/31/2012")));
// result 40
alert(daysTilData(new Date("12/31/2012"), new Date("1/12/2013")));
// result -12
Here's a line by line explanation.
The function declaration...
function daysTilDate(expiredate){
Takes the parameter expiredate sets it equal to the same value with "12/" prepended and "/2012" appended. so if the value of expiredate was "10", the new value is now "12/10/2012"...
expiredate ="12/"+expiredate+"/2012";
Instantiates a new Date object named thisDay using the expiredate string...
var thisDay=new Date(expiredate);
Instantiates a new Date object named CurrentDate, using the default constructor which will set the value equal to today's date...
var CurrentDate = new Date();
Gets just the Year segment from CurrentDate (which was earlier set to today's date)...
var thisYear=CurrentDate.getFullYear();
Gets the Year segment from thisDay (which was earlier set to "2012")...
thisDay.getFullYear(thisYear);
Gets the difference between thisDay and CurrentDate, which is in milliseconds, and multiplies that by 1000*60*60*24 to get the difference in days...
var DayCount=(thisDay-CurrentDate)/(1000*60*60*24);
Rounds the previously calculated difference...
DayCount=Math.round(DayCount);
Returns the difference between today and the passed-in day in December 2012...
return DayCount;
}
Note that the 2 lines that get the year segments are extraneous, because those values are never used...
I am not going to review the code, but I can answer your question of "I want to loop through a list of items, determine whether they are in the past, present, or future".
First, you want to construct your target date. If it's "now", just use new Date(). If it's a specific date, use new Date(dateString).
Second, Date objects in JavaScript have various members that return the date's characteristics. You can use this to compare dates. So, let's say you have your date strings in an array:
function loopDates(targetDateString, myDates) {
var targetDate, nextDate, status, ix;
targetDate = new Date(targetDateString);
for (ix = 0; ix < myDates.length; ++ix) {
nextDate = new Date(myDates[ix]);
if (nextDate.getFullYear() < targetDate.getFullYear()) {
status = "past";
} else if (nextDate.getFullYear() > targetDate.getFullYear()) {
status = "future";
} else {
// Year matches, compare month
if (nextDate.getMonth() < targetDate.getMonth()) {
status = "past";
} else if (nextDate.getMonth() > targetDate.getMonth()) {
status = "future";
} else {
// Month matches, compare day of month
if (nextDate.getDate() < targetDate.getDate()) {
status = "past";
} else if (nextDate.getDate() > targetDate.getDate()) {
status = "future";
} else {
// Day matches, present
status = "present";
}
}
}
console.log("Date " + myDates[ix] + " is " + status + " from " + targetDateString);
}
}
loopDates("11/17/2012", ["11/16/2012", "11/17/2012", "11/18/2012"]);
This will log:
Date 11/16/2012 is past from 11/17/2012
Date 11/17/2012 is present from 11/17/2012
Date 11/18/2012 is future from 11/17/2012
Working jsFiddle here.
If you want to work with a comprehensive Date class, use DateJS, an open source JavaScript date and time processing library with some impressive features.

Categories

Resources