Timex.Interval (timex v3.7.5) View Source

This module is used for creating and manipulating date/time intervals.

Examples

iex> use Timex
...> Interval.new(from: ~D[2016-03-03], until: [days: 3])
%Elixir.Timex.Interval{from: ~N[2016-03-03 00:00:00], left_open: false, right_open: true, step: [days: 1], until: ~N[2016-03-06 00:00:00]}

iex> use Timex
...> Interval.new(from: ~D[2016-03-03], until: ~N[2016-03-10 01:23:45])
%Timex.Interval{from: ~N[2016-03-03 00:00:00], left_open: false, right_open: true, step: [days: 1], until: ~N[2016-03-10 01:23:45]}

iex> use Timex
...> ~N[2016-03-04 12:34:56] in Interval.new(from: ~D[2016-03-03], until: [days: 3])
true

iex> use Timex
...> ~D[2016-03-01] in Interval.new(from: ~D[2016-03-03], until: [days: 3])
false

iex> use Timex
...> Interval.overlaps?(Interval.new(from: ~D[2016-03-01], until: [days: 5]),  Interval.new(from: ~D[2016-03-03], until: [days: 3]))
true

iex> use Timex
...> Interval.overlaps?(Interval.new(from: ~D[2016-03-01], until: [days: 1]),  Interval.new(from: ~D[2016-03-03], until: [days: 3]))
false

Link to this section Summary

Functions

Returns true if the first interval includes every point in time the second includes.

Removes one interval from another which may reduce, split, or eliminate the original interval. Returns a (possibly empty) list of intervals representing the remaining time.

Return the interval duration, given a unit.

Formats the interval as a human readable string.

Create a new Interval struct.

Returns true if the first interval shares any point(s) in time with the second.

Change the step value for the provided interval.

Link to this section Types

Specs

t() :: %Timex.Interval{
  from: term(),
  left_open: term(),
  right_open: term(),
  step: term(),
  until: term()
}

Specs

valid_interval_step() :: {valid_step_unit(), integer()}
Link to this type

valid_interval_steps()

View Source

Specs

valid_interval_steps() :: [valid_interval_step()]

Specs

valid_step_unit() ::
  :microseconds
  | :milliseconds
  | :seconds
  | :minutes
  | :hours
  | :days
  | :weeks
  | :months
  | :years

Link to this section Functions

Specs

contains?(t(), t()) :: boolean()

Returns true if the first interval includes every point in time the second includes.

Examples

iex> Elixir.Timex.Interval.contains?(Elixir.Timex.Interval.new(from: ~D[2018-01-01], until: ~D[2018-01-31]), Elixir.Timex.Interval.new(from: ~D[2018-01-01], until: ~D[2018-01-30]))
true

iex> Elixir.Timex.Interval.contains?(Elixir.Timex.Interval.new(from: ~D[2018-01-01], until: ~D[2018-01-30]), Elixir.Timex.Interval.new(from: ~D[2018-01-01], until: ~D[2018-01-31]))
false

iex> Elixir.Timex.Interval.contains?(Elixir.Timex.Interval.new(from: ~D[2018-01-01], until: ~D[2018-01-10]), Elixir.Timex.Interval.new(from: ~D[2018-01-05], until: ~D[2018-01-15]))
false
Link to this function

difference(original, removal)

View Source

Specs

difference(t(), t()) :: [t()]

Removes one interval from another which may reduce, split, or eliminate the original interval. Returns a (possibly empty) list of intervals representing the remaining time.

Graphs

The following textual graphs show all the ways that the original interval and the removal can relate to each other, and the action that difference/2 will take in each case. The original interval is drawn with Os and the removal interval with Xs.

# return original
OO
    XX

# trim end
OOO
  XXX

# trim end
OOOOO
  XXX

# split
OOOOOOO
  XXX

# eliminate
OO
XX

# eliminate
OO
XXXX

# trim beginning
OOOO
XX

# eliminate
  OO
XXXXXX

# eliminate
    OO
XXXXXX

# trim beginning
  OOO
XXX

# return original
     OO
XX

Examples

iex> Elixir.Timex.Interval.difference(Elixir.Timex.Interval.new(from: ~N[2018-01-01 02:00:00.000], until: ~N[2018-01-01 04:00:00.000]), Elixir.Timex.Interval.new(from: ~N[2018-01-01 03:00:00.000], until: ~N[2018-01-01 05:00:00.000]))
[%Elixir.Timex.Interval{from: ~N[2018-01-01 02:00:00.000], left_open: false, right_open: true, step: [days: 1], until: ~N[2018-01-01 03:00:00.000]}]

iex> Elixir.Timex.Interval.difference(Elixir.Timex.Interval.new(from: ~N[2018-01-01 01:00:00.000], until: ~N[2018-01-01 05:00:00.000]), Elixir.Timex.Interval.new(from: ~N[2018-01-01 02:00:00.000], until: ~N[2018-01-01 03:00:00.000]))
[%Elixir.Timex.Interval{from: ~N[2018-01-01 01:00:00.000], left_open: false, right_open: true, step: [days: 1], until: ~N[2018-01-01 02:00:00.000]}, %Elixir.Timex.Interval{from: ~N[2018-01-01 03:00:00.000], left_open: false, right_open: true, step: [days: 1], until: ~N[2018-01-01 05:00:00.000]}]

iex> Elixir.Timex.Interval.difference(Elixir.Timex.Interval.new(from: ~N[2018-01-01 02:00:00.000], until: ~N[2018-01-01 04:00:00.000]), Elixir.Timex.Interval.new(from: ~N[2018-01-01 01:00:00.000], until: ~N[2018-01-01 05:00:00.000]))
[]
Link to this function

duration(interval, unit)

View Source

Return the interval duration, given a unit.

When the unit is one of :seconds, :minutes, :hours, :days, :weeks, :months, :years, the result is an integer.

When the unit is :duration, the result is a Duration struct.

Example

iex> use Timex
...> Interval.new(from: ~D[2014-09-22], until: [months: 5])
...> |> Interval.duration(:months)
5

iex> use Timex
...> Interval.new(from: ~N[2014-09-22T15:30:00], until: [minutes: 20])
...> |> Interval.duration(:duration)
Duration.from_minutes(20)
Link to this function

format(interval, format, formatter \\ nil)

View Source

Formats the interval as a human readable string.

Examples

iex> use Timex
...> Interval.new(from: ~D[2014-09-22], until: [days: 3])
...> |> Interval.format!("%Y-%m-%d %H:%M", :strftime)
"[2014-09-22 00:00, 2014-09-25 00:00)"

iex> use Timex
...> Interval.new(from: ~D[2014-09-22], until: [days: 3])
...> |> Interval.format!("%Y-%m-%d", :strftime)
"[2014-09-22, 2014-09-25)"
Link to this function

format!(interval, format, formatter \\ nil)

View Source

Same as format/3, but raises a Timex.Interval.FormatError on failure.

Specs

new(Keyword.t()) :: t() | {:error, :invalid_until} | {:error, :invalid_step}

Create a new Interval struct.

Note: By default intervals are left closed, i.e. they include the from date/time, and exclude the until date/time. Put another way, from <= x < until. This behavior matches that of other popular date/time libraries, such as Joda Time, as well as the SQL behavior of the overlaps keyword.

Options:

  • from: The date the interval starts at. Should be a (Naive)DateTime.
  • until: Either a (Naive)DateTime, or a time shift that will be applied to the from date. This value must be greater than from, otherwise an error will be returned.
  • left_open: Whether the interval is left open. See explanation below.
  • right_open: Whether the interval is right open. See explanation below.
  • step: The step to use when iterating the interval, defaults to [days: 1]

The terms left_open and right_open come from the mathematical concept of intervals. You can see more detail on the theory on Wikipedia, but it can be more intuitively thought of like so:

  • An "open" bound is exclusive, and a "closed" bound is inclusive
  • So a left-closed interval includes the from value, and a left-open interval does not.
  • Likewise, a right-closed interval includes the until value, and a right-open interval does not.
  • An open interval is both left and right open, conversely, a closed interval is both left and right closed.

Note: until shifts delegate to Timex.shift, so the options provided should match its valid options.

Examples

iex> use Timex
...> Interval.new(from: ~D[2014-09-22], until: ~D[2014-09-29])
...> |> Interval.format!("%Y-%m-%d", :strftime)
"[2014-09-22, 2014-09-29)"

iex> use Timex
...> Interval.new(from: ~D[2014-09-22], until: [days: 7])
...> |> Interval.format!("%Y-%m-%d", :strftime)
"[2014-09-22, 2014-09-29)"

iex> use Timex
...> Interval.new(from: ~D[2014-09-22], until: [days: 7], left_open: true, right_open: false)
...> |> Interval.format!("%Y-%m-%d", :strftime)
"(2014-09-22, 2014-09-29]"

iex> use Timex
...> Interval.new(from: ~N[2014-09-22T15:30:00], until: [minutes: 20], right_open: false)
...> |> Interval.format!("%H:%M", :strftime)
"[15:30, 15:50]"

Specs

overlaps?(t(), t()) :: boolean()

Returns true if the first interval shares any point(s) in time with the second.

Examples

iex> Elixir.Timex.Interval.overlaps?(Elixir.Timex.Interval.new(from: ~D[2016-03-04], until: [days: 1]), Elixir.Timex.Interval.new(from: ~D[2016-03-03], until: [days: 3]))
true

iex> Elixir.Timex.Interval.overlaps?(Elixir.Timex.Interval.new(from: ~D[2016-03-07], until: [days: 1]), Elixir.Timex.Interval.new(from: ~D[2016-03-03], until: [days: 3]))
false
Link to this function

with_step(interval, step)

View Source

Specs

with_step(t(), valid_interval_steps()) :: t() | {:error, :invalid_step}

Change the step value for the provided interval.

The step should be a keyword list valid for use with Timex.Date.shift.

Examples

iex> use Timex
...> Interval.new(from: ~D[2014-09-22], until: [days: 3], right_open: true)
...> |> Interval.with_step([days: 1]) |> Enum.map(&Timex.format!(&1, "%Y-%m-%d", :strftime))
["2014-09-22", "2014-09-23", "2014-09-24"]

iex> use Timex
...> Interval.new(from: ~D[2014-09-22], until: [days: 3], right_open: false)
...> |> Interval.with_step([days: 1]) |> Enum.map(&Timex.format!(&1, "%Y-%m-%d", :strftime))
["2014-09-22", "2014-09-23", "2014-09-24", "2014-09-25"]

iex> use Timex
...> Interval.new(from: ~D[2014-09-22], until: [days: 3], right_open: false)
...> |> Interval.with_step([days: 2]) |> Enum.map(&Timex.format!(&1, "%Y-%m-%d", :strftime))
["2014-09-22", "2014-09-24"]

iex> use Timex
...> Interval.new(from: ~D[2014-09-22], until: [days: 3], right_open: false)
...> |> Interval.with_step([days: 3]) |> Enum.map(&Timex.format!(&1, "%Y-%m-%d", :strftime))
["2014-09-22", "2014-09-25"]