Two identical JavaScript dates aren't equal - javascript

When I create two identical JavaScript Date objects and then compare them, it appears that they are not equal. How to I test if two JavaScript dates have the same value?
var date1 = new Date('Mon Mar 11 2013 00:00:00');
var date2 = new Date('Mon Mar 11 2013 00:00:00');
console.log(date1 == date2); //false?
JS Fiddle available here

It appears this has been addressed already.
To check whether dates are equal, they must be converted to their primitives:
date1.getTime()=== date2.getTime()
//true

First of all, you are making a sound mistake here in comparing the references. Have a look at this:
var x = {a:1};
var y = {a:1};
// Looks like the same example huh?
alert (x == y); // It says false
Here, although the objects look identical they hold different slots in memory. Reference stores only the address of the object. Hence both references (addresses) are different.
So now, we have to compare the values since you know reference comparison won't work here.
You can just do
if (date1 - date2 == 0) {
// Yep! Dates are equal
} else {
// Handle different dates
}

I compare many kinds of values in a for loop, so I wasn't able to evaluate them by substracting, instead I coverted values to string before comparing
var a = [string1, date1, number1]
var b = [string2, date2, number2]
for (var i in a){
if(a.toString() == b.toString()){
// some code here
}
}

Related

cannot compare dates for some reason [duplicate]

When comparing date objects in Javascript I found that even comparing the same date does not return true.
var startDate1 = new Date("02/10/2012");
var startDate2 = new Date("01/10/2012");
var startDate3 = new Date("01/10/2012");
alert(startDate1>startDate2); // true
alert(startDate2==startDate3); //false
How could I compare the equality of these dates? I am interested in utilizing the native Date object of JS and not any third party libraries since its not appropriate to use a third party JS just to compare the dates.
That is because in the second case, the actual date objects are compared, and two objects are never equal to each other. Coerce them to number:
alert( +startDate2 == +startDate3 ); // true
If you want a more explicity conversion to number, use either:
alert( startDate2.getTime() == startDate3.getTime() ); // true
or
alert( Number(startDate2) == Number(startDate3) ); // true
Oh, a reference to the spec: §11.9.3 The Abstract Equality Comparison Algorithm which basically says when comparing objects, obj1 == obj2 is true only if they refer to the same object, otherwise the result is false.
Compare dates using getTime() returning number of milliseconds from epoch (i.e. a number):
var startDate1 = new Date("02/10/2012");
var startDate2 = new Date("01/10/2012");
var startDate3 = new Date("01/10/2012");
alert(startDate1.getTime() > startDate2.getTime()); // true
alert(startDate2.getTime() == startDate3.getTime()); //true
Also consider using Date constructor taking explicit year/month/date number rather then relying on string representation (see: Date.parse()). And remember that dates in JavaScript are always represented using client (browser) timezone.
You do not need to use the getTime method- you can subtract a date object from another date object. It will return the milliseconds difference(negative, if the second is a later date)
var startDate1 = new Date("02/10/2012");
var startDate2 = new Date("01/10/2012");
var diff= (startDate1 -startDate2)
// evaluates to 0 if the dates have the same timestamp
you can compare the actual milliseconds :
alert(startDate2.getTime() === startDate3.getTime());
tl;dr
Use date.getTime() for comparisons.
Based on my testing, it was at least 25% than the next fastest alternative (date.valueOf()).
Details
Came across this in 2022. As others have already said, comparing like date1.getTime() === date2.getTime() is the way to go.
Someone else shared a jsperf link in an answer that seems broken for me right now, so decided to add some performance comparison of my own.
I created two arrays containing 1000 dates each. All dates will naturally be different instances (meaning direct === checks will fail), so what this benchmark does, is test what the fastest way is to convert a date to a primitive.
Here's the test data:
const data1 = Array.from({length: 1000}, () => new Date())
const data2 = Array.from({length: 1000}, () => new Date())
And here are the test cases (there's more in the link below):
// 1
data1.forEach((d1, i) => d1.getTime() === data2[i].getTime());
// 2
data1.forEach((d1, i) => d1.valueOf() === data2[i].valueOf());
// 3
data1.forEach((d1, i) => Number(d1) === Number(data2[i]));
// 4
data1.forEach((d1, i) => d1.toISOString() === data2[i].toISOString());
Result (use date.getTime())
Not a surprise that a date.getTime() conversion is much faster. It's around 25% faster than date.valueOf(), and between 10x and 100x faster than everything else (as far as I've checked).
Additionally, introducing optional chaining slowed the best case by almost 10% for me. Found that interesting. date.valueOf() also slowed down by 5% compared to its non optional chaining counterpart.
data1.forEach((d1, i) => d1?.getTime() === data2[i]?.getTime());
Benchmark link: here
Here's an image, in case the above link breaks at some point in the future.
You can also use the function valueOf()
var startDate1 = new Date("02/10/2012").valueOf();
var startDate2 = new Date("01/10/2012").valueOf();
var startDate3 = new Date("01/10/2012").valueOf();
alert(startDate1>startDate2); // 1326150000000 > 1328828400000 true
alert(startDate2==startDate3); // 1328828400000 > 1326150000000 false
One more way of comparing two dates would be converting dates to timestamps using "+" operator before the date.
So, let's say we have two dates:
const dateOne = new Date("10 January 1986")
const dateTwo = new Date("10 December 2020")
if(+dateOne == +dateTwo){
//do something
}
and so on.
This is really handy if you are sorting date objects too as you can use this in the sorting callback function.

