Current section

Files

Jump to
timex lib format time formatters humanized.ex
Raw

lib/format/time/formatters/humanized.ex

defmodule Timex.Format.Time.Formatters.Humanized do
@moduledoc """
Handles formatting timestamp values as human readable strings.
For formatting timestamps as points in time rather than intervals,
use `DateFormat`
"""
use Timex.Format.Time.Formatter
@minute 60
@hour @minute * 60
@day @hour * 24
@week @day * 7
@month @day * 30
@year @day * 365
@doc """
Return a human readable string representing the time interval.
## Examples
iex> {1435, 180354, 590264} |> #{__MODULE__}.format
"45 years, 6 months, 5 days, 21 hours, 12 minutes, 34 seconds, 590.264 milliseconds"
iex> {0, 65, 0} |> #{__MODULE__}.format
"1 minutes, 5 seconds"
"""
@spec format(Date.timestamp) :: String.t
def format({_,_,_} = timestamp), do: timestamp |> deconstruct |> do_format
defp do_format(components), do: do_format(components, <<>>)
defp do_format([], str), do: str
defp do_format([{unit, value}|rest], str) do
case str do
<<>> -> do_format(rest, "#{value} #{Atom.to_string(unit)}")
_ -> do_format(rest, str <> ", #{value} #{Atom.to_string(unit)}")
end
end
defp deconstruct({_, _, micro} = ts), do: deconstruct({ts |> Time.to_secs |> trunc, micro}, [])
defp deconstruct({0, 0}, components), do: components |> Enum.reverse
defp deconstruct({seconds, us}, components) when seconds > 0 do
cond do
seconds >= @year -> deconstruct({rem(seconds, @year), us}, [{:years, div(seconds, @year)} | components])
seconds >= @month -> deconstruct({rem(seconds, @month), us}, [{:months, div(seconds, @month)} | components])
seconds >= @week -> deconstruct({rem(seconds, @week), us}, [{:weeks, div(seconds, @week)} | components])
seconds >= @day -> deconstruct({rem(seconds, @day), us}, [{:days, div(seconds, @day)} | components])
seconds >= @hour -> deconstruct({rem(seconds, @hour), us}, [{:hours, div(seconds, @hour)} | components])
seconds >= @minute -> deconstruct({rem(seconds, @minute), us}, [{:minutes, div(seconds, @minute)} | components])
true -> deconstruct({0, us}, [{:seconds, seconds} | components])
end
end
defp deconstruct({seconds, micro}, components) when seconds < 0, do: deconstruct({seconds * -1, micro}, components)
defp deconstruct({0, micro}, components) do
msecs = {0, 0, micro} |> Time.abs |> Time.to_msecs
cond do
msecs >= 1.0 -> deconstruct({0, 0}, [{:milliseconds, msecs} | components])
true -> deconstruct({0, 0}, [{:microseconds, micro} | components])
end
end
end