So I'm just starting out in Elixir and saw that the current master
adds support for a ~U[2015-01-13 13:00:07Z]
sigil to create/parse UTC date.
Code follows:
defmodule MySigils do
defmacro sigil_U(datetime_string, modifiers)
defmacro sigil_U({:<<>>, _, [string]}, []) do
Macro.escape(datetime_from_utc_iso8601!(string))
end
defp datetime_from_utc_iso8601!(string) do
case DateTime.from_iso8601(string) do
{:ok, utc_datetime, 0} ->
utc_datetime
{:ok, _datetime, _offset} ->
raise ArgumentError,
"cannot parse #{inspect(string)} as UTC datetime, reason: :non_utc_offset"
{:error, reason} ->
raise ArgumentError,
"cannot parse #{inspect(string)} as UTC datetime, reason: #{inspect(reason)}"
end
end
end
In my code I'm trying to use this with a variable timestamp
timestamp = Map.get(item, "timestamp")
~U[timestamp]
** (ArgumentError) cannot parse "timestamp" as UTC datetime, reason: :invalid_format
but timestamp
is being interpreted as is, not the previous match.
Is there a way I can make it work? Do I need to quote/unquote something? Beside using DateTime.from_iso8601/1
directly.
Everything between sigil delimiters is sent as a string. So timestamp
variable is sent to sigil_U
as the string "timestamp"
. There are some sigils that allow interpolation which are by convention in lowercase. For example ~r
versus ~R
:
iex(1)> x = "foo"
"foo"
iex(2)> ~R/#{x}/
~r/\#{x}/
iex(3)> ~r/#{x}/
~r/foo/
But in this case no lowercase version of sigil_U
is defined so you can't interpolate timestamp
.