DEV Community

Discussion on: Daily Challenge #21 - Human Readable Time

Collapse
 
brightone profile image
Oleksii Filonenko

Elixir:

defmodule ReadableTime do
  @minute 60
  @hour @minute * 60
  @day @hour * 24
  @year @day * 365

  @spec from_seconds(non_neg_integer) :: String.t()
  def from_seconds(0), do: "now"

  def from_seconds(time) do
    [
      year: &div(&1, @year),
      day: &(&1 |> div(@day) |> rem(365)),
      hour: &(&1 |> div(@hour) |> rem(24)),
      minute: &(&1 |> div(@minute) |> rem(60)),
      second: &rem(&1, 60)
    ]
    |> Enum.map(fn {word, quotient} -> {quotient.(time), pluralize(word, quotient.(time))} end)
    |> Enum.filter(fn {quotient, _} -> quotient > 0 end)
    |> Enum.map(fn {quotient, word} -> "#{quotient} #{word}" end)
    |> to_sentence()
  end

  @spec pluralize(String.t(), non_neg_integer) :: String.t()
  defp pluralize(word, 1), do: word
  defp pluralize(word, n) when n >= 0, do: "#{word}s"

  @spec to_sentence([String.t()]) :: String.t()
  defp to_sentence([elem]), do: elem

  defp to_sentence(list) do
    (list |> Enum.slice(0..-2) |> Enum.join(", ")) <>
      " and " <> List.last(list)
  end
end