Current section

Files

Jump to
timex lib convert convert.ex
Raw

lib/convert/convert.ex

defmodule Timex.Convert do
@moduledoc false
@doc """
Converts a map to a Date, NaiveDateTime or DateTime, depending on the amount
of date/time information in the map.
"""
@spec convert_map(Map.t) :: Date.t | DateTime.t | NaiveDateTime.t | {:error, term}
def convert_map(map) when is_map(map) do
case convert_keys(map) do
{:error, _} = err ->
err
datetime_map when is_map(datetime_map) ->
year = Map.get(datetime_map, :year)
month = Map.get(datetime_map, :month)
day = Map.get(datetime_map, :day)
cond do
not(is_nil(year)) and not(is_nil(month)) and not(is_nil(day)) ->
case Map.get(datetime_map, :hour) do
nil ->
Date.new(year, month, day)
hour ->
minute = Map.get(datetime_map, :minute, 0)
second = Map.get(datetime_map, :second, 0)
us = Map.get(datetime_map, :microsecond, {0, 0})
tz = Map.get(datetime_map, :time_zone, nil)
case tz do
s when is_binary(s) ->
Timex.DateTime.Helpers.construct({{year,month,day},{hour,minute,second,us}}, tz)
nil ->
{:ok, nd} = NaiveDateTime.new(year, month, day, hour, minute, second, us)
nd
end
end
:else ->
{:error, :insufficient_date_information}
end
end
end
def try_convert(_), do: {:error, :invalid_date}
@allowed_keys_atom [
:year, :month, :day,
:hour, :minute, :min, :mins, :second, :sec, :secs,
:milliseconds, :millisecond, :ms,
:microsecond
]
@allowed_keys Enum.concat(@allowed_keys_atom, Enum.map(@allowed_keys_atom, &Atom.to_string/1))
@valid_keys_map %{
:min => :minute,
:mins => :minute,
:secs => :second,
:sec => :second,
:milliseconds => :millisecond,
:ms => :millisecond,
:microsecond => :microsecond,
:tz => :time_zone,
:timezone => :time_zone,
:time_zone => :time_zone
}
def convert_keys(map) when is_map(map) do
Enum.reduce(map, %{}, fn
{_, _}, {:error, _} = err -> err
{k, v}, acc when k in [:microsecond, "microsecond"] ->
case v do
{us, pr} when is_integer(us) and pr >= 0 and pr <= 6 ->
Map.put(acc, :microsecond, {us, pr})
us when is_integer(us) ->
Map.put(acc, :microsecond, {us, 6})
_ -> acc
end
{k, v}, acc when k in [:milliseconds, "milliseconds", :ms, "ms", :millisecond, "millisecond"] ->
case v do
n when is_integer(n) ->
us = Timex.DateTime.Helpers.construct_microseconds(n*1_000)
Map.put(acc, :microsecond, us)
:error ->
{:error, {:expected_integer, for: k, got: v}}
end
{k, v}, acc when k in [:tz, "tz", :timezone, "timezone", :time_zone, "time_zone"] ->
case v do
s when is_binary(s) -> Map.put(acc, :time_zone, s)
%{"full_name" => s} -> Map.put(acc, :time_zone, s)
_ -> acc
end
{k, v}, acc when k in @allowed_keys and is_atom(k) and is_integer(v) ->
case Map.get(@valid_keys_map, k) do
nil -> Map.put(acc, k, v)
vk -> Map.put(acc, vk, v)
end
{k, v}, acc when k in @allowed_keys and is_integer(v) ->
ak = String.to_atom(k)
case Map.get(@valid_keys_map, ak) do
nil -> Map.put(acc, ak, v)
vk -> Map.put(acc, vk, v)
end
{k, v}, acc when k in @allowed_keys and is_atom(k) and is_binary(v) ->
case Integer.parse(v) do
{n, _} ->
case Map.get(@valid_keys_map, k) do
nil -> Map.put(acc, k, n)
vk -> Map.put(acc, vk, n)
end
:error ->
{:error, {:expected_integer, for: k, got: v}}
end
{k, v}, acc when k in @allowed_keys and is_binary(v) ->
case Integer.parse(v) do
{n, _} ->
ak = String.to_atom(k)
case Map.get(@valid_keys_map, ak) do
nil -> Map.put(acc, ak, n)
vk -> Map.put(acc, vk, n)
end
:error ->
{:error, {:expected_integer, for: k, got: v}}
end
{_, _}, acc -> acc
end)
end
end