elixir-map_diff
elixir-map_diff copied to clipboard
DateTime comparisons do not work
Here is an example of where DateTime
values are not being considered equal, I suppose because under-the-hood a regular ==
comparison is being done:
# DateTime with no milliseconds
iex(1)> dt_1 = ~U[2020-01-01T00:00:00Z]
~U[2020-01-01 00:00:00Z]
# DateTime with milliseconds
iex(2)> dt_2 = ~U[2020-01-01T00:00:00.000Z]
~U[2020-01-01 00:00:00.000Z]
# Putting them in maps, they are not equal
iex(3)> MapDiff.diff(%{dt: dt_1}, %{dt: dt_2})
%{
added: %{dt: ~U[2020-01-01 00:00:00.000Z]},
changed: :map_change,
removed: %{dt: ~U[2020-01-01 00:00:00Z]},
value: %{
dt: %{
added: ~U[2020-01-01 00:00:00.000Z],
changed: :map_change,
removed: ~U[2020-01-01 00:00:00Z],
struct_name: DateTime,
value: %{
calendar: %{changed: :equal, value: Calendar.ISO},
day: %{changed: :equal, value: 1},
hour: %{changed: :equal, value: 0},
microsecond: %{
added: {0, 3},
changed: :primitive_change,
removed: {0, 0}
},
minute: %{changed: :equal, value: 0},
month: %{changed: :equal, value: 1},
second: %{changed: :equal, value: 0},
std_offset: %{changed: :equal, value: 0},
time_zone: %{changed: :equal, value: "Etc/UTC"},
utc_offset: %{changed: :equal, value: 0},
year: %{changed: :equal, value: 2020},
zone_abbr: %{changed: :equal, value: "UTC"}
}
}
}
}
# Comparing them using == they are not equal
iex(4)> dt_1 == dt_2
false
# Comparing them with DateTime.compare/2 works as expected
iex(5)> DateTime.compare(dt_1, dt_2)
:eq
Possible solutions
- Add an option for common structs like this to be compared using their own
compare
functions:
MapDiff.diff(map1, map2, compare_carefully: [DateTime, NaiveDateTime])
- Add a callback to let users do their own comparisons for specific types:
MapDiff.diff(map1, map2, compare: {DateTime, fn a, b -> DateTime.compare(a, b) == :eq end})
If you let me know what your preference is I can prepare a PR.