Packages

Ecto-friendly units commonly used in the IHDL world.

Current section

Files

Jump to
ex_ihdl_units lib zse date_time.ex
Raw

lib/zse/date_time.ex

defmodule ExIhdlUnits.Zse.DateTime do
@behaviour Ecto.Type
@seconds_per_year 31_557_600
@zse_ts_epoch_offset_years 30
alias Elixir.DateTime, as: ElixirDateTime
def type, do: :utc_datetime
def cast(device_recorded_at_zsets)
when is_integer(device_recorded_at_zsets) do
with {:ok, device_recorded_at_zse_utc} <- ElixirDateTime.from_unix(device_recorded_at_zsets) do
cast(device_recorded_at_zse_utc)
end
end
def cast(device_recorded_at_zsets)
when is_binary(device_recorded_at_zsets) do
with {:ok, device_recorded_at_zse_utc, _utc_offset} <-
ElixirDateTime.from_iso8601(device_recorded_at_zsets) do
cast(device_recorded_at_zse_utc)
end
end
def cast(%ElixirDateTime{} = device_recorded_at_zse_utc) do
years_diff =
ElixirDateTime.diff(
ElixirDateTime.utc_now(),
device_recorded_at_zse_utc,
:second
)
device_recorded_at =
cond do
years_diff > 20 * @seconds_per_year ->
Timex.shift(device_recorded_at_zse_utc, years: @zse_ts_epoch_offset_years)
true ->
device_recorded_at_zse_utc
end
{:ok, device_recorded_at |> ElixirDateTime.truncate(:second)}
end
# Everything else is a failure though
def cast(_), do: :error
# When loading data from the database, we are guaranteed to
# receive a map (as databases are strict) and we will
# just put the data back into an URI struct to be stored
# in the loaded schema struct.
def load(data) do
{:ok, ElixirDateTime.from_naive!(data, "Etc/UTC") |> ElixirDateTime.truncate(:second)}
end
# When dumping data to the database, we *expect* an URI struct
# but any value could be inserted into the schema struct at runtime,
# so we need to guard against them.
def dump(%ElixirDateTime{} = datetime), do: {:ok, datetime |> ElixirDateTime.truncate(:second)}
def dump(_), do: :error
end