Why does two JS date Objects instantianted differently?

I'd like to enable/disable a button based on a datepicker, and I have a setup for a check like this:
public dateChanged = false;
public availableFromDate: Date;
public availableToDate: Date;
initDatepickers() {
const currentDay = new Date();
this.availableFromDate = currentDay;
this.availableToDate = currentDay;
}
private dateCheck() {
if ((this.availableFromDate > this.availableToDate) || (this.availableFromDate === this.availableToDate)) {
this.dateChanged = false;
} else {
this.dateChanged = true;
}
console.log(this.dateChanged);
console.log(`Available from - ${this.availableFromDate}`);
console.log(`Available to - ${this.availableToDate}`);
}
The check works good upwards, and enables the button when from date is lower, however!
If you log the values to the console be button is disabled because the init value is false, not because the check works.
The two date objects are initialized differently (console.log dump):
true
clinics-upload-documents.component.ts:73 Available from - Fri Feb 22 2019 00:00:00 GMT+0100 (Central European Standard Time)
clinics-upload-documents.component.ts:74 Available to - Fri Feb 22 2019 10:52:31 GMT+0100 (Central European Standard Time)
It's never going to be false because the first date obj is # 0:00:00 however the 2nd is tied to current local time.
these are used to manipulate the dates:
onFromChange(fromDate) {
const dateType = 'from';
this.setDateValues(fromDate, dateType);
}
onToChange(toDate) {
const dateType = 'to';
this.setDateValues(toDate, dateType);
}
private setDateValues(date: Date, dateType: string) {
dateType === 'from' ? this.availableFromDate = new Date(date) : this.availableToDate = new Date(date);
this.dateCheck();
}
What am I missing so badly?
Change this:
const currentDay = new Date();
this.availableFromDate = currentDay;
this.availableToDate = currentDay;
To this:
const currentDay = new Date();
currentDay.setHours(0, 0, 0, 0);
this.availableFromDate = new Date(currentDay);
this.availableToDate = new Date(currentDay);
This will zero out the time portion and make date comparison straight forward.
Next, change this:
if (
(this.availableFromDate > this.availableToDate) ||
(this.availableFromDate === this.availableToDate)
)
To this (assuming that you want to check greater than or equal to):
if (this.availableFromDate >= this.availableToDate)
You cannot compare two dates with === although you can compare them using < <= >= >.
It looks like the Date objects that come in from your date picker via onFromChange/onToChange are pure dates (they are all at midnight), while the date objects that you create with Date() will have the current time included. The js Date class should really have been called DateTime. The mismatched times will cause the === comparison to fail.
Try using something like this to set availableFromDate and availableToDate in your initDatepickers function:
private getCurrentDate() {
const date = new Date();
date.setHours(0);
date.setMinutes(0);
date.setSeconds(0);
date.setMilliseconds(0);
}
EDIT: Nevermind, the === will still fail if you do this, because Date is an object, so === checks for reference equality. Two Date objects can hold the same underlying date/time values, but they are still considered to be separate objects. Things like numbers, however, are value types, so === will tell you if the two values are equal. E.g:
5 === 5; // True, because pure numbers are value types
const number1 = { number: 5 }; // This is an object, so it is a reference type. Dates are also objects.
const number2 = { number: 5 }; // Another reference type
number1 === number2; // False, because although number1 and number2 hold the same values, they are still distinct objects.
See Salman's answer for a proper solution.

