When I subtract two Date-objects like this:
const startTime = new Date();
await someAsyncStuff();
const endTime = new Date();
const elapsedTime = endTime - startTime;
console.log(`The async stuff took ${elapsedTime} ms`);
Why does the Date objects end up being cast to milliseconds, which are then subtracted? I understand that they do, but I can't figure out what the actual sequence of events is that lead to this.
In general, JavaScript objects can define methods to convert the object to a String or a number (which you can customize by defining toString and valueOf methods). JavaScript will use those methods in numerical contexts (like 2 * a) or string contexts (like '' + a) to convert the object to the appropriate primitive.
In a context where it's ambiguous whether to use numerical or string conversion (like a + b), there's a default behavior, depending on the type of the object. Interestingly, Date are singled out among the default ECMAScript objects to convert to a String, instead of a number. Via the spec:
Date objects, are unique among built-in ECMAScript object in that they treat "
default" as being equivalent to "string", All other built-in ECMAScript objects treat "default" as being equivalent to "number".
In the particular case of Date objects, the numerical conversion (the valueOf method) converts the time to epoch milliseconds, while the string conversion (the toString method) converts the object to a human-readable string. As @baao mentions in his answer, this can cause some issues when doing "arithmetic" with objects, due to automatic conversions of type.
In summary, Date (unlike most other objects) defaults to string conversion, but since subtraction requires two numbers for it to make sense, it converts the dates to numbers.
It's generally a good idea to explicitly define the behavior, in this case using valueOf, getTime or toString to make the code less ambiguous.
For more information of whether JavaScript chooses to use toString vs valueOf, see this question, the overall spec for addition (and subtraction), and the specific spec for Dates (mdn link), and @baao's answer for a more in depth look.
See Also:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/valueOf
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/valueOf
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With