Created
December 22, 2020 13:02
-
-
Save johninvictus/9bbfd9d233e80b92d6d91b1d74deda50 to your computer and use it in GitHub Desktop.
duration_parser.ex
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule DurationParser do | |
@moduledoc """ | |
Parse a given string as either a time interval or a fractional number of hours | |
and return the equivalent number of hours and minutes. | |
## Examples | |
iex> DurationParser.parse_minutes("2:15") | |
{:ok, 135} | |
iex> DurationParser.parse_minutes("02:15") | |
{:ok, 135} | |
iex> DurationParser.parse_minutes("2h 35m") | |
{:ok, 155} | |
iex> DurationParser.parse_minutes("10") | |
{:ok, 10} | |
iex> DurationParser.parse_minutes("0.5h") | |
{:ok, 30} | |
iex> DurationParser.parse_minutes("0.5") | |
{:ok, 30} | |
iex> DurationParser.parse_minutes("10.0") | |
{:ok, 600} | |
iex> DurationParser.parse_minutes("7.5") | |
{:ok, 450} | |
iex> DurationParser.parse_minutes("24.5") | |
{:ok, 1470} | |
iex> DurationParser.parse_minutes("a24.5") | |
{:error, "expected 2 digits"} | |
""" | |
@type response :: {:ok, integer()} | :error | |
def parse_minutes(str) do | |
with :error <- parse_hour_colon_str(str), | |
:error <- parse_hours_space_minutes(str), | |
:error <- parse_fraction_hours(str), | |
:error <- parse_only_minutes(str) do | |
{:error, "expected 2 digits"} | |
end | |
end | |
@doc """ | |
This function will be used to match duration with full colon in them | |
ie. "2:15 | |
""" | |
@spec parse_hour_colon_str(String.t()) :: response | |
def parse_hour_colon_str(str) do | |
with [hours_str, minutes_str] <- try_parse_duration_colon(str), | |
{:ok, h_minutes} <- try_h_hours_to_minutes(hours_str), | |
{:ok, m_minutes} <- try_m_minutes_to_minutes(minutes_str) do | |
total = m_minutes + h_minutes | |
{:ok, total} | |
end | |
end | |
@doc """ | |
This function will be for matching duration with a space in it | |
ie. 2h 35m | |
""" | |
@spec parse_hours_space_minutes(String.t()) :: response | |
def parse_hours_space_minutes(str) do | |
with [hours_str, minutes_str] <- try_parse_hours_space_minutes(str), | |
{:ok, h_minutes} <- try_h_hours_to_minutes(hours_str), | |
{:ok, m_minutes} <- try_m_minutes_to_minutes(minutes_str) do | |
total = m_minutes + h_minutes | |
{:ok, total} | |
end | |
end | |
@doc """ | |
This function will be used for parsing fraction time | |
""" | |
@spec parse_fraction_hours(String.t()) :: response | |
def parse_fraction_hours(str) do | |
case String.split(str, ".") do | |
[hours_l, minutes_r] -> | |
minutes_str = String.replace(minutes_r, "h", "") | |
(hours_l <> "." <> minutes_str) | |
|> try_parse_as_number() | |
_ -> | |
:error | |
end | |
end | |
@doc ~S""" | |
This function will be used to parse minutes | |
It will accept a plain number or number with m in it ie | |
10 or 10m | |
""" | |
@spec parse_only_minutes(String.t()) :: response | |
def parse_only_minutes(str) do | |
try_m_minutes_to_minutes(str) | |
end | |
defp try_parse_hours_space_minutes(str) do | |
case String.split(str, " ") do | |
[hours_str, minutes_str] -> | |
[hours_str, minutes_str] | |
_ -> | |
:error | |
end | |
end | |
defp try_parse_duration_colon(str) do | |
case String.split(str, ":") do | |
[hours_str, minutes_str] -> | |
[hours_str, minutes_str] | |
_ -> | |
:error | |
end | |
end | |
defp try_h_hours_to_minutes(hours_str) do | |
case String.split(hours_str, "h") do | |
[hours, _] -> | |
try_hours_to_minutes(hours) | |
_ -> | |
try_hours_to_minutes(hours_str) | |
end | |
end | |
defp try_hours_to_minutes(hours_str) do | |
case Integer.parse(hours_str) do | |
{num, ""} -> | |
{:ok, num * 60} | |
_ -> | |
:error | |
end | |
end | |
# return minutes | |
defp try_m_minutes_to_minutes(minutes_str) do | |
case String.split(minutes_str, "m") do | |
[minutes, _] -> | |
try_minutes_to_minutes(minutes) | |
_ -> | |
try_minutes_to_minutes(minutes_str) | |
end | |
end | |
def try_minutes_to_minutes(minutes_str) do | |
case Integer.parse(minutes_str) do | |
{num, ""} -> | |
{:ok, num} | |
_ -> | |
:error | |
end | |
end | |
# work on fraction | |
defp try_parse_as_number(str) do | |
case Float.parse(str) do | |
{num, ""} -> {:ok, trunc(num * 60)} | |
_ -> :error | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment