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.
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 | :slots
if slots, the function returns theTempus.Slots.t/0
instance 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)]
]