View Source Tempus.Slots.Stream (Tempus v0.16.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.
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
@type t() :: Tempus.Slots.implementation(Tempus.Slots.Stream)
Functions
@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]}]
  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]}
]}
  @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 joinedreturn_as(default::stream) —:stream | :slotsif slots, the function returns theTempus.Slots.t/0instance backed up by producedt: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)]
  @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.
@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|}]
  @spec split(t(), Tempus.Slots.locator(), keyword()) :: {Enumerable.t(Tempus.Slot.t()), Enumerable.t(Tempus.Slot.t())}
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)]
]