Packages

A simple library which converts the values of maps from various string representations of dates and times into native Elixir 1.3 dates. This is useful as a plug for converting user input into something that can reliably be sent to Ecto for saving to a database.

Current section

Files

Jump to
date_params lib date_params.ex
Raw

lib/date_params.ex

defmodule DateParams do
@moduledoc """
An Elixir library that converts specified values within maps into native
`Date`, `DateTime`, `NaiveDateTime`, and `Time` structs.
"""
@doc"""
Convert the values within a map to DateTime structs for the given keys.
The keys given follows the format for accessing nested structures like
in `Kernel.get_in/2`.
"""
def to_structs(map, keys) do
Enum.reduce(keys, map, &transform_values/2)
end
@doc"""
Converts the value to a DateTime struct
"""
def to_struct(value), do: transform_value(value)
# Converts a value to integer for creating dates
defp to_integer(value) when is_atom(value),
do: value |> Atom.to_string |> String.to_integer
defp to_integer(value) when is_bitstring(value),
do: String.to_integer(value)
defp to_integer(value),
do: value
# ISO 8601 date and time without seconds (Chrome's datetime input submits this way)
defp transform_value(value = <<_::4-bytes, ?-, _::2-bytes, ?-, _::2-bytes, sep,
_::2-bytes, ?:, _::2-bytes>>) when sep in [?\s, ?T] do
transform_value(value <> ":00")
end
# ISO 8601 date and time with seconds
defp transform_value(value = <<_::4-bytes, ?-, _::2-bytes, ?-, _::2-bytes, sep,
_::2-bytes, ?:, _::2-bytes, ?:, _::2-bytes>>) when sep in [?\s, ?T] do
case Calendar.NaiveDateTime.Parse.iso8601(value) do
{:ok, datetime, nil} -> {value, datetime}
{:error, _} -> {value, value}
end
end
# Phoenix-style date-time param maps
defp transform_value(value = %{"year" => year, "month" => month, "day" => day,
"hour" => hour, "minute" => minute, "second" => second}) do
datetime = NaiveDateTime.new(to_integer(year), to_integer(month), to_integer(day),
to_integer(hour), to_integer(minute), to_integer(second))
case datetime do
{:ok, date} -> {value, date}
{:error, _} -> {value, value}
end
end
# ISO 8601 dates
defp transform_value(value = <<_::4-bytes, ?-, _::2-bytes, ?-, _::2-bytes>>) do
case Calendar.Date.Parse.iso8601(value) do
{:ok, date} -> {value, date}
{:error, _} -> {value, value}
end
end
# Phoenix-style date param maps
defp transform_value(value = %{"year" => year, "month" => month, "day" => day}) do
case Date.new(to_integer(year), to_integer(month), to_integer(day)) do
{:ok, date} -> {value, date}
{:error, _} -> {value, value}
end
end
# Fallback
defp transform_value(value), do: {value, value}
# Get and covert for the given keys
defp transform_values(keys, map) do
{_, transformed} = get_and_update_in(map, keys, &transform_value/1)
transformed
end
end