defmodule Azan.TimeComponent do @moduledoc """ Documentation for `TimeComponent`. """ use TypedStruct typedstruct do field :hour, integer() field :minute, integer() field :second, integer() end @doc ~S""" Create a new `TimeComponent` from an hour with fractional part. ## Examples iex> TimeComponent.new(12.5) %TimeComponent{hour: 12, minute: 30, second: 0} """ def new({:error, _}) do {:error, :invalid_time_component} end def new(num) do hour = num |> floor() minute = ((num - hour) * 60) |> floor() second = ((num - hour - minute / 60) * 3600) |> floor() %__MODULE__{hour: hour, minute: minute, second: second} end @doc ~S""" Convert a `TimeComponent` to a string in the format of "HH:MM". ## Examples iex> TimeComponent.new(12.5) |> TimeComponent.to_hm_string() "12:30" """ def to_hm_string(%__MODULE__{hour: hour, minute: minute, second: second}) do hour_string = hour |> Integer.to_string() minute_string = (minute + round(second / 60)) |> Integer.to_string() |> String.pad_leading(2, "0") hour_string <> ":" <> minute_string end @doc ~S""" Create a DateTime from `TimeComponent` ## Examples iex> TimeComponent.new(12.5) |> TimeComponent.create_utc_datetime(2015, 1, 1) ~U[2015-01-01 12:30:00Z] """ def create_utc_datetime({:error, _reason}, _date), do: {:error, :invalid_date} def create_utc_datetime(%__MODULE__{hour: hour, minute: minute, second: second}, %Date{ year: year, month: month, day: day }) do create_utc_datetime( %__MODULE__{hour: hour, minute: minute, second: second}, year, month, day ) end def create_utc_datetime({:error, _reason}, _year, _month, _day), do: {:error, :invalid_date} def create_utc_datetime( %__MODULE__{hour: hour, minute: minute, second: second}, year, month, day ) when hour > 23 do day_offset = hour |> div(24) hour = hour |> rem(24) create_utc_datetime( %__MODULE__{hour: hour, minute: minute, second: second}, year, month, day ) |> Timex.shift(days: day_offset) end def create_utc_datetime( %__MODULE__{hour: hour, minute: minute, second: second}, year, month, day ) when hour < 0 and hour > -23 do hour = hour + 24 create_utc_datetime( %__MODULE__{hour: hour, minute: minute, second: second}, year, month, day ) |> Timex.shift(days: -1) end def create_utc_datetime( %__MODULE__{hour: hour, minute: minute, second: second}, year, month, day ) when hour < -23 do day_offset = hour |> div(24) hour = hour + 24 create_utc_datetime( %__MODULE__{hour: hour, minute: minute, second: second}, year, month, day ) |> Timex.shift(days: day_offset) end def create_utc_datetime( %__MODULE__{hour: hour, minute: minute, second: second}, year, month, day ) do {{year, month, day}, {hour, minute, second}} |> Timex.to_datetime("UTC") end end