Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does MomentJS work comparing values with > and < (and >=, <=)?

I'm using moment.js in a current project and I see that the comparison operators <,>,>=,<= work correctly. However == does not.

It surprises me that these work and that you don't need to use the .isBefore() and .isAfter() functions.

Can anyone give me a brief description of why these work? Would it be possible to make == work as well?

Thanks.

like image 613
Charley Rathkopf Avatar asked Apr 11 '14 18:04

Charley Rathkopf


1 Answers

This is due to how comparison and equality operators in JavaScript work (emphasis mine):

For relational abstract comparisons (e.g., <=), the operands are first converted to primitives, then to the same type, before comparison.

[...]

The equality operator converts the operands if they are not of the same type, then applies strict comparison. If either operand is a number or a boolean, the operands are converted to numbers if possible; else if either operand is a string, the string operand is converted to a number if possible. If both operands are objects, then JavaScript compares internal references which are equal when operands refer to the same object in memory.

So when two moment objects are compared with inequalities, they are first converted to numbers. For Moment.js objects, this is milliseconds since the unix epoch of midnight UTC, Jan 1st 1970.

In your favorite browser's console window/node REPL:

> +moment()
<- 1412332710977

For the == equality check, the runtime does a reference comparison between the two objects, which returns false for two different moment instances, even if they both are for the same date/time.

A lack of default .equals() or operator==() overloading in JavaScript makes this behaviour rather counter-intuitive, especially if you're coming from other languages.

Also note that Moment's isBefore/isAfter functions are really slow, as they clone both moment objects internally before doing the comparison (this is because there is an optional argument to isBefore/isAfter to specify which time component to compare on (e.g. 'hour') and it clones regardless of whether this argument is present or not).

Moment suffers here from having mutable objects, which is why it is doing a defensive clone() in the first place, and then further from not having optimised the common path where this is actually unnecessary.

like image 168
Alastair Maw Avatar answered Nov 14 '22 22:11

Alastair Maw