View Source Tempus.Slots.Stream (Tempus v0.15.0)

The default Stream implementation of Tempus.Slots ordered collection.

Examples

iex> import Tempus.Slots.Stream, only: [slots: 0]
iex> slots = [
...>   Tempus.Slot.wrap(~D|2020-08-07|),
...>   Tempus.Slot.wrap(~D|2020-08-10|),
...>   %Tempus.Slot{
...>       from: ~U|2020-08-07 01:00:00Z|, to: ~U|2020-08-08 01:00:00Z|}]
...> slots |> Enum.into(slots()) |> Enum.to_list()
[%Tempus.Slot{from: ~U[2020-08-07 00:00:00.000000Z], to: ~U[2020-08-08 01:00:00Z]},
 %Tempus.Slot{from: ~U[2020-08-10 00:00:00.000000Z], to: ~U[2020-08-10 23:59:59.999999Z]}]
iex> Enum.map(slots, & &1.from)
[~U[2020-08-07 00:00:00.000000Z], ~U[2020-08-10 00:00:00.000000Z], ~U[2020-08-07 01:00:00Z]]

Summary

Functions

Adds another slot to the slots collection backed by stream.

Inverses Slots returning the new Slots instance with slots set where there were blanks.

Produces a stream of slots wrapped in Tempus.Slots.Stream, ensuring the order of elements emitted.

Merges other into this slots instance. other might be Enum or Stream. When other is a stream, it gets terminated immediately after the last element in this.

Creates the new instance of Tempus.Slots.Stream struct. One usually does not need to call this function directly.

Produces a stream or recurrent weekly slots, given starting and ending {dow, time, zone} triples.

Splits the slots by the pivot given as a Slot.t or as a function.

Types

Functions

Link to this function

add(slots, slot, options \\ [])

View Source
@spec add(t(), Tempus.Slot.t(), keyword()) :: t()

Adds another slot to the slots collection backed by stream.

Joins slots intersecting with the new one, if any.

Example

iex> import Tempus.Slots.Stream, only: [slots: 0]
iex> Tempus.Slots.Stream.add(slots(), Tempus.Slot.wrap(~D|2020-08-07|)) |> Enum.to_list()
[%Tempus.Slot{from: ~U[2020-08-07 00:00:00.000000Z], to: ~U[2020-08-07 23:59:59.999999Z]}]

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

inverse(slots, options \\ [])

View Source

Inverses Slots returning the new Slots instance with slots set where there were blanks.

Example

iex> [
...>   Tempus.Slot.wrap(~D|2020-08-07|),
...>   Tempus.Slot.wrap(~D|2020-08-08|),
...>   Tempus.Slot.wrap(~D|2020-08-10|),
...>   Tempus.Slot.wrap(~D|2020-08-12|)
...> ] |> Enum.into(%Tempus.Slots.List{})
...> |> Tempus.Slots.List.inverse()
%Tempus.Slots.List{slots: [
  %Tempus.Slot{from: nil, to: ~U[2020-08-06 23:59:59.999999Z]},
  %Tempus.Slot{from: ~U[2020-08-09 00:00:00.000000Z], to: ~U[2020-08-09 23:59:59.999999Z]},
  %Tempus.Slot{from: ~U[2020-08-11 00:00:00.000000Z], to: ~U[2020-08-11 23:59:59.999999Z]},
  %Tempus.Slot{from: ~U[2020-08-13 00:00:00.000000Z], to: nil}]}

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

iterate(start_value, next_fun, options \\ [])

View Source
@spec iterate(
  Tempus.Slot.origin(),
  (Tempus.Slot.t() -> Tempus.Slot.t()),
  join: nil | boolean() | pos_integer(),
  return_as: :slots | :stream
) :: t() | Tempus.Slots.t(Tempus.Slots.Stream)

Produces a stream of slots wrapped in Tempus.Slots.Stream, ensuring the order of elements emitted.

Options

  • join (default: false) — nil | boolean() | non_neg_integer() specifies how slots are to be joined

  • return_as (default: :stream) — :stream | :slots if slots, the function returns the Tempus.Slots.t/0 instance backed up by produced t:Temput.Slots.Stream.t/0

By default, slots will not be joined. Pass true to join if they are 1μsec aside, or an integer specifying the number of μsecs to join.

Examples

iex> import Tempus.Sigils
...> Tempus.Slots.Stream.iterate(~D|2024-01-20|,
...>   &Tempus.Slot.shift(&1, by: rem(&1.from.day, 2) + 1, unit: :day),
...>   join: true) |> Enum.take(2)
[~I(2024-01-20T00:00:00.000000Z → 2024-01-21T23:59:59.999999Z),
 ~I(2024-01-23T00:00:00.000000Z → 2024-01-23T23:59:59.999999Z)]
Link to this function

merge(slots, other, options \\ [])

View Source
@spec merge(t(), Tempus.Slots.container(), keyword()) :: t()

Merges other into this slots instance. other might be Enum or Stream. When other is a stream, it gets terminated immediately after the last element in this.

Examples

iex> import Tempus.Slots.Stream, only: [slots: 0]
iex> slots = [
...>   Tempus.Slot.wrap(~D|2020-08-07|),
...>   Tempus.Slot.wrap(~D|2020-08-10|)
...> ] |> Enum.into(slots())
iex> other = [
...>   %Tempus.Slot{from: ~U|2020-08-07 23:00:00Z|, to: ~U|2020-08-08 12:00:00Z|},
...>   %Tempus.Slot{from: ~U|2020-08-12 23:00:00Z|, to: ~U|2020-08-12 23:30:00Z|}
...> ] |> Enum.into(slots())
iex> slots |> Tempus.Slots.Stream.merge(other) |> Enum.to_list()
[%Tempus.Slot{from: ~U[2020-08-07 00:00:00.000000Z], to: ~U[2020-08-08 12:00:00Z]},
 %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 23:00:00Z], to: ~U[2020-08-12 23:30:00Z]}]

Creates the new instance of Tempus.Slots.Stream struct. One usually does not need to call this function directly.

Link to this function

recurrent(origin \\ nil, arg1, arg2)

View Source
@spec recurrent(
  origin :: nil | Date.t(),
  from :: recurrent_time,
  to :: recurrent_time
) ::
  Tempus.Slots.t(Tempus.Slots.Stream)
  | {:error,
     :incompatible_calendars
     | :invalid_format
     | :invalid_input
     | :invalid_time
     | :time_zone_not_found
     | :utc_only_time_zone_database}
  | {:ambiguous, DateTime.t(), DateTime.t()}
  | {:gap, DateTime.t(), DateTime.t()}
when recurrent_time: {Calendar.day_of_week(), Time.t(), Calendar.time_zone()}

Produces a stream or recurrent weekly slots, given starting and ending {dow, time, zone} triples.

### Examples

 iex> import Tempus.Sigils
 ...> Tempus.Slots.Stream.recurrent(Date.from_iso8601!("2024-01-22"), {7, "15:00:00", "Etc/UTC"}, {3, "01:00:00", "Etc/UTC"}) |> Enum.take(3)
 [~I(2024-01-21T15:00:00.000000Z → 2024-01-24T01:00:00.000000Z),
  ~I(2024-01-28T15:00:00.000000Z → 2024-01-31T01:00:00.000000Z),
  ~I(2024-02-04T15:00:00.000000Z → 2024-02-07T01:00:00.000000Z)]
 ...> Tempus.Slots.Stream.recurrent(Date.from_iso8601!("2024-01-22"), {1, "15:00:00", "Etc/UTC"}, {3, "01:00:00", "Etc/UTC"}) |> Enum.take(3)
 [~I(2024-01-22T15:00:00.000000Z → 2024-01-24T01:00:00.000000Z),
  ~I(2024-01-29T15:00:00.000000Z → 2024-01-31T01:00:00.000000Z),
  ~I(2024-02-05T15:00:00.000000Z → 2024-02-07T01:00:00.000000Z)]
 ...> Tempus.Slots.Stream.recurrent(Date.from_iso8601!("2024-01-22"), {1, "15:00:00", "Etc/UTC"}, {1, "15:00:00", "Australia/Sydney"}) |> Enum.take(3)
 [~I(2024-01-15T15:00:00.000000Z → 2024-01-22T15:00:00.000000+11:00),
  ~I(2024-01-22T15:00:00.000000Z → 2024-01-29T15:00:00.000000+11:00),
  ~I(2024-01-29T15:00:00.000000Z → 2024-02-05T15:00:00.000000+11:00)]
 ...> Tempus.Slots.Stream.recurrent(Date.from_iso8601!("2024-01-22"), {1, "09:00:00", "Australia/Sydney"}, {7, "23:00:00", "Etc/UTC"}) |> Enum.take(3)
 [%Tempus.Slot{from: DateTime.new!(~D"2024-01-29", ~T"09:00:00.000000", "Australia/Sydney"), to: ~U|2024-01-28T23:00:00.000000Z|},
  %Tempus.Slot{from: DateTime.new!(~D"2024-02-05", ~T"09:00:00.000000", "Australia/Sydney"), to: ~U|2024-02-04T23:00:00.000000Z|},
  %Tempus.Slot{from: DateTime.new!(~D"2024-02-12", ~T"09:00:00.000000", "Australia/Sydney"), to: ~U|2024-02-11T23:00:00.000000Z|}]
 ...> Tempus.Slots.Stream.recurrent(Date.from_iso8601!("2024-03-28"), {1, "09:00:00", "Australia/Sydney"}, {7, "23:00:00", "Etc/UTC"}) |> Enum.take(2)
 [%Tempus.Slot{from: DateTime.new!(~D"2024-04-01", ~T"09:00:00.000000", "Australia/Sydney"), to: ~U|2024-03-31T23:00:00.000000Z|},
  %Tempus.Slot{from: DateTime.new!(~D"2024-04-08", ~T"09:00:00.000000", "Australia/Sydney"), to: ~U|2024-04-07T23:00:00.000000Z|}]
Link to this function

split(slots, pivot, options \\ [])

View Source

Splits the slots by the pivot given as a Slot.t or as a function.

To keep it consistent, the function actually does split it until, which is intuitive when the pivot is given and kinda counter-intuitive when the locator function is given.

See the examples below to grasp the reasoning behind this architectural decision.

Examples

iex> import Tempus.Guards
...> import Tempus.Sigils
iex> slots =
...> [~D|2020-08-07|, ~D|2020-08-08|, ~D|2020-08-10|, ~D|2020-08-12|]
...> |> Enum.into(%Tempus.Slots.Stream{})
iex> slots |> Tempus.Slots.Stream.split(~U|2020-08-09T12:00:00Z|) |> Tuple.to_list() |> Enum.map(&Enum.to_list/1)
[
  [~I(2020-08-07T00:00:00.000000Z → 2020-08-07T23:59:59.999999Z), ~I(2020-08-08T00:00:00.000000Z → 2020-08-08T23:59:59.999999Z)],
  [~I(2020-08-10T00:00:00.000000Z → 2020-08-10T23:59:59.999999Z), ~I(2020-08-12T00:00:00.000000Z → 2020-08-12T23:59:59.999999Z)]
]
iex> slots
...> |> Tempus.Slots.Stream.split(&is_slot_coming_before(Tempus.Slot.wrap(~U|2020-08-09T12:00:00Z|), &1))
...> |> Tuple.to_list()
...> |> Enum.map(&Enum.to_list/1)
[
  [~I(2020-08-07T00:00:00.000000Z → 2020-08-07T23:59:59.999999Z), ~I(2020-08-08T00:00:00.000000Z → 2020-08-08T23:59:59.999999Z)],
  [~I(2020-08-10T00:00:00.000000Z → 2020-08-10T23:59:59.999999Z), ~I(2020-08-12T00:00:00.000000Z → 2020-08-12T23:59:59.999999Z)]
]