how to use findIndex javascript method with date object? [duplicate]

When comparing date objects in Javascript I found that even comparing the same date does not return true.
var startDate1 = new Date("02/10/2012");
var startDate2 = new Date("01/10/2012");
var startDate3 = new Date("01/10/2012");
alert(startDate1>startDate2); // true
alert(startDate2==startDate3); //false
How could I compare the equality of these dates? I am interested in utilizing the native Date object of JS and not any third party libraries since its not appropriate to use a third party JS just to compare the dates.
That is because in the second case, the actual date objects are compared, and two objects are never equal to each other. Coerce them to number:
alert( +startDate2 == +startDate3 ); // true
If you want a more explicity conversion to number, use either:
alert( startDate2.getTime() == startDate3.getTime() ); // true
or
alert( Number(startDate2) == Number(startDate3) ); // true
Oh, a reference to the spec: §11.9.3 The Abstract Equality Comparison Algorithm which basically says when comparing objects, obj1 == obj2 is true only if they refer to the same object, otherwise the result is false.
Compare dates using getTime() returning number of milliseconds from epoch (i.e. a number):
var startDate1 = new Date("02/10/2012");
var startDate2 = new Date("01/10/2012");
var startDate3 = new Date("01/10/2012");
alert(startDate1.getTime() > startDate2.getTime()); // true
alert(startDate2.getTime() == startDate3.getTime()); //true
Also consider using Date constructor taking explicit year/month/date number rather then relying on string representation (see: Date.parse()). And remember that dates in JavaScript are always represented using client (browser) timezone.
You do not need to use the getTime method- you can subtract a date object from another date object. It will return the milliseconds difference(negative, if the second is a later date)
var startDate1 = new Date("02/10/2012");
var startDate2 = new Date("01/10/2012");
var diff= (startDate1 -startDate2)
// evaluates to 0 if the dates have the same timestamp
you can compare the actual milliseconds :
alert(startDate2.getTime() === startDate3.getTime());
tl;dr
Use date.getTime() for comparisons.
Based on my testing, it was at least 25% than the next fastest alternative (date.valueOf()).
Details
Came across this in 2022. As others have already said, comparing like date1.getTime() === date2.getTime() is the way to go.
Someone else shared a jsperf link in an answer that seems broken for me right now, so decided to add some performance comparison of my own.
I created two arrays containing 1000 dates each. All dates will naturally be different instances (meaning direct === checks will fail), so what this benchmark does, is test what the fastest way is to convert a date to a primitive.
Here's the test data:
const data1 = Array.from({length: 1000}, () => new Date())
const data2 = Array.from({length: 1000}, () => new Date())
And here are the test cases (there's more in the link below):
// 1
data1.forEach((d1, i) => d1.getTime() === data2[i].getTime());
// 2
data1.forEach((d1, i) => d1.valueOf() === data2[i].valueOf());
// 3
data1.forEach((d1, i) => Number(d1) === Number(data2[i]));
// 4
data1.forEach((d1, i) => d1.toISOString() === data2[i].toISOString());
Result (use date.getTime())
Not a surprise that a date.getTime() conversion is much faster. It's around 25% faster than date.valueOf(), and between 10x and 100x faster than everything else (as far as I've checked).
Additionally, introducing optional chaining slowed the best case by almost 10% for me. Found that interesting. date.valueOf() also slowed down by 5% compared to its non optional chaining counterpart.
data1.forEach((d1, i) => d1?.getTime() === data2[i]?.getTime());
Benchmark link: here
Here's an image, in case the above link breaks at some point in the future.
You can also use the function valueOf()
var startDate1 = new Date("02/10/2012").valueOf();
var startDate2 = new Date("01/10/2012").valueOf();
var startDate3 = new Date("01/10/2012").valueOf();
alert(startDate1>startDate2); // 1326150000000 > 1328828400000 true
alert(startDate2==startDate3); // 1328828400000 > 1326150000000 false
One more way of comparing two dates would be converting dates to timestamps using "+" operator before the date.
So, let's say we have two dates:
const dateOne = new Date("10 January 1986")
const dateTwo = new Date("10 December 2020")
if(+dateOne == +dateTwo){
//do something
}
and so on.
This is really handy if you are sorting date objects too as you can use this in the sorting callback function.

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.

Why is this function behaving weirdly

I have the following JavaScript as below
function getExpiryDate(contract) {
var expiryDay;
var contractType;
var today = new moment();
var today1 = new moment();
var x = myFunction(4, 3);
var abc =3;
var xyz= 4;
var c = myFunction(abc, xyz);
console.log("abc is: "+abc);
console.log("xyz is: "+xyz);
console.log(today1);
expiryDay = getlastDayofMonth('Thursday',today1);
console.log(today1); /* Why has the value of today changed? */
}
function getlastDayofMonth(dayName,date1) {
var endDate = date1.endOf('month');
var lastDayOfMonth = endDate.format('dddd');
var weekDayToFind = moment().day(dayName).weekday(); //change to searched day name
var searchDate = endDate; //now or change to any date
while (searchDate.weekday() !== weekDayToFind)
{
searchDate.subtract(1, 'days');
}
return searchDate;
}
function myFunction(a, b) {
return a * b; // Function returns the product of a and b
}
When I execute I get the following output.
expirydate.js:11 abc is: 3
expirydate.js:12 xyz is: 4
expirydate.js:13 Moment { _d: Wed Aug 31 2016 10:21:04 GMT+0530 }
expirydate.js:15 Moment { _d: Thu Aug 25 2016 23:59:59 GMT+0530 }
I am totally confused on why the value of today1 changes when it is used in the function.
Because in JS, objects are passing by reference and not by value. It means you are working on the same object.
To prevent this you have to clone date1 value in the function into a variable with a scope restricted to the function
This is happening because Moment is written in a mutable style of code. It's fairly surprising behavior. After reading through your code a few times I couldn't find any obvious problem until I looked at the Moment documentation.
The .endOf() method mutates the date, aka changes the date of the moment object you call it on:
Mutates the original moment by setting it to the end of a unit of time.
So when you call that method here:
var endDate = date1.endOf('month');
It's mutating date1, meaning it modifies date1 in place and changes its time. In fact, it looks like almost all of moment's methods mutate the moment object. There's a discussion on Github about why the API is designed poorly.
In terms of solving your specific problem, it's a personal style preference. I think it's undesirable to force the user to clone an object before passing it to a function. So I would clone the moment passed in inside the function:
function getlastDayofMonth(dayName,date1) {
var endDate = date1.clone().endOf('month');

Categories

Resources