jeffdeville
Elixir's DateTime values don't seem to compare correctly
Elixir 1.3.4 & 1.4.0
dt1 = %DateTime{calendar: Calendar.ISO, day: 12, hour: 0, month: 1, std_offset: 0, time_zone: "Etc/UTC", utc_offset: 0, year: 2017, zone_abbr: "UTC", microsecond: {878630, 6}, minute: 57, second: 59}
dt2 = %DateTime{calendar: Calendar.ISO, day: 12, hour: 0, month: 1, std_offset: 0, time_zone: "Etc/UTC", utc_offset: 0, year: 2017, zone_abbr: "UTC", microsecond: {481183, 6}, minute: 58, second: 2}
dt1 <= dt2
false
This was part of a spec that had been working fine until I upgraded Ecto to 2.1, and swapped out Ecto.DateTime for elixir’s DateTime. After upgrading to 1.4.0, I tried DateTime.compare, which seemed to work
DateTime.compare(dt1, dt2)
:lt
What am I missing here?
Marked As Solved
bbense
Basic Erlang ordering often produces confusing results when you apply it to complicated data structures such as a map with Tuples.
Look into the Erlang man page on Comparision operators and Term ordering
The arguments can be of different data types. The following order is defined:
number < atom < reference < fun < port < pid < tuple < map < nil < list < bit string
Lists are compared element by element. Tuples are ordered by size, two tuples with the same size are compared element by element.
Maps are ordered by size, two maps with the same size are compared by keys in ascending term order and then by values in key order. In maps key order integers types are considered less than floats types.
When comparing an integer to a float, the term with the lesser precision is converted into the type of the other term, unless the operator is one of =:= or =/=. A float is more precise than an integer until all significant figures of the float are to the left of the decimal point. This happens when the float is larger/smaller than +/-9007199254740992.0. The conversion strategy is changed depending on the size of the float because otherwise comparison of large floats and integers would lose their transitivity.
Term comparison operators return the Boolean value of the expression, true or false.
So since DateTime is a map, it will sort the keys in term order, and microsecond is before minute. Once it finds a key that disgrees it stops searching.
It is possible to make structs that will sort properly with the default Erlang term ordering, but it is quite tricky and often leads to many strange edge cases and odd naming conventions.
Also Liked
rvirding
nil is the empty list in Erlang [] as well, we just call it nil by tradition. We were lisp hackers from way back.
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance









