Chcete někomu připravit pěkné aprílové překvapení v kódu? Jeden den testy fungují a další ráno najednou ne? Zkuste tohle :-)

defmodule April do
  def check(date) do
    day_before = Date.add(date, -1)
    if day_before < date do
      "#{date} - The World is OK today."
    else
      "#{date} - April Fools' Day!"
    end
  end
end

IO.puts(April.check(~D[2020-03-31]))
IO.puts(April.check(~D[2020-04-01]))
IO.puts(April.check(~D[2020-04-02]))

Kód si zkopírujte a uložte třeba do souboru april.exs. Pak ho spusťte:

$ elixir april.exs
2020-03-31 - The World is OK today.
2020-04-01 - April Fools' Day!
2020-04-02 - The World is OK today.

Porovnáváme day_before < date. Jak je možné, že 1. dubna podmínka najednou neplatí? Datum v našem kódu je struct. Příkazem IO.inspect(date, structs: false) zobrazíme nenaformátovaný tvar a zjistíme, že v pozadí se skrývá mapa:

iex(1)> IO.inspect(~D[2020-03-31], structs: false)
%{__struct__: Date, calendar: Calendar.ISO, day: 31, month: 3, year: 2020}
~D[2020-03-31]

iex(2)> IO.inspect(~D[2020-04-01], structs: false)
%{__struct__: Date, calendar: Calendar.ISO, day: 1, month: 4, year: 2020}
~D[2020-04-01]

V kódu tedy porovnáváme dvě mapy, které se v klíčích day a month liší. Vše zdánlivě funguje, ale na přelomu měsíce máme problém. Hodnota v klíči day (který má v tomto případě díky pravidlům pro porovnávání map přednost před klíčem month) kód rozbije: 31 > 1.

Datumy je nutné vždy porovnávat pomocí funkce Date.compare/2. V skriptu tedy day_before < date nahradíme Date.compare(day_before, date) == :lt a porovnání bude fungovat bez aprílových překvápek.