README.md

# Timex Interval

[![hex.pm version](https://img.shields.io/hexpm/v/timex_interval.svg)](https://hex.pm/packages/timex_interval) [![travis.ci build status](http://img.shields.io/travis/atabary/timex-interval/master.svg)](https://travis-ci.org/atabary/timex-interval)

Timex Interval is an extension of [Timex](https://github.com/bitwalker/timex) that deals with date/time intervals.

Intervals are enumerable, making them useful to iterate over time intervals, for instance every day between two dates.


## Constructors

The `DateTimeInterval` module provides a helper function to make new intervals.

Valid keywords:

  - `from`: the date the interval starts at (defaults to `Date.now()`)
  - `until`: either the date the interval ends at, or a time shift that will be applied to the "from" date (defaults to `[days: 7]`)
  - `left_open`: whether the interval is left open, defaults to #{@default_left_open}
  - `right_open`: whether the interval is right open, defaults to #{@default_right_open}
  - `step`: the iteration step for enumerations, defaults to `[days: 1]`

Time shifts should be keyword lists valid for use with `Timex.Date.shift`.

```elixir
use Timex
alias TimexInterval.DateTimeInterval, as: Interval

Interval.new(from: Date.from({2014, 9, 22}), until: Date.from({2014, 9, 29}))
|> Interval.format!("%Y-%m-%d")
#=> "[2014-09-22, 2014-09-29)"

Interval.new(from: Date.from({2014, 9, 22}), until: [months: 5])
|> Interval.format!("%Y-%m-%d")
#=> "[2014-09-22, 2015-02-22)"

Interval.new(from: Date.from({{2014, 9, 22}, {15, 30, 0}}), until: [mins: 20], right_open: false)
|> Interval.format!("%H:%M")
#=> "[15:30, 15:50]"

```

Note that by default intervals are right open.


## Iterators

`DateTimeInterval` implements the `Enumerable` protocol.

```elixir
use Timex
alias TimexInterval.DateTimeInterval, as: Interval

Interval.new(from: Date.from({2014, 9, 22}), until: [days: 3])
|> Enum.map(fn(dt) -> DateFormat.format!(dt, "%Y-%m-%d", :strftime) end)
#=> ["2014-09-22", "2014-09-23", "2014-09-24"]
```

You can easily specify whether to exclude the first and last dates:

```elixir
Interval.new(from: Date.from({2014, 9, 22}), until: [days: 3], right_open: false)
|> Enum.map(fn(dt) -> DateFormat.format!(dt, "%Y-%m-%d", :strftime) end)
#=> ["2014-09-22", "2014-09-23", "2014-09-24", "2014-09-25"]
```

You can of course iterate over anything else, for instance by chunks of 10 minutes:

```elixir
Interval.new(from: Date.from({{2014, 9, 22}, {15, 0, 0}}), until: [hours: 1])
|> Interval.with_step(mins: 10)
|> Enum.map(fn(dt) -> DateFormat.format!(dt, "%H:%M", :strftime) end)
#=> ["15:00", "15:10", "15:20", "15:30", "15:40", "15:50"]
```

## Duration

You can query an interval to know its duration, given a time unit.

When the unit is one of `:secs`, `:mins`, `:hours`, `:days`, `:weeks`, `:months`, `:years`, the result is an `integer`.

When the unit is `:timestamp`, the result is a tuple representing a valid `Timex.Time`.

```elixir
use Timex
alias TimexInterval.DateTimeInterval, as: Interval

Interval.new(from: Date.from({2014, 9, 22}), until: [months: 5])
|> Interval.duration(:months)
#=> 5

Interval.new(from: Date.from({{2014, 9, 22}, {15, 30, 0}}), until: [mins: 20])
|> Interval.duration(:timestamp)
#=> {0, 0, 1200}
```