Packages

Human Time is a function to convert a string such as "every other tuesday", "every weekday" or "every friday at 2pm" and convert it into a sequence of date times as allowed by the string.

Current section

Files

Jump to
human_time lib human_time.ex
Raw

lib/human_time.ex

defmodule HumanTime do
@moduledoc """
Human Time is a function to convert a string such as "every other tuesday", "every weekday" or "next friday at 2pm" and convert it into a one or a sequence of date times as allowed by the string.
"""
alias HumanTime.Repeating
alias HumanTime.Relative
@doc """
Generates a stream of datetimes for the string given.
## Options
`from` The datetime from when the sequence will be generated, defaults to the current time.
`until` The datetime when the sequence will be terminated, defaults to nil. When nil the sequence will never be terminated.
## Example
HumanTime.repeating("Every wednesday at 1530")
|> Stream.take(3)
|> Enum.to_list
#=> [
#=> #DateTime<2018-08-15 15:30:00.848218Z>,
#=> #DateTime<2018-08-22 15:30:00.848218Z>,
#=> #DateTime<2018-08-29 15:30:00.848218Z>
#=> ]
"""
@spec repeating(String.t(), [term]) :: {:ok, Enumerable.t} | {:error, String.t}
def repeating(timestring, opts \\ []) do
from = opts[:from] || Timex.now()
until = opts[:until]
while_function = Repeating.Generators.while_function(until)
result = Repeating.Parser.build_functions(timestring)
case result do
{:error, msg} -> {:error, msg}
{:ok, {generator_function, filter_function, mapper_function}} ->
{:ok, from
|> Stream.iterate(generator_function)
|> Stream.take_while(while_function)
|> Stream.filter(filter_function)
|> Stream.map(mapper_function)
|> Stream.filter(&(&1 != nil))}
end
end
@doc """
Repeats the time string and raises an exception in case of errors
"""
@spec repeating!(String.t(), [term]) :: Enumerable.t
def repeating!(timestring, opts \\ []) do
case repeating(timestring, opts) do
{:ok, enumerable} -> enumerable
{:error, msg} -> raise msg
end
end
@doc """
Generates a single datetime for the string given.
## Options
`from` The datetime from when the sequence will be generated, defaults to the current time.
## Example
HumanTime.relative("Next wednesday at 1530")
#=> {:ok, #DateTime<2018-08-15 15:30:00.848218Z>}
"""
@spec relative(String.t(), [term]) :: {:ok, DateTime.t} | {:error, String.t}
def relative(timestring, opts \\ []) do
from = opts[:from] || Timex.now()
Relative.Parser.parse(timestring, from)
end
@doc """
Creates the time string and raises an exception in case of errors
"""
@spec relative!(String.t(), [term]) :: DateTime.t
def relative!(timestring, opts \\ []) do
case relative(timestring, opts) do
{:ok, the_datetime} -> the_datetime
{:error, msg} -> raise msg
end
end
end