View Source Tempus (Tempus v0.10.0)

Tempus is a library to deal with timeslots.

It aims to be a fast yet easy to use implementation of a schedule of any type, including but not limited to free/busy time schedules.

The example of it might be a calendar software, where slots might be marked as free, or busy. It also allows simple arithmetics with schedules, like adding five days or subtracting 7 hours 30 minutes from now, considering busy slots.

Link to this section Summary

Types

Number of slots (:stream means lazy folding, unknown upfront)

Direction for slots navigation

Navigation option

Argument containing navigation options

The type defining how slicing is to be applied. When :greedy, overlapping boundary slots would be included, :reluctant would take only those fully contained in the interval.

Functions

Adds an amount of units to the origin, considering slots given.

Returns the reversed list of free days after origin.

Returns the reversed list of free days after origin.

Returns the reversed list of free days after origin.

Drops slots at the beginning of the %Slots{} struct while fun returns a truthy value.

Checks whether the slot is disjoined against slots.

Helper to instantiate slot from any known format, by wrapping the argument.

Helper to instantiate slot from any known format, by joining the arguments.

Returns the next busy slot from the slots passed as a first argument, that immediately follows origin. If slots are overlapped, the overlapped one gets returned.

Returns the next free slot from the slots passed as a first argument, that immediately follows origin. If slots are overlapped, the overlapped one gets returned.

Slices the %Slots{} based on origins from and to and an optional type (default: :reluctant.) Returns sliced %Slots{} back.

Syntactic sugar for |> Enum.into(%Slots{}).

Takes slots at the beginning of the %Slots{} struct while fun returns a truthy value.

Link to this section Types

@type count() :: :infinity | :stream | non_neg_integer()

Number of slots (:stream means lazy folding, unknown upfront)

@type direction() :: :fwd | :bwd

Direction for slots navigation

@type option() ::
  {:origin, Tempus.Slot.origin()}
  | {:count, count() | neg_integer()}
  | {:direction, direction()}

Navigation option

@type options() :: [option()]

Argument containing navigation options

@type slice_type() :: :greedy | :reluctant

The type defining how slicing is to be applied. When :greedy, overlapping boundary slots would be included, :reluctant would take only those fully contained in the interval.

Link to this section Functions

Link to this function

add(slots, origin \\ DateTime.utc_now(), amount_to_add, unit \\ :second)

View Source
@spec add(
  slots :: Tempus.Slots.t(),
  origin :: DateTime.t(),
  amount_to_add :: integer(),
  unit :: System.time_unit()
) :: DateTime.t()

Adds an amount of units to the origin, considering slots given.

examples

Examples

iex> slots = [
...>   ~D|2020-08-07|,
...>   ~D|2020-08-10|,
...>   ~D|2020-08-11|,
...>   ~D|2020-08-14|
...> ] |> Enum.into(%Tempus.Slots{})
iex> Tempus.add(slots, ~U|2020-08-11 23:00:00Z|, -10*60+1, :second)
~U[2020-08-09 23:50:00Z]
iex> Tempus.add(slots, ~U|2020-08-12 00:09:00Z|, -10*60, :second)
~U[2020-08-09 23:59:00Z]
iex> Tempus.add(slots, ~U|2020-08-12 00:10:00Z|, -10*60, :second)
~U[2020-08-12 00:00:00Z]
iex> Tempus.add(slots, ~U|2020-08-12 00:10:00Z|, -10*60-1, :second)
~U[2020-08-09 23:59:59Z]
iex> Tempus.add(slots, ~U|2020-08-11 23:00:00Z|, 10*60, :second)
~U[2020-08-12 00:10:00Z]
iex> Tempus.add(slots, ~U|2020-08-12 00:00:00Z|, 10*60, :second)
~U[2020-08-12 00:10:00Z]
iex> Tempus.add(slots, ~U|2020-08-09 23:55:00Z|, 10*60, :second)
~U[2020-08-12 00:05:00Z]
iex> Tempus.add(slots, ~U|2020-08-08 23:55:00Z|, 10*60, :second)
~U[2020-08-09 00:05:00Z]
iex> Tempus.add(slots, ~U|2020-08-06 23:55:00Z|, 2*3600*24 + 10*60, :second)
~U[2020-08-12 00:05:00Z]
Link to this function

days_add(slots, opts \\ [])

View Source (since 0.2.0)
@spec days_add(slots :: Tempus.Slots.t(), opts :: options()) :: [Date.t()]

Returns the reversed list of free days after origin.

examples

Examples

iex> slots = [
...>   Tempus.Slot.wrap(~D|2020-08-07|),
...>   Tempus.Slot.wrap(~D|2020-08-10|)
...> ] |> Enum.into(%Tempus.Slots{})
iex> Tempus.days_add(slots, origin: ~D|2020-08-07|, count: 3) |> hd()
~D|2020-08-12|
iex> Tempus.days_add(slots, origin: ~D|2020-08-07|, count: 3, direction: :fwd) |> hd()
~D|2020-08-12|
iex> Tempus.days_add(slots, origin: ~D|2020-08-07|, count: -3, direction: :bwd) |> hd()
~D|2020-08-12|
iex> Tempus.days_add(slots, origin: ~D|2020-08-12|, count: -4) |> hd()
~D|2020-08-06|
iex> Tempus.days_add(slots, origin: ~D|2020-08-12|, count: 4, direction: :bwd) |> hd()
~D|2020-08-06|
iex> Tempus.days_add(slots, origin: ~D|2020-08-12|, count: -4, direction: :fwd) |> hd()
~D|2020-08-06|
Link to this function

days_ago(slots, origin, count)

View Source
This function is deprecated. Use days_add/2 with negative count or `:bwd` forth parameter instead.
@spec days_ago(slots :: Tempus.Slots.t(), origin :: Date.t(), count :: integer()) :: [
  Date.t()
]

Returns the reversed list of free days after origin.

examples

Examples

iex> slots = [
...>   Tempus.Slot.wrap(~D|2020-08-07|),
...>   Tempus.Slot.wrap(~D|2020-08-10|)
...> ] |> Enum.into(%Tempus.Slots{})
iex> Tempus.days_ago(slots, ~D|2020-08-07|, 0)
[~D|2020-08-06|]
iex> Tempus.days_ago(slots, ~D|2020-08-12|, 4) |> hd()
~D|2020-08-06|
Link to this function

days_ahead(slots, origin, count)

View Source
This function is deprecated. Use days_add/2 instead.
@spec days_ahead(slots :: Tempus.Slots.t(), origin :: Date.t(), count :: integer()) ::
  [Date.t()]

Returns the reversed list of free days after origin.

examples

Examples

iex> slots = [
...>   Tempus.Slot.wrap(~D|2020-08-07|),
...>   Tempus.Slot.wrap(~D|2020-08-10|)
...> ] |> Enum.into(%Tempus.Slots{})
iex> Tempus.days_ahead(slots, ~D|2020-08-07|, 0)
[~D|2020-08-08|]
iex> Tempus.days_ahead(slots, ~D|2020-08-07|, 3) |> hd()
~D|2020-08-12|
Link to this function

drop_while(slots, fun)

View Source (since 0.7.0)
@spec drop_while(slots :: Tempus.Slots.t(), fun :: (Tempus.Slot.t() -> boolean())) ::
  Tempus.Slots.t()

Drops slots at the beginning of the %Slots{} struct while fun returns a truthy value.

@spec free?(slots :: Tempus.Slots.t(), slot :: Tempus.Slot.origin()) :: boolean()

Checks whether the slot is disjoined against slots.

examples

Examples

iex> slots = [
...>   Tempus.Slot.wrap(~D|2020-08-07|),
...>   Tempus.Slot.wrap(~D|2020-08-10|)
...> ] |> Enum.into(%Tempus.Slots{})
iex> Tempus.free?(slots, ~D|2020-08-07|)
false
iex> Tempus.free?(slots, ~D|2020-08-08|)
true
iex> Tempus.free?(slots, ~U|2020-08-09T23:59:59.999999Z|)
true
iex> Tempus.free?(slots, DateTime.add(~U|2020-08-09T23:59:59.999999Z|, 1, :microsecond))
false
@spec guess(input :: nil | binary()) :: {:ok, Tempus.Slot.t()} | {:error, any()}

Helper to instantiate slot from any known format, by wrapping the argument.

examples

Examples

iex> Tempus.guess("2023-04-10")
{:ok, Tempus.Slot.wrap(~D[2023-04-10])}
iex> Tempus.guess("2023-04-10T10:00:00Z")
{:ok, Tempus.Slot.wrap(~U[2023-04-10T10:00:00Z])}
iex> Tempus.guess("20230410T235007.123+0230")
if Version.compare(System.version(), "1.14.0") == :lt do
  {:error, :invalid_format}
else
  {:ok, Tempus.Slot.wrap(~U[2023-04-10T21:20:07.123Z])}
end
iex> Tempus.guess("2023-04-10-15")
{:error, :invalid_format}
@spec guess(from :: nil | binary(), to :: nil | binary()) ::
  {:ok, Tempus.Slot.t()} | {:error, any()}

Helper to instantiate slot from any known format, by joining the arguments.

examples

Examples

iex> import Tempus.Sigils
iex> Tempus.guess("2023-04-10", "2023-04-12")
{:ok, ~I[2023-04-10 00:00:00.000000Z|2023-04-12 23:59:59.999999Z]}
iex> Tempus.guess("2023-04-10T10:00:00Z", "2023-04-12")
{:ok, ~I[2023-04-10 10:00:00Z|2023-04-12 23:59:59.999999Z]}
iex> Tempus.guess("20230410T235007.123+0230", "2023-04-12")
if Version.compare(System.version(), "1.14.0") == :lt do
  {:error, {:invalid_arguments, [from: :invalid_format]}}
else
  {:ok, ~I[2023-04-10 21:20:07.123Z|2023-04-12 23:59:59.999999Z]}
end
iex> Tempus.guess("2023-04-10-15", :ok)
{:error, {:invalid_arguments, [from: :invalid_format, to: :invalid_argument]}}
Link to this function

next_busy(slots, opts \\ [])

View Source
This function is deprecated. Use `slice/3` instead.
@spec next_busy(Tempus.Slots.t(), options()) ::
  [Tempus.Slot.t()] | Tempus.Slot.t() | nil | no_return()

Returns the next busy slot from the slots passed as a first argument, that immediately follows origin. If slots are overlapped, the overlapped one gets returned.

examples

Examples

iex> slots = [
...>   Tempus.Slot.wrap(~D|2020-08-07|),
...>   Tempus.Slot.wrap(~D|2020-08-10|)
...> ] |> Enum.into(%Tempus.Slots{})
iex> Tempus.next_busy(slots, origin: %Tempus.Slot{from: ~U|2020-08-08 23:00:00Z|, to: ~U|2020-08-09 12:00:00Z|})
%Tempus.Slot{from: ~U[2020-08-10 00:00:00.000000Z], to: ~U[2020-08-10 23:59:59.999999Z]}
iex> Tempus.next_busy(slots, origin: %Tempus.Slot{from: ~U|2020-08-07 11:00:00Z|, to: ~U|2020-08-07 12:00:00Z|}, count: 2) |> hd()
%Tempus.Slot{from: ~U[2020-08-07 00:00:00.000000Z], to: ~U[2020-08-07 23:59:59.999999Z]}
iex> Tempus.next_busy(slots, origin: %Tempus.Slot{from: ~U|2020-08-07 11:00:00Z|, to: ~U|2020-08-08 12:00:00Z|})
%Tempus.Slot{from: ~U[2020-08-07 00:00:00.000000Z], to: ~U[2020-08-07 23:59:59.999999Z]}
iex> Tempus.next_busy(slots, origin: %Tempus.Slot{from: ~U|2020-08-07 11:00:00Z|, to: ~U|2020-08-10 12:00:00Z|})
%Tempus.Slot{from: ~U[2020-08-07 00:00:00.000000Z], to: ~U[2020-08-07 23:59:59.999999Z]}
iex> Tempus.next_busy(slots, origin: ~D|2020-08-07|)
%Tempus.Slot{from: ~U[2020-08-07 00:00:00.000000Z], to: ~U[2020-08-07 23:59:59.999999Z]}
iex> Tempus.next_busy(slots, origin: ~D|2020-08-08|)
%Tempus.Slot{from: ~U[2020-08-10 00:00:00.000000Z], to: ~U[2020-08-10 23:59:59.999999Z]}
iex> Tempus.next_busy(slots, origin: ~D|2020-08-08|, direction: :bwd)
%Tempus.Slot{from: ~U[2020-08-07 00:00:00.000000Z], to: ~U[2020-08-07 23:59:59.999999Z]}
iex> Tempus.next_busy(slots, origin: ~D|2020-08-10|, direction: :bwd)
%Tempus.Slot{from: ~U[2020-08-10 00:00:00.000000Z], to: ~U[2020-08-10 23:59:59.999999Z]}
iex> Tempus.next_busy(slots, origin: %Tempus.Slot{from: ~U|2020-08-11 11:00:00Z|, to: ~U|2020-08-11 12:00:00Z|})
nil
iex> Tempus.next_busy(slots, origin: %Tempus.Slot{from: ~U|2020-08-06 11:00:00Z|, to: ~U|2020-08-06 12:00:00Z|}, direction: :bwd)
nil
iex> Tempus.next_busy(%Tempus.Slots{})
nil
Link to this function

next_free(slots, opts \\ [])

View Source
This function is deprecated. Use `slice/3` instead.
@spec next_free(Tempus.Slots.t(), options()) ::
  [Tempus.Slot.t()] | Tempus.Slot.t() | no_return()

Returns the next free slot from the slots passed as a first argument, that immediately follows origin. If slots are overlapped, the overlapped one gets returned.

examples

Examples

iex> import Tempus.Sigils
iex> slots = [
...>   Tempus.Slot.wrap(~D|2020-08-07|),
...>   Tempus.Slot.wrap(~D|2020-08-10|),
...>   Tempus.Slot.wrap(~D|2020-08-12|),
...>   Tempus.Slot.wrap(~D|2020-08-14|)
...> ] |> Enum.into(%Tempus.Slots{})
iex> Tempus.next_free(slots, origin: %Tempus.Slot{from: ~U|2020-08-08 23:00:00Z|, to: ~U|2020-08-09 12:00:00Z|})
~I[2020-08-08 00:00:00.000000Z → 2020-08-09 23:59:59.999999Z]
iex> Tempus.next_free(slots, origin: %Tempus.Slot{from: ~U|2020-08-06 11:00:00Z|, to: ~U|2020-08-06 12:00:00Z|})
~I[∞ → 2020-08-06 23:59:59.999999Z]nu
iex> Tempus.next_free(slots, origin: ~U|2020-08-13 01:00:00.000000Z|)
~I[2020-08-13 00:00:00.000000Z → 2020-08-13 23:59:59.999999Z]
iex> Tempus.next_free(slots, origin: ~D|2020-08-13|)
~I[2020-08-13 00:00:00.000000Z → 2020-08-13 23:59:59.999999Z]
iex> Tempus.next_free(slots, origin: ~D|2020-08-14|)
~I[2020-08-15 00:00:00.000000Z → ∞]un
Link to this function

slice(slots, from, to, type \\ :reluctant)

View Source (since 0.7.0)
@spec slice(
  slots :: Tempus.Slots.t(),
  from :: Tempus.Slots.locator(),
  to :: Tempus.Slots.locator(),
  type :: slice_type()
) :: Tempus.Slots.t()

Slices the %Slots{} based on origins from and to and an optional type (default: :reluctant.) Returns sliced %Slots{} back.

See Tempus.Slot.new/2.

See Tempus.Slot.new!/2.

Syntactic sugar for |> Enum.into(%Slots{}).

examples

Examples

iex> [
...>   Tempus.Slot.wrap(~D|2020-08-07|),
...>   Tempus.Slot.wrap(~D|2020-08-10|),
...>   Tempus.Slot.wrap(~D|2020-08-12|)
...> ] |> Tempus.slots()
%Tempus.Slots{slots: %Tempus.Slots.List{slots: [
    %Tempus.Slot{from: ~U[2020-08-07 00:00:00.000000Z], to: ~U[2020-08-07 23:59:59.999999Z]},
    %Tempus.Slot{from: ~U[2020-08-10 00:00:00.000000Z], to: ~U[2020-08-10 23:59:59.999999Z]},
    %Tempus.Slot{from: ~U[2020-08-12 00:00:00.000000Z], to: ~U[2020-08-12 23:59:59.999999Z]}]}}
Link to this function

take_while(slots, fun)

View Source (since 0.7.0)
@spec take_while(slots :: Tempus.Slots.t(), fun :: (Tempus.Slot.t() -> boolean())) ::
  Tempus.Slots.t()

Takes slots at the beginning of the %Slots{} struct while fun returns a truthy value.