# `Timex`
[🔗](https://github.com/bitwalker/timex/blob/4.0.0/lib/timex.ex#L1)

## Timex

[![Main](https://github.com/bitwalker/timex/workflows/elixir/badge.svg?branch=main)](https://github.com/bitwalker/timex/actions?query=workflow%3A%22elixir%22+branch%3Amain)
[![Hex.pm Version](https://img.shields.io/hexpm/v/timex.svg?style=flat)](https://hex.pm/packages/timex)
[![Coverage Status](https://coveralls.io/repos/github/bitwalker/timex/badge.svg?branch=main)](https://coveralls.io/github/bitwalker/timex?branch=main)

Timex is a rich, comprehensive Date/Time library for Elixir projects, with full timezone support via the `:tzdata` package. If
you need to manipulate dates, times, datetimes, timestamps, etc., then Timex is for you! It is very easy to use Timex types
in place of default Erlang types, as well as Ecto types via the `timex_ecto` package.

The complete documentation for Timex is located [here](https://hexdocs.pm/timex).

## Requirements

Timex requires Elixir 1.16 or later and Erlang/OTP 26 or later.

Timezone updates use tzdata's built-in HTTP client, which verifies HTTPS against
the operating system's trusted CA certificates. Ensure your deployment includes
an accessible CA certificate bundle. Timex no longer requires Hackney or its
dependencies.

When upgrading, remove an explicit `config :tzdata, :http_client,
Tzdata.HTTPClient.Hackney` setting to use the built-in client. If your application
still needs Hackney independently, update it to a patched version and audit the
whole application's dependency graph with `mix hex.audit`. Updating Timex does not
upgrade unrelated application dependencies automatically.

## Supported calendars and years

Timex's date arithmetic and conversion entrypoints accept `Date`,
`NaiveDateTime`, and `DateTime` inputs in `Calendar.ISO`, with years from 0
through 9999. Date tuples and maps use the same year range. Unsupported inputs
return `{:error, {:unsupported_calendar, calendar}}` or
`{:error, {:unsupported_year, year}}`; `is_valid?/1` returns `false`, and
boolean comparison helpers such as `equal?/2` raise `ArgumentError`.
Comparisons also require the UTC instant to fall within that year range.
ISO week-year metadata may refer to the preceding year: for example,
`Timex.iso_week(~D[0000-01-01])` returns `{-1, 52}`.

For another calendar, explicitly convert with `Date.convert/2`,
`NaiveDateTime.convert/2`, or `DateTime.convert/2` and `Calendar.ISO` before
calling Timex. These conversions preserve the represented date or instant
instead of reinterpreting another calendar's fields as ISO values.

Setters retain their normalization policy: negative replacement years clamp
to zero, while years above 9999 return an unsupported-year error. Using
`validate: false` permits raw replacement fields outside this range; subsequent
Timex operations still require supported inputs. Composite date/time setter
options must use `Calendar.ISO` even when validation is disabled.

These checks apply to Timex's protocol-backed arithmetic and conversions.
Standard-library constructor delegates such as `from_unix/2`, ordinary formatters,
and lower-level timezone APIs retain their own contracts. Built-in protocol
implementations assume supported inputs; direct protocol callers must enforce
those preconditions.

## Migrating to Timex 4.x

- Upgrade to Elixir 1.16 / OTP 26 or later and update dependencies. Check the
  certificate and HTTP-client requirements above, then audit your application's
  complete dependency graph.
- Public `Timex.compare/2`, `diff/2`, and `to_datetime/1` retain their defaults.
  Direct protocol calls must supply the granularity or timezone explicitly.
- Handle `AmbiguousDateTime` with `type: :gap` when converting nonexistent naive
  wall times through IANA or explicit POSIX zones. Its `before` and `after` values
  bound the gap; overlaps use `type: :ambiguous`. Neither selects a time for you.
- Setters now validate the final result and refresh timezone metadata. Changing
  January 31 to February clamps the day. Use `validate: false` only when raw,
  potentially invalid fields are intended. Date-only tuple setters retain their
  date-only shape.
- Relative Date targets compare calendar days against the reference's UTC date.
  Datetime targets retain elapsed-time thresholds; use an explicit reference for
  deterministic output at those thresholds.
- Built-in date arithmetic requires the ISO calendar and supported years described
  above. Parsing requires complete input, including literal whitespace in the format.
- Parsed `PosixTimezone` transition bounds are signed seconds from midnight.
  Existing custom structs with `Time` bounds remain accepted. Explicit POSIX
  conversions now expose gap/overlap results, and `is_dst?/2` is true only for a
  unique daylight interpretation.

## Migrating to Timex 3.x

If you are coming from an earlier version of Timex, it is recommended that you evaluate whether or not the functionality provided
by the standard library `Calendar` API is sufficient for your needs, as you may be able to avoid the dependency entirely.

For those that require Timex for one reason or another, Timex delegates to the standard library where possible, within the supported
runtime versions listed above. This avoids duplicating effort and eases the maintenance of
this library in the future. Take a look at the documentation to see what APIs are available and how to use them. Many of them may have
changed, been removed/renamed, or have had their semantics improved since early versions of the library, so if you are coming from
an earlier version, you will need to review how you are using various APIs. The CHANGELOG is a helpful document to sort through what
has changed in general.

Timex is primarily oriented around the Olson timezone database, and so you are encouraged to use those timezones in favor of alternatives. 
Timex does provide compatibility with the POSIX-TZ standard, which allows specification of custom timezones, see 
[this document](https://pubs.opengroup.org/onlinepubs/9699919799/) for more information. Timex does not provide support
for timezones which do not adhere to one of those two standards. While Timex attempted to support timezone abbreviations without context
in prior versions, this was broken, and has been removed.

## Getting Started

There are some brief examples on usage below, but I highly recommend you review the
API docs [here](https://hexdocs.pm/timex), there are many examples, and some extra pages with
richer documentation on specific subjects such as custom formatters/parsers, etc.

### Quickfast introduction

To use Timex, I recommend you add `use Timex` to the top of the module where you will be working with Timex modules,
all it does is alias common types so you can work with them more comfortably. If you want to see the specific aliases
added, check the top of the `Timex` module, in the `__using__/1` macro definition.

Here's a few simple examples:

```elixir
> use Timex
> Timex.today()
~D[2016-02-29]

> datetime = Timex.now()
#<DateTime(2016-02-29T12:30:30.120+00:00Z Etc/UTC)

> Timex.now("America/Chicago")
#<DateTime(2016-02-29T06:30:30.120-06:00 America/Chicago)

> Duration.now()
#<Duration(P46Y6M24DT21H57M33.977711S)>

> {:ok, default_str} = Timex.format(datetime, "{ISO:Extended}")
{:ok, "2016-02-29T12:30:30.120+00:00"}

> {:ok, relative_str} = Timex.shift(datetime, minutes: -3) |> Timex.format("{relative}", :relative)
{:ok, "3 minutes ago"}

> strftime_str = Timex.format!(datetime, "%FT%T%:z", :strftime)
"2016-02-29T12:30:30+00:00"

> Timex.parse(strftime_str, "{ISO:Extended}")
{:ok, #<DateTime(2016-02-29T12:30:30.120+00:00 Etc/Utc)}

> Timex.parse!(strftime_str, "%FT%T%:z", :strftime)
#<DateTime(2016-02-29T12:30:30.120+00:00 Etc/Utc)

> Duration.diff(Duration.now(), Duration.zero(), :days)
16850

> Timex.shift(date, days: 3)
~D[2016-03-03]

> Timex.shift(datetime, hours: 2, minutes: 13)
#<DateTime(2016-02-29T14:43:30.120Z Etc/UTC)>

> timezone = Timezone.get("America/Chicago", Timex.now())
#<TimezoneInfo(America/Chicago - CDT (-06:00:00))>

> Timezone.convert(datetime, timezone)
#<DateTime(2016-02-29T06:30:30.120-06:00 America/Chicago)>

> Timex.before?(Timex.today(), Timex.shift(Timex.today, days: 1))
true

> Timex.before?(Timex.shift(Timex.today(), days: 1), Timex.today())
false

> interval = Timex.Interval.new(from: ~D[2016-03-03], until: [days: 3])
%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]}

> ~D[2016-03-04] in interval
true

> ~N[2016-03-04 00:00:00] in interval
true

> ~N[2016-03-02 00:00:00] in interval
false

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

> Timex.Interval.overlaps?(Timex.Interval.new(from: ~D[2016-03-07], until: [days: 1]), interval)
false

```

There are a ton of other functions, all of which work with Erlang datetime tuples, Date, NaiveDateTime, and DateTime. 
The Duration module contains functions for working with Durations, including Erlang timestamps (such as those returned from `:timer.tc`)

## Extensibility

Timex exposes a number of extension points for you, in order to accommodate different use cases:

Timex itself defines its core operations on the Date, DateTime, and NaiveDateTime types using the `Timex.Protocol` protocol. 
From there, all other Timex functionality is derived. If you have custom date/datetime types you want to use with Timex, 
this is the protocol you would need to implement.

Timex also defines a `Timex.Comparable` protocol, which you can extend to add comparisons to custom date/datetime types.

You can provide your own formatter/parser for datetime strings by implementing the `Timex.Format.DateTime.Formatter` 
and/or `Timex.Parse.DateTime.Parser` behaviours, depending on your needs.

### Timex with escript

Timex 4 requires tzdata 1.2.2 or later, including in escript deployments.
Tzdata loads timezone data from files in its `priv` directory, so those files
must be accessible at runtime. The historical tzdata 0.1.8 override is unsupported.

### Automatic time zone updates

Timex includes the [Tzdata](https://github.com/lau/tzdata) library for time zone data.
Tzdata has an automatic update capability that fetches updates from IANA and which is enabled by default; 
if you want to disable it, check [the Tzdata documentation](https://github.com/lau/tzdata#automatic-data-updates) for details.

## License

This software is licensed under [the MIT license](https://github.com/bitwalker/timex/blob/main/LICENSE.md).

# `between_options`

```elixir
@type between_options() :: [inclusive: boolean() | :start | :end, cycled: boolean()]
```

# `set_options`

```elixir
@type set_options() :: [
  validate: boolean(),
  datetime: Timex.Types.datetime(),
  date: Timex.Types.valid_date(),
  time: Timex.Types.valid_time(),
  year: Timex.Types.year(),
  month: Timex.Types.month(),
  day: Timex.Types.day(),
  hour: Timex.Types.hour(),
  minute: Timex.Types.minute(),
  second: Timex.Types.second(),
  microsecond: Timex.Types.microsecond(),
  timezone: Timex.Types.valid_timezone()
]
```

# `shift_options`

```elixir
@type shift_options() :: [
  microseconds: integer(),
  milliseconds: integer(),
  seconds: integer(),
  minutes: integer(),
  hours: integer(),
  days: integer(),
  weeks: integer(),
  months: integer(),
  years: integer(),
  duration: Timex.Duration.t()
]
```

# `add`

```elixir
@spec add(Timex.Types.valid_datetime(), Timex.Duration.t()) ::
  Timex.Types.valid_datetime() | Timex.AmbiguousDateTime.t() | {:error, term()}
```

Add time to a date using a Duration
Same as `shift(date, Duration.from_minutes(5), :duration)`.

# `after?`

```elixir
@spec after?(
  Time.t() | Timex.Comparable.comparable(),
  Time.t() | Timex.Comparable.comparable()
) ::
  boolean()
```

Returns a boolean indicating whether the first `Timex.Comparable` occurs after the second

# `before?`

```elixir
@spec before?(
  Time.t() | Timex.Comparable.comparable(),
  Time.t() | Timex.Comparable.comparable()
) ::
  boolean()
```

Returns a boolean indicating whether the first `Timex.Comparable` occurs before the second

# `beginning_of_day`

```elixir
@spec beginning_of_day(Timex.Types.valid_datetime()) ::
  Timex.Types.valid_datetime() | {:error, term()}
```

Returns a DateTime representing the beginning of the day

## Examples

    iex> date = Timex.to_datetime({{2015, 1, 1}, {13, 14, 15}}, "Etc/UTC")
    iex> Timex.beginning_of_day(date)
    Timex.to_datetime({{2015, 1, 1}, {0, 0, 0}}, "Etc/UTC")

    iex> date = ~D[2015-01-01]
    ...> Timex.beginning_of_day(date)
    ~D[2015-01-01]

# `beginning_of_month`

```elixir
@spec beginning_of_month(Timex.Types.valid_datetime()) ::
  Timex.Types.valid_datetime() | {:error, term()}
```

Given a date returns a date at the beginning of the month.

    iex> date = Timex.to_datetime({{2015, 6, 15}, {12,30,0}}, "Europe/Paris")
    iex> Timex.beginning_of_month(date)
    Timex.to_datetime({{2015, 6, 1}, {0, 0, 0}}, "Europe/Paris")

# `beginning_of_month`

```elixir
@spec beginning_of_month(Timex.Types.year(), Timex.Types.month()) ::
  Date.t() | {:error, term()}
```

Same as beginning_of_month/1, except takes year and month as distinct arguments

# `beginning_of_quarter`

```elixir
@spec beginning_of_quarter(Timex.Types.valid_datetime()) ::
  Timex.Types.valid_datetime() | {:error, term()}
```

Given a date returns a date at the beginning of the quarter.

    iex> date = Timex.to_datetime({{2015, 6, 15}, {12,30,0}}, "America/Chicago")
    iex> Timex.beginning_of_quarter(date)
    Timex.to_datetime({{2015, 4, 1}, {0, 0, 0}}, "America/Chicago")

# `beginning_of_week`

```elixir
@spec beginning_of_week(Timex.Types.valid_datetime(), Timex.Types.weekstart()) ::
  Timex.Types.valid_datetime() | {:error, term()}
```

Shifts the date to the beginning of the week

The weekstart can between 1..7, an atom e.g. :mon, or a string e.g. "Monday"

## Examples

    iex> date = ~N[2015-11-30T13:30:30] # Monday 30th November
    iex> Timex.beginning_of_week(date)
    ~N[2015-11-30T00:00:00]

    iex> date = ~D[2015-11-30] # Monday 30th November
    iex> Timex.beginning_of_week(date, :sun)
    ~D[2015-11-29]

# `beginning_of_year`

```elixir
@spec beginning_of_year(Timex.Types.year() | Timex.Types.valid_datetime()) ::
  Timex.Types.valid_datetime() | {:error, term()}
```

Given a date or a number create a date at the beginning of that year

Examples

    iex> date = ~N[2015-06-15T00:00:00]
    iex> Timex.beginning_of_year(date)
    ~N[2015-01-01T00:00:00]

    iex> Timex.beginning_of_year(2015)
    ~D[2015-01-01]

# `between?`

```elixir
@spec between?(
  Time.t() | Timex.Comparable.comparable(),
  Time.t() | Timex.Comparable.comparable(),
  Time.t() | Timex.Comparable.comparable(),
  between_options()
) :: boolean()
```

Returns a boolean indicating whether the first `Timex.Comparable` occurs between the second
and third.

If an error occurs, an error tuple will be returned.

By default, the `start` and `end` bounds are *exclusive*. You can opt for inclusive bounds with the
`inclusive: true` option.
To set just one of the bounds as inclusive, use the
`inclusive: :start` or `inclusive: :end` option.

Also, by default, for `Time.t`, if `start` and `end`
are on different sides of midnight,
it doesn't count as a continous period. Hence, `23:00 < 00:00, 01:00` would return `false`.
To use cycled time, use option `cycled: true`.

# `century`

```elixir
@spec century() :: non_neg_integer() | {:error, term()}
```

Gets the current century

## Examples

    iex> Timex.century
    21

# `century`

```elixir
@spec century(Timex.Types.year() | Timex.Types.valid_datetime()) ::
  non_neg_integer() | {:error, term()}
```

Given a date, get the century this date is in.

## Examples

    iex> Timex.today |> Timex.century
    21
    iex> Timex.now |> Timex.century
    21
    iex> Timex.century(2016)
    21

# `compare`

```elixir
@spec compare(
  Time.t() | Timex.Comparable.comparable(),
  Time.t() | Timex.Comparable.comparable()
) ::
  Timex.Comparable.compare_result()
```

See docs for `compare/3`

# `compare`

```elixir
@spec compare(
  Time.t() | Timex.Comparable.comparable(),
  Time.t() | Timex.Comparable.comparable(),
  Timex.Comparable.granularity()
) :: Timex.Comparable.compare_result()
```

Compare two `Timex.Comparable` values, returning one of the following values:

 * `-1` -- the first date comes before the second one
 * `0`  -- both arguments represent the same date when coalesced to the same timezone.
 * `1`  -- the first date comes after the second one

You can provide a few reference constants for the second argument:

- :epoch will compare the first parameter against the Date/DateTime of the first moment of the UNIX epoch
- :zero will compare the first parameter against the Date/DateTime of the first moment of year zero
- :distant_past will compare the first parameter against a date/time infinitely in the past (i.e. it will always return 1)
- :distant_future will compare the first parameter against a date/time infinitely in the future (i.e. it will always return -1)

You can optionally specify a comparison granularity from the list below.

- :year
- :years
- :month
- :months
- :week (an alias for 7 days)
- :weeks
- :calendar_week (weeks of the calendar as opposed to actual weeks in terms of days)
- :calendar_weeks
- :day (an alias for 24 hours)
- :days
- :hour
- :hours
- :minute
- :minutes
- :second
- :seconds
- :millisecond
- :milliseconds
- :microsecond (default)
- :microseconds
- :duration

## Examples

    iex> date1 = ~D[2014-03-04]
    iex> date2 = ~D[2015-03-04]
    iex> Timex.compare(date1, date2, :year)
    -1
    iex> Timex.compare(date2, date1, :year)
    1
    iex> Timex.compare(date1, date1)
    0

# `day`

```elixir
@spec day(Timex.Types.valid_datetime()) :: Timex.Types.daynum() | {:error, term()}
```

Returns the ordinal day number of the date.

## Examples

    iex> Timex.day(~D[2015-06-26])
    177

# `day_name`

```elixir
@spec day_name(Timex.Types.weekday()) ::
  String.t() | {:error, :invalid_weekday_number}
```

Get the name of the day corresponding to the provided number

## Examples

    iex> Timex.day_name(1)
    "Monday"
    iex> Timex.day_name(0)
    {:error, :invalid_weekday_number}

# `day_shortname`

```elixir
@spec day_shortname(Timex.Types.weekday()) ::
  String.t() | {:error, :invalid_weekday_number}
```

Get the short name of the day corresponding to the provided number

## Examples

    iex> Timex.day_shortname(1)
    "Mon"
    iex> Timex.day_shortname(0)
    {:error, :invalid_weekday_number}

# `day_to_num`

```elixir
@spec day_to_num(binary() | atom()) ::
  Timex.Types.weekday() | {:error, :invalid_day_name}
```

Get the day of the week corresponding to the given name.

The name can be given as a string of the weekday name or its first three characters
(lowercase or capitalized) or as a corresponding atom (lowercase only).

## Examples

    iex> Timex.day_to_num("Monday")
    1
    iex> Timex.day_to_num("monday")
    1
    iex> Timex.day_to_num("Mon")
    1
    iex> Timex.day_to_num("mon")
    1
    iex> Timex.day_to_num(:mon)
    1
    iex> Timex.day_to_num(:sunday)
    7

# `days_in_month`

```elixir
@spec days_in_month(Timex.Types.valid_datetime()) ::
  Timex.Types.num_of_days() | {:error, term()}
```

Return the number of days in the month which the date falls on.

## Examples

    iex> Timex.days_in_month(~D[1970-01-01])
    31

# `days_in_month`

```elixir
@spec days_in_month(Timex.Types.year(), Timex.Types.month()) ::
  Timex.Types.num_of_days() | {:error, term()}
```

Same as days_in_month/2, except takes year and month as distinct arguments

# `days_to_beginning_of_week`

```elixir
@spec days_to_beginning_of_week(Timex.Types.valid_datetime(), Timex.Types.weekstart()) ::
  integer() | {:error, term()}
```

Number of days to the beginning of the week

The weekstart determines which is the first day of the week, defaults to monday. It can be a number
between 1..7 (1 is monday, 7 is sunday), or any value accepted by `day_to_num/1`.

## Examples

    iex> date = ~D[2015-11-30] # Monday 30th November
    iex> Timex.days_to_beginning_of_week(date)
    0

    iex> date = ~D[2015-11-30] # Monday 30th November
    iex> Timex.days_to_beginning_of_week(date, :sun)
    1

# `days_to_end_of_week`

```elixir
@spec days_to_end_of_week(Timex.Types.valid_datetime(), Timex.Types.weekstart()) ::
  integer() | {:error, term()}
```

Number of days to the end of the week.

The weekstart can between 1..7, an atom e.g. :mon, or a string e.g. "Monday"

## Examples

    Week starting Monday
    iex> date = ~D[2015-11-30] # Monday 30th November
    iex> Timex.days_to_end_of_week(date)
    6

    Week starting Sunday
    iex> date = ~D[2015-11-30] # Monday 30th November
    iex> Timex.days_to_end_of_week(date, :sun)
    5

# `diff`

```elixir
@spec diff(
  Time.t() | Timex.Comparable.comparable(),
  Time.t() | Timex.Comparable.comparable()
) ::
  Timex.Duration.t() | integer() | {:error, term()}
```

See docs for `diff/3`

# `diff`

```elixir
@spec diff(
  Time.t() | Timex.Comparable.comparable(),
  Time.t() | Timex.Comparable.comparable(),
  Timex.Comparable.granularity()
) :: Timex.Duration.t() | integer() | {:error, term()}
```

Calculate time interval between two dates. The result will be a signed integer, negative
if the first date/time comes before the second, and positive if the first date/time comes
after the second.

You must specify one of the following units:

- :year
- :years
- :month
- :months
- :week
- :weeks
- :calendar_week (weeks of the calendar as opposed to actual weeks in terms of days)
- :calendar_weeks
- :day
- :days
- :hour
- :hours
- :minute
- :minutes
- :second
- :seconds
- :millisecond
- :milliseconds
- :microsecond (default)
- :microseconds
- :duration

and the result will be an integer value of those units or a Duration.

# `end_of_day`

```elixir
@spec end_of_day(Timex.Types.valid_datetime()) ::
  Timex.Types.valid_datetime() | {:error, term()}
```

Returns a DateTime representing the end of the day

## Examples

    iex> date = ~N[2015-01-01T13:14:15]
    ...> Timex.end_of_day(date)
    ~N[2015-01-01T23:59:59]

# `end_of_month`

```elixir
@spec end_of_month(Timex.Types.valid_datetime()) ::
  Timex.Types.valid_datetime() | {:error, term()}
```

Given a date returns a date at the end of the month.

    iex> date = ~N[2015-06-15T12:30:00Z]
    iex> Timex.end_of_month(date)
    ~N[2015-06-30T23:59:59Z]

# `end_of_month`

```elixir
@spec end_of_month(Timex.Types.year(), Timex.Types.month()) :: Date.t()
```

Same as end_of_month/1, except takes year and month as distinct arguments

## Examples

    iex> Timex.end_of_month(2016, 2)
    ~D[2016-02-29]

# `end_of_quarter`

```elixir
@spec end_of_quarter(Timex.Types.valid_datetime()) ::
  Timex.Types.valid_datetime() | {:error, term()}
```

Given a date or a year and month returns a date at the end of the quarter.

    iex> date = ~N[2015-06-15T12:30:00]
    ...> Timex.end_of_quarter(date)
    ~N[2015-06-30T23:59:59]

    iex> Timex.end_of_quarter(2015, 4)
    ~D[2015-06-30]

# `end_of_quarter`

```elixir
@spec end_of_quarter(Timex.Types.year(), Timex.Types.month()) ::
  Date.t() | {:error, term()}
```

Same as end_of_quarter/1, except takes year and month as distinct arguments

# `end_of_week`

```elixir
@spec end_of_week(Timex.Types.valid_datetime(), Timex.Types.weekstart()) ::
  Timex.Types.valid_datetime() | {:error, term()}
```

Returns a Date or a DateTime representing the end of the week, depending on the input,
i.e. if you pass a date/time value which represents just a date, you will get back a Date,
if both a date and time are present, you will get back a DateTime

The weekstart can between 1..7, an atom e.g. :mon, or a string e.g. "Monday"

## Examples

    iex> date = ~N[2015-11-30T13:30:30] # Monday 30th November
    ...> Timex.end_of_week(date)
    ~N[2015-12-06T23:59:59]

    iex> date = ~D[2015-11-30] # Monday 30th November
    ...> Timex.end_of_week(date, :sun)
    ~D[2015-12-05]

# `end_of_year`

```elixir
@spec end_of_year(Timex.Types.year() | Timex.Types.valid_datetime()) ::
  Timex.Types.valid_datetime() | {:error, term()}
```

Given a date or a number create a date at the end of that year

Examples

    iex> date = ~N[2015-06-15T00:00:00]
    iex> Timex.end_of_year(date)
    ~N[2015-12-31T23:59:59]

    iex> Timex.end_of_year(2015)
    ~D[2015-12-31]

# `epoch`

```elixir
@spec epoch() :: Date.t()
```

Returns a Date representing the start of the UNIX epoch

# `equal?`

```elixir
@spec equal?(
  Time.t() | Timex.Comparable.comparable(),
  Time.t() | Timex.Comparable.comparable(),
  Timex.Comparable.granularity()
) :: boolean() | no_return()
```

Returns a boolean indicating whether the two `Timex.Comparable` values are equivalent.

Equality here implies that the two Comparables represent the same moment in time (with
the given granularity), not equality of the data structure.

The options for granularity is the same as for `compare/3`, defaults to `:seconds`.

## Examples

    iex> date1 = ~D[2014-03-01]
    ...> date2 = ~D[2014-03-01]
    ...> Timex.equal?(date1, date2)
    true

    iex> date1 = ~D[2014-03-01]
    ...> date2 = Timex.to_datetime({2014, 3, 1}, "Etc/UTC")
    ...> Timex.equal?(date1, date2)
    true

# `format`

```elixir
@spec format(Timex.Types.valid_datetime(), format :: String.t()) ::
  {:ok, String.t()} | {:error, term()}
```

Formats a date/time value using the given format string (and optional formatter).

See `Timex.Format.DateTime.Formatters.Default` or `Timex.Format.DateTime.Formatters.Strftime`
for documentation on the syntax supported by those formatters.

To use the Default formatter, simply call `format/2`. To use the Strftime formatter, you
can either alias and pass Strftime by module name, or as a shortcut, you can pass :strftime
instead.

Formatting will convert other dates than Elixir date types (Date, DateTime, NaiveDateTime)
to a NaiveDateTime using `to_naive_datetime/1` before formatting.

## Examples

    iex> date = ~D[2016-02-29]
    ...> Timex.format(date, "{YYYY}-{0M}-{D}")
    {:ok, "2016-02-29"}

    iex> datetime = Timex.to_datetime({{2016,2,29},{22,25,0}}, "Etc/UTC")
    ...> Timex.format(datetime, "{ISO:Extended}")
    {:ok, "2016-02-29T22:25:00+00:00"}

# `format`

```elixir
@spec format(Timex.Types.valid_datetime(), format :: String.t(), formatter :: atom()) ::
  {:ok, String.t()} | {:error, term()}
```

Same as format/2, except using a custom formatter

## Examples

    iex> use Timex
    ...> datetime = Timex.to_datetime({{2016,2,29},{22,25,0}}, "America/Chicago")
    iex> Timex.format(datetime, "%FT%T%:z", :strftime)
    {:ok, "2016-02-29T22:25:00-06:00"}

# `format!`

```elixir
@spec format!(Timex.Types.valid_datetime(), format :: String.t()) ::
  String.t() | no_return()
```

Same as format/2, except it returns only the value (not a tuple) and raises on error.

## Examples

    iex> date = ~D[2016-02-29]
    ...> Timex.format!(date, "{YYYY}-{0M}-{D}")
    "2016-02-29"

# `format!`

```elixir
@spec format!(Timex.Types.valid_datetime(), format :: String.t(), formatter :: atom()) ::
  String.t() | no_return()
```

Same as format/3, except it returns only the value (not a tuple) and raises on error.

## Examples

    iex> use Timex
    ...> datetime = Timex.to_datetime({{2016,2,29},{22,25,0}}, "America/Chicago")
    iex> Timex.format!(datetime, "%FT%T%:z", :strftime)
    "2016-02-29T22:25:00-06:00"

# `format_duration`

```elixir
@spec format_duration(Timex.Duration.t()) :: String.t() | {:error, term()}
```

Formats an Erlang timestamp using the ISO-8601 duration format, or optionally, with a custom
formatter of your choosing.

See Timex.Format.Duration.Formatters.Default or Timex.Format.Duration.Formatters.Humanized
for documentation on the specific formatter behaviour.

To use the Default formatter, simply call format_duration/2.
To use the Humanized formatter, you can either alias and pass Humanized by module name,
or as a shortcut, you can pass :humanized instead.

## Examples

    iex> use Timex
    ...> duration = Duration.from_seconds(Timex.to_unix({2016, 2, 29}))
    ...> Timex.format_duration(duration)
    "P46Y2M10D"

    iex> use Timex
    ...> duration = Duration.from_seconds(Timex.to_unix({2016, 2, 29}))
    ...> Timex.format_duration(duration, :humanized)
    "46 years, 2 months, 1 week, 3 days"

    iex> use Timex
    ...> datetime = Duration.from_seconds(Timex.to_unix(~N[2016-02-29T22:25:00]))
    ...> Timex.format_duration(datetime, :humanized)
    "46 years, 2 months, 1 week, 3 days, 22 hours, 25 minutes"

# `format_duration`

```elixir
@spec format_duration(Timex.Duration.t(), atom()) :: String.t() | {:error, term()}
```

Same as format_duration/1, except it also accepts a formatter

# `from_iso_day`

```elixir
@spec from_iso_day(non_neg_integer()) :: Date.t() | {:error, term()}
```

Convert an iso ordinal day number to the day it represents in the current year.

 ## Examples

    iex> %Date{:year => year} = Timex.from_iso_day(180)
    ...> %Date{:year => todays_year} = Timex.today()
    ...> year == todays_year
    true

# `from_iso_day`

```elixir
@spec from_iso_day(
  non_neg_integer(),
  Timex.Types.year() | Timex.Types.valid_datetime()
) ::
  Timex.Types.valid_datetime() | {:error, term()}
```

Same as from_iso_day/1, except you can expect the following based on the second parameter:

- If an integer year is given, the result will be a Date struct
- For any date/time value, the result will be in the same format (i.e. Date -> Date)

In all cases, the resulting value will be the date representation of the provided ISO day in that year

## Examples

### Creating a Date from the given day

    iex> use Timex
    ...> expected = ~D[2015-06-29]
    ...> (expected === Timex.from_iso_day(180, 2015))
    true

### Creating a Date/DateTime from the given day

    iex> use Timex
    ...> expected = Timex.to_datetime({{2015, 6, 29}, {0,0,0}}, "Etc/UTC")
    ...> beginning = Timex.to_datetime({{2015,1,1}, {0,0,0}}, "Etc/UTC")
    ...> (expected === Timex.from_iso_day(180, beginning))
    true

### Shifting a Date/DateTime to the given day

    iex> use Timex
    ...> date = Timex.to_datetime({{2015,6,26}, {12,0,0}}, "Etc/UTC")
    ...> expected = Timex.to_datetime({{2015, 6, 29}, {12,0,0}}, "Etc/UTC")
    ...> (Timex.from_iso_day(180, date) === expected)
    true

# `from_iso_triplet`

```elixir
@spec from_iso_triplet(Timex.Types.iso_triplet()) :: Date.t() | {:error, term()}
```

Given an ISO triplet `{year, week number, weekday}`, convert it to a Date struct.

## Examples

    iex> expected = Timex.to_date({2014, 1, 28})
    iex> Timex.from_iso_triplet({2014, 5, 2}) === expected
    true

# `from_now`

```elixir
@spec from_now(Timex.Types.valid_datetime()) :: String.t() | {:error, term()}
```

Formats a date or datetime using a fuzzy relative duration, from now.

Date targets compare calendar days with today's UTC date. Datetime targets
compare elapsed time; see `Timex.Format.DateTime.Formatters.Relative`.

## Examples

    iex> use Timex
    ...> Timex.from_now(Timex.shift(DateTime.utc_now(), days: 2, hours: 1))
    "in 2 days"

    iex> use Timex
    ...> Timex.from_now(Timex.shift(DateTime.utc_now(), days: -2))
    "2 days ago"

# `from_now`

```elixir
@spec from_now(Timex.Types.valid_datetime(), String.t()) ::
  String.t() | {:error, term()}
@spec from_now(Timex.Types.valid_datetime(), Timex.Types.valid_datetime()) ::
  String.t() | {:error, term()}
```

Formats a DateTime using a fuzzy relative duration, translated using given locale

## Examples

    iex> use Timex
    ...> Timex.from_now(Timex.shift(DateTime.utc_now(), days: 2, hours: 1), "ru")
    "через 2 дня"

    iex> use Timex
    ...> Timex.from_now(Timex.shift(DateTime.utc_now(), days: -2), "ru")
    "2 дня назад"

# `from_now`

```elixir
@spec from_now(Timex.Types.valid_datetime(), Timex.Types.valid_datetime(), String.t()) ::
  String.t() | {:error, term()}
```

Formats a DateTime using a fuzzy relative duration, with a reference datetime other than now,
translated using the given locale

# `from_unix`

```elixir
@spec from_unix(
  secs :: integer(),
  :native
  | System.time_unit()
  | :seconds
  | :milliseconds
  | :microseconds
  | :nanoseconds
) :: DateTime.t() | no_return()
```

Delegates to `DateTime.from_unix!/2`. To recap the docs:

Converts the given Unix time to DateTime.

The integer can be given in different units according to `System.convert_time_unit/3`
and it will be converted to microseconds internally. Defaults to `:second`.

Unix times are always in UTC and therefore the DateTime will be returned in UTC.

# `is_leap?`

```elixir
@spec is_leap?(Timex.Types.valid_datetime() | Timex.Types.year()) ::
  boolean() | {:error, term()}
```

Return a boolean indicating whether the given year is a leap year. You may
pass a date or a year number.

## Examples

    iex> Timex.epoch() |> Timex.is_leap?
    false
    iex> Timex.is_leap?(2012)
    true

# `is_valid?`

```elixir
@spec is_valid?(Timex.Types.valid_datetime()) :: boolean()
```

Return a boolean indicating whether the given date is valid.

## Examples

    iex> use Timex
    ...> Timex.is_valid?(~N[0001-01-01T01:01:01])
    true

    iex> use Timex
    ...> %Date{year: 1, day: 1, month: 13} |> Timex.is_valid?
    false

# `is_valid_time?`

```elixir
@spec is_valid_time?(term()) :: boolean()
```

Returns a boolean indicating whether the provided term represents a valid time,
valid times are one of:

- `{hour, min, sec}`
- `{hour, min, sec, ms}`

# `is_valid_timezone?`

```elixir
@spec is_valid_timezone?(term()) :: boolean()
```

Returns a boolean indicating whether the provided term represents a valid timezone,
valid timezones are one of:

- TimezoneInfo struct
- A timezone name as a string
- `:utc` as a shortcut for the UTC timezone
- `:local` as a shortcut for the local timezone
- A number representing an offset from UTC

# `iso_triplet`

```elixir
@spec iso_triplet(Timex.Types.valid_datetime()) ::
  {Timex.Types.year(), Timex.Types.weeknum(), Timex.Types.weekday()}
  | {:error, term()}
```

Return a 3-tuple {year, week number, weekday} for the given Date/DateTime.

## Examples

    iex> Timex.iso_triplet(Timex.epoch)
    {1970, 1, 4}

# `iso_week`

```elixir
@spec iso_week(Timex.Types.valid_datetime()) ::
  {Timex.Types.year(), Timex.Types.weeknum()} | {:error, term()}
```

Return a pair {year, week number} (as defined by ISO 8601) that the given
Date/DateTime value falls on.

## Examples

    iex> Timex.iso_week({1970, 1, 1})
    {1970,1}

# `iso_week`

```elixir
@spec iso_week(Timex.Types.year(), Timex.Types.month(), Timex.Types.day()) ::
  {Timex.Types.year(), Timex.Types.weeknum()} | {:error, term()}
```

Same as iso_week/1, except this takes a year, month, and day as distinct arguments.

## Examples

    iex> Timex.iso_week(1970, 1, 1)
    {1970,1}

# `lformat`

```elixir
@spec lformat(
  Timex.Types.valid_datetime(),
  format :: String.t(),
  locale :: String.t()
) ::
  {:ok, String.t()} | {:error, term()}
```

Same as format/2, except takes a locale name to translate text to.

Translations only apply to units, relative time phrases, and only for the locales in the
list of supported locales in the Timex documentation.

# `lformat`

```elixir
@spec lformat(
  Timex.Types.valid_datetime(),
  format :: String.t(),
  locale :: String.t(),
  formatter :: atom()
) :: {:ok, String.t()} | {:error, term()}
```

Same as lformat/3, except takes a formatter as it's last argument.

Translations only apply to units, relative time phrases, and only for the locales in the
list of supported locales in the Timex documentation.

# `lformat!`

```elixir
@spec lformat!(
  Timex.Types.valid_datetime(),
  format :: String.t(),
  locale :: String.t()
) ::
  String.t() | no_return()
```

Same as lformat/3, except local_format! raises on error.

See lformat/3 docs for usage examples.

# `lformat!`

```elixir
@spec lformat!(
  Timex.Types.valid_datetime(),
  format :: String.t(),
  locale :: String.t(),
  formatter :: atom()
) :: String.t() | no_return()
```

Same as lformat/4, except local_format! raises on error.

See lformat/4 docs for usage examples

# `lformat_duration`

```elixir
@spec lformat_duration(Timex.Duration.t(), locale :: String.t()) ::
  String.t() | {:error, term()}
```

Same as format_duration/1, except takes a locale for use in translation

# `lformat_duration`

```elixir
@spec lformat_duration(Timex.Duration.t(), locale :: String.t(), atom()) ::
  String.t() | {:error, term()}
```

Same as lformat_duration/2, except takes a formatter as an argument

# `local`

```elixir
@spec local() :: DateTime.t() | {:error, term()}
```

Returns a DateTime representing the current moment in time in the local timezone.

## Example

    iex> %DateTime{time_zone: tz} = Timex.local();
    ...> tz != nil
    true

# `local`

```elixir
@spec local(Timex.Types.valid_datetime()) ::
  DateTime.t() | Timex.AmbiguousDateTime.t() | {:error, term()}
```

Returns a DateTime representing the given date/time in the local timezone.
A timezone-aware input preserves its instant; an input without a timezone is
interpreted as local wall time.

## Example

    iex> %DateTime{time_zone: tz} = Timex.local(DateTime.utc_now());
    ...> tz != nil
    true

# `month_name`

```elixir
@spec month_name(Timex.Types.month()) :: String.t() | {:error, :invalid_month_number}
```

Get the name of the month corresponding to the provided number

## Examples

    iex> Timex.month_name(1)
    "January"
    iex> Timex.month_name(0)
    {:error, :invalid_month_number}

# `month_shortname`

```elixir
@spec month_shortname(Timex.Types.month()) ::
  String.t() | {:error, :invalid_month_number}
```

Get the short name of the month corresponding to the provided number

## Examples

    iex> Timex.month_shortname(1)
    "Jan"
    iex> Timex.month_shortname(0)
    {:error, :invalid_month_number}

# `month_to_num`

```elixir
@spec month_to_num(binary()) :: integer() | {:error, :invalid_month_name}
```

Get the number of the month corresponding to the given name.

## Examples

    iex> Timex.month_to_num("January")
    1
    iex> Timex.month_to_num("january")
    1
    iex> Timex.month_to_num("Jan")
    1
    iex> Timex.month_to_num("jan")
    1
    iex> Timex.month_to_num(:jan)
    1

# `normalize`

```elixir
@spec normalize(:date, {integer(), integer(), integer()}) ::
  Timex.Types.date() | {:error, term()}
@spec normalize(
  :time,
  {integer(), integer(), integer()}
  | {integer(), integer(), integer(), integer()}
) ::
  Timex.Types.time()
@spec normalize(:day, {integer(), integer(), integer()}) ::
  non_neg_integer() | {:error, term()}
@spec normalize(
  :year
  | :month
  | :day
  | :hour
  | :minute
  | :second
  | :millisecond
  | :microsecond,
  integer()
) :: non_neg_integer() | {:error, term()}
```

Given a unit to normalize, and the value to normalize, produces a valid
value for that unit, clamped to whatever boundaries are defined for that unit.

## Example

    iex> Timex.normalize(:hour, 26)
    23

# `now`

```elixir
@spec now() :: DateTime.t()
```

Returns a DateTime representing the current moment in time in UTC

# `now`

```elixir
@spec now(Timex.Types.valid_timezone()) :: DateTime.t() | {:error, term()}
```

Returns a DateTime representing the current moment in time in the provided
timezone.

# `parse`

```elixir
@spec parse(String.t(), String.t()) ::
  {:ok, DateTime.t() | NaiveDateTime.t() | Timex.AmbiguousDateTime.t()}
  | {:error, term()}
```

Parses a datetime string into a DateTime struct, using the provided format string (and optional tokenizer).

See `Timex.Format.DateTime.Formatters.Default` or `Timex.Format.DateTime.Formatters.Strftime`
for documentation on the syntax supported in format strings by their respective tokenizers.

To use the Default tokenizer, simply call `parse/2`. To use the Strftime tokenizer, you
can either alias and pass Timex.Parse.DateTime.Tokenizer.Strftime by module name,
or as a shortcut, you can pass :strftime instead.

## Examples

    iex> use Timex
    ...> {:ok, result} = Timex.parse("2016-02-29", "{YYYY}-{0M}-{D}")
    ...> result
    ~N[2016-02-29T00:00:00]

    iex> use Timex
    ...> expected = Timex.to_datetime({{2016, 2, 29}, {22, 25, 0}}, "America/Chicago")
    ...> {:ok, result} = Timex.parse("2016-02-29T22:25:00-06:00", "{ISO:Extended}")
    ...> Timex.equal?(expected, result)
    true

    iex> use Timex
    ...> expected = Timex.to_datetime({{2016, 2, 29}, {22, 25, 0}}, "America/Chicago")
    ...> {:ok, result} = Timex.parse("2016-02-29T22:25:00-06:00", "%FT%T%:z", :strftime)
    ...> Timex.equal?(expected, result)
    true

# `parse`

```elixir
@spec parse(String.t(), String.t(), atom()) ::
  {:ok, DateTime.t() | NaiveDateTime.t() | Timex.AmbiguousDateTime.t()}
  | {:error, term()}
```

# `parse!`

```elixir
@spec parse!(String.t(), String.t()) ::
  DateTime.t() | NaiveDateTime.t() | Timex.AmbiguousDateTime.t() | no_return()
```

Same as parse/2 and parse/3, except parse! raises on error.

See parse/2 or parse/3 docs for usage examples.

# `parse!`

```elixir
@spec parse!(String.t(), String.t(), atom()) ::
  DateTime.t() | NaiveDateTime.t() | Timex.AmbiguousDateTime.t() | no_return()
```

# `quarter`

```elixir
@spec quarter(Timex.Types.month() | Timex.Types.valid_datetime()) ::
  1..4 | {:error, term()}
```

Returns what quarter of the year the given date/time falls in.

## Examples

    iex> Timex.quarter(4)
    2

# `set`

```elixir
@spec set(Timex.Types.valid_datetime(), set_options()) ::
  Timex.Types.valid_datetime() | Timex.AmbiguousDateTime.t() | {:error, term()}
```

Return a new date/time value with the specified fields replaced by new values.

By default, the final date/time is validated and its fields clamped to valid
values. The day is clamped against the final year and month, including when only
the year or month changes. For example, changing January 31 to February produces
February 28 (or 29 in a leap year).

Replacements are applied in order, including repeated keys and composite
`:date`, `:time`, and `:datetime` values. For example, `[datetime: dt, date: d]`
uses the date from `d`. Validation happens after the replacements, so
`[day: 31, month: 1]` can produce January 31 even when the input is in February.

For a `DateTime`, timezone metadata is resolved against the final wall date/time
in the selected timezone (or the original timezone if none is supplied). This
preserves the requested wall time rather than the original instant. A timezone
overlap or gap returns an `AmbiguousDateTime` with `type: :ambiguous` or `:gap`,
respectively; an unknown timezone returns `{:error, :time_zone_not_found}`.

Pass `validate: false` to keep raw field values, even if the result is invalid.
Existing timezone metadata is retained unless a timezone is explicitly supplied.
If `:validate` is repeated, its first value controls the entire operation.

The result preserves the input representation, including date-only Erlang
tuples and fractional-second tuples. Options which do not apply to the input
value (for example, `:hour` against a `Date` struct or date-only tuple) are ignored.

## Example

    iex> use Timex
    ...> expected = ~D[2015-02-28]
    ...> result = Timex.set(expected, [month: 2, day: 30])
    ...> result == expected
    true

    iex> use Timex
    ...> expected = ~N[2016-02-29T23:30:00]
    ...> result = Timex.set(expected, [hour: 30])
    ...> result === expected
    true

# `shift`

```elixir
@spec shift(Timex.Types.valid_datetime(), shift_options()) ::
  Timex.Types.valid_datetime() | Timex.AmbiguousDateTime.t() | {:error, term()}
```

A single function for adjusting the date using various units: duration,
microseconds, seconds, minutes, hours, days, weeks, months, years.

The result of applying the shift will be the same type as that of the input,
with the exception of shifting DateTimes, which may result in an AmbiguousDateTime
if the shift moves to an ambiguous time period for the zone of that DateTime.

Shifting by months will always return a date in the expected month. Because months
have different number of days, shifting to a month with fewer days may not be
the same day of the month as the original date.

If an error occurs, an error tuple will be returned.

## Examples

### Shifting across timezone changes

    iex> use Timex
    ...> datetime = Timex.to_datetime({{2016,3,13}, {1,0,0}}, "America/Chicago")
    ...> # 2-3 AM doesn't exist due to leap forward, shift accounts for this
    ...> %DateTime{hour: 3} = Timex.shift(datetime, hours: 1)
    ...> shifted = Timex.shift(datetime, hours: 1)
    ...> {datetime.zone_abbr, shifted.zone_abbr, shifted.hour}
    {"CST", "CDT", 3}

### Shifting and leap days

    iex> use Timex
    ...> date = ~D[2016-02-29]
    ...> Timex.shift(date, years: -1)
    ~D[2015-03-01]

### Shifting by months

    iex> date = ~D[2016-01-15]
    ...> Timex.shift(date, months: 1)
    ~D[2016-02-15]

    iex> date = ~D[2016-01-31]
    ...> Timex.shift(date, months: 1)
    ~D[2016-02-29]

    iex> date = ~D[2016-01-31]
    ...> Timex.shift(date, months: 2)
    ~D[2016-03-31]
    ...> Timex.shift(date, months: 1) |> Timex.shift(months: 1)
    ~D[2016-03-29]

# `subtract`

```elixir
@spec subtract(Timex.Types.valid_datetime(), Timex.Duration.t()) ::
  Timex.Types.valid_datetime() | Timex.AmbiguousDateTime.t() | {:error, term()}
```

Subtract time from a date using a Duration
Same as `shift(date, Duration.from_minutes(5) |> Duration.invert, :timestamp)`.

# `timezone`

```elixir
@spec timezone(
  Timex.Types.valid_timezone() | Timex.TimezoneInfo.t(),
  Timex.Types.valid_datetime()
) ::
  Timex.TimezoneInfo.t() | Timex.AmbiguousTimezoneInfo.t() | {:error, term()}
```

Get a TimezoneInfo object for the specified offset or name.

When offset or name is invalid, exception is raised.

If no DateTime value is given for the second parameter, the current date/time
will be used (in other words, it will return the current timezone info for the
given zone). If one is provided, the timezone info returned will be based on
the provided DateTime (or Erlang datetime tuple) value.

## Examples

    iex> date = Timex.to_datetime({2015, 4, 12})
    ...> tz = Timex.timezone(:utc, date)
    ...> tz.full_name
    "Etc/UTC"

    iex> tz = Timex.timezone("America/Chicago", {2015,4,12})
    ...> {tz.full_name, tz.abbreviation}
    {"America/Chicago", "CDT"}

    iex> tz = Timex.timezone(+2, {2015, 4, 12})
    ...> {tz.full_name, tz.abbreviation}
    {"Etc/UTC+2", "+02"}

# `timezones`

```elixir
@spec timezones() :: [String.t()]
```

Returns a list of all valid timezone names in the Olson database

# `to_date`

```elixir
@spec to_date(Timex.Types.valid_datetime()) :: Date.t() | {:error, term()}
```

Convert a date/time value to a Date struct.

# `to_datetime`

```elixir
@spec to_datetime(Timex.Types.valid_datetime()) :: DateTime.t() | {:error, term()}
```

Convert a date/time value and timezone name to a DateTime struct.

Naive datetime values, including datetime tuples and maps without a timezone,
are interpreted as wall time in the destination zone. If the wall time falls
in an IANA or explicit POSIX timezone gap, returns an `AmbiguousDateTime` with `type: :gap`.
Its `before` value is the last valid instant before the gap and `after` is
the first valid instant after it; neither represents the requested wall time.

If the wall time occurs twice, returns an `AmbiguousDateTime` with
`type: :ambiguous`, containing both valid interpretations in chronological
order. The caller chooses how to handle either result.

`DateTime` inputs preserve their instant. Date-only `%Date{}` inputs retain
their midnight policy: if midnight is skipped or repeated, the later result
is selected. Unknown timezones return `{:error, :time_zone_not_found}`.

If no timezone is provided, "Etc/UTC" will be used.

### Examples

    iex> Timex.to_datetime(~N[2022-01-01 12:00:00], "America/New_York")
    #DateTime<2022-01-01 12:00:00-05:00 EST America/New_York>

    # This time was skipped as daylight savings started and clocks moved forward
    iex> %AmbiguousDateTime{type: :gap} = gap = Timex.to_datetime(~N[2021-03-14 02:30:00], "America/New_York")
    iex> {DateTime.to_naive(gap.before), DateTime.to_naive(gap.after)}
    {~N[2021-03-14 01:59:59.999999], ~N[2021-03-14 03:00:00]}

    # This time occurred twice as daylight savings ended and clocks moved back
    iex> %AmbiguousDateTime{} = adt = Timex.to_datetime(~N[2021-11-07 01:30:00], "America/New_York")
    ...> match?(%DateTime{zone_abbr: "EDT"}, adt.before) && match?(%DateTime{zone_abbr: "EST"}, adt.after)
    true

    iex> Timex.to_datetime(~N[2022-01-01 12:00:00])
    ~U[2022-01-01 12:00:00Z]

# `to_datetime`

```elixir
@spec to_datetime(Timex.Types.valid_datetime(), Timex.Types.valid_timezone()) ::
  DateTime.t() | Timex.AmbiguousDateTime.t() | {:error, term()}
```

# `to_erl`

```elixir
@spec to_erl(Timex.Types.valid_datetime()) ::
  Timex.Types.date() | Timex.Types.datetime() | {:error, term()}
```

Convert a date/time value to it's Erlang representation

# `to_gregorian_microseconds`

```elixir
@spec to_gregorian_microseconds(Timex.Types.valid_datetime()) ::
  non_neg_integer() | {:error, term()}
```

Convert a date/time value to gregorian microseconds (microseconds since start of year zero)

# `to_gregorian_seconds`

```elixir
@spec to_gregorian_seconds(Timex.Types.valid_datetime()) ::
  non_neg_integer() | {:error, term()}
```

Convert a date/time value to gregorian seconds (seconds since start of year zero)

# `to_julian`

```elixir
@spec to_julian(Timex.Types.valid_datetime()) :: integer() | {:error, term()}
```

Convert a date/time value to a Julian calendar date number

# `to_naive_datetime`

```elixir
@spec to_naive_datetime(Timex.Types.valid_datetime()) ::
  NaiveDateTime.t() | {:error, term()}
```

Convert a date/time value to a NaiveDateTime struct.

# `to_unix`

```elixir
@spec to_unix(Timex.Types.valid_datetime()) :: non_neg_integer() | {:error, term()}
```

Convert a date/time value to seconds since the UNIX epoch

# `today`

```elixir
@spec today() :: Date.t()
```

Returns a Date representing the current day in UTC

# `today`

```elixir
@spec today(Timex.Types.valid_timezone()) :: Date.t()
```

Returns a Date representing the current day in the provided timezone.

# `validate_format`

```elixir
@spec validate_format(String.t()) :: :ok | {:error, term()}
```

Given a format string, validates that the format string is valid for the Default formatter.

Given a format string and a formatter, validates that the format string is valid for that formatter.

## Examples

    iex> use Timex
    ...> Timex.validate_format("{YYYY}-{M}-{D}")
    :ok

    iex> use Timex
    ...> Timex.validate_format("{YYYY}-{M}-{V}")
    {:error, "Expected end of input at line 1, column 11"}

    iex> use Timex
    ...> Timex.validate_format("%FT%T%:z", :strftime)
    :ok

# `validate_format`

```elixir
@spec validate_format(String.t(), atom()) :: :ok | {:error, term()}
```

# `week_of_month`

```elixir
@spec week_of_month(Timex.Types.valid_datetime()) :: Timex.Types.week_of_month()
```

Returns the week number within the month, starting at 1.

Weeks begin on Monday. The partial week containing the first day of the month
is week 1, even when it begins in the preceding month or ISO year. A month can
therefore contain up to six weeks.

## Examples

    iex> Timex.week_of_month(~D[2016-03-05])
    1

    iex> Timex.week_of_month(~N[2016-03-14T00:00:00Z])
    3

    iex> Timex.week_of_month(~D[2019-12-01])
    1

    iex> Timex.week_of_month(~D[2019-12-02])
    2

# `week_of_month`

```elixir
@spec week_of_month(Timex.Types.year(), Timex.Types.month(), Timex.Types.day()) ::
  Timex.Types.week_of_month()
```

Same as `week_of_month/1`, except takes year, month, and day as distinct arguments.

Weeks begin on Monday, and the partial week containing the first day of the
month is week 1.

## Examples

    iex> Timex.week_of_month(2016, 3, 30)
    5

# `weekday`

```elixir
@spec weekday(Timex.Types.valid_datetime()) ::
  Timex.Types.weekday() | {:error, :invalid_date}
```

Return weekday number (as defined by ISO 8601) of the specified date.

## Examples

    iex> Timex.epoch |> Timex.weekday
    4 # (i.e. Thursday)

# `weekday`

```elixir
@spec weekday(Timex.Types.valid_datetime(), Timex.Types.weekday_name()) ::
  Timex.Types.weekday() | {:error, :invalid_date}
```

Like `weekday/1`, but accepts a valid starting weekday value.

## Examples

    iex> Timex.epoch() |> Elixir.Timex.weekday(:sunday)
    5

# `weekday!`

Provides a version of `weekday/1` and `weekday/2` that raises on error.

# `zero`

```elixir
@spec zero() :: Date.t()
```

Returns a Date representing the start of the Gregorian epoch

---

*Consult [api-reference.md](api-reference.md) for complete listing*
