Here's a fun challenge, converting seconds into a specially formatted HH:MM:SS string -- Here's what I did, what would you do?

A few weeks ago I was working on a feature where I wanted to output human readable time spans, similar to what you might see in Youtube’s video player for keeping track of the time.

For example, 0:40, 1:50, 12:50 and so on.

I wrote a blog post that defines the spec in more detail and included both a Python and Elixir code example of how I solved the problem. There’s also a code solution from Greg Vaughn because he happened to be on Slack at the time of when I asked a question around solving this problem.

I thought maybe it would be interesting to post it here just to see how others would solve the problem. I have a feeling there’s probably 20 different ways this could be solved and the last time I posted something like this (a request for others to post their code to solve a real world problem) it had a lot of great submissions and discussions.

The spec and code examples can be found here: https://nickjanetakis.com/blog/formatting-seconds-into-hh-mm-ss-with-elixir-and-python. If you only care about the code, skim around. You’ll find the code blocks in a few seconds.

Feel free to post your code here.

1 Like

Here’s my approach. Posting it as a Gist to avoid accidentally spoiling the solution.
https://gist.github.com/alco/ed213fc92510aa899984700c5c4fc04f.

3 Likes

My take using strftime in Elixir master (upcoming v1.11): https://gist.github.com/josevalim/dd78e6c5c050927b3e4674744de04393

7 Likes

Great idea, and nice code.

Does it pass the test suite at https://gist.github.com/alco/ed213fc92510aa899984700c5c4fc04f#file-time_format_test-exs?

It’s hard to tell from looking at it without running it, but how does it handle tracks less than 1 minute with adding a zero based minute 0:XX, only zero padding the non-left most cases or not showing the HH: for tracks less than 1 hour?

Using one of my ex_cldr libs. Similar approach to José’s. The function remove_leading_zeros/1 would probably apply to that code as well.

defmodule TimeFormat do
  def format(seconds) do
    ~T[00:00:00]
    |> Time.add(seconds)
    |> Cldr.Time.to_string!(format: "HH:mm:ss")
    |> remove_leading_zeros
  end

  def remove_leading_zeros("00:0" <> rest), do: rest
  def remove_leading_zeros("00:" <> rest), do: rest
  def remove_leading_zeros("0" <> rest), do: rest
  def remove_leading_zeros(other), do: other
end
4 Likes

Doesn’t this and @josevalim approach will work only when there is less than 24 hours? If it is the case (so the amount of seconds is less than 86400) then one can use:

def format(seconds) do
  seconds
  |> :calendar.seconds_to_time()
  |> do_format()
  |> List.to_string()
end

defp do_format({0, m, s}), do: :io_lib.format("~B:~2..0B", [m, s])
defp do_format({h, m, s}), do: :io_lib.format("~B:~2..0B:~2..0B", [h, m, s])
4 Likes