# `Localize.Date`
[🔗](https://github.com/elixir-localize/localize/blob/v1.4.0/lib/localize/date.ex#L1)

Provides localized formatting of `Date` structs and date-like maps.

Supports both full dates (`%{year: _, month: _, day: _}`) and partial
dates (any map with one or more of `:year`, `:month`, `:day`). For a
partial date a standard format, or no format, derives the skeleton from
the fields present; a skeleton or pattern that asks for a field the date
does not have returns `Localize.DateTimeInvalidInputError`.

Formats are defined in CLDR and described in
[TR35](http://unicode.org/reports/tr35/tr35-dates.html).

> #### Ordinal days are a technical preview {: .warning}
>
> CLDR 49 adds the `ddd` field, which formats the day as a date ordinal
> taken from the locale's `dayOfMonths` data — `:yMMMddd` renders
> "Jul 6th, 2024" in `en` and "1er juil. 2024" in `fr`. A locale without
> that data, and any pattern whose month is numeric, format the plain day.
>
> TR35 designates the `dayOfMonth` section a technical preview, and the
> element shape was narrowed once during CLDR 49's development. Only the
> `abbreviated` width and the ordinal-keyed forms are read, and
> `Localize.Interval` cannot yet request an ordinal skeleton. Treat both
> the output and the surface as subject to change.

# `parse`

```elixir
@spec parse(String.t(), Keyword.t()) :: {:ok, Date.t()} | {:error, Exception.t()}
```

Parses a localized date string.

Accepts any shape the locale accepts, including the locale's CLDR short,
medium, long and full patterns and ISO 8601.

A date in another calendar is parsed by passing that calendar's module
as `:calendar`; the companion
[calendrical](https://hex.pm/packages/calendrical) package supplies the
calendars Localize formats for.

### Arguments

* `string` is a string in any shape the locale accepts, including the
  locale's CLDR short, medium, long and full patterns and ISO 8601.

* `options` is a keyword list of options.

### Options

* `:locale` is a locale identifier. The default is the locale returned by
  `Localize.get_locale/0`.

* `:calendar` is a calendar module, such as `Calendar.ISO` (the
  default), `Calendrical.Gregorian` or `Calendrical.Hebrew`. The input is
  read with the locale's patterns for the calendar's CLDR type, and the
  date is built and returned in this module. A week date, in any
  form ISO 8601 writes one in (`"2024-W05-4"`, `"2024W054"` and the
  week alone, `"2024-W05"`), is the calendar's own: every calendar
  answers `date_from_week_date/3`, so it is ISO 8601's week for
  `Calendar.ISO` and the fifth week of its own year for a calendar
  built of weeks. Text that none of the calendar's own formats reads
  is read in the calendar its `info/0` names as `:parsing_calendar`, and
  converted: a calendar built of weeks, whose months are `"M02"` and
  not `"Feb"`, names `Calendar.ISO`, so `"Feb 1, 2024"` is 1 February
  2024 in it. A composite calendar, whose dates are written with the
  formats of whichever of its calendars was in effect, names those
  calendars with its `parsing_calendars/0`, and a date is then
  read in each and converted, held to the calendar its day is written
  in. A calendar's own formats come before ISO 8601: a year, a
  month and a day between hyphens that any of them reads, as CLDR's
  root short date of the Chinese calendar does (`r-MM-dd`), is the
  calendar's own date, and where none does it is an ISO 8601 date,
  converted into the calendar. Anything that is not a calendar module,
  including a CLDR calendar name such as `:hebrew` or `"gregorian"`, and
  a module that implements only the `Calendar` behaviour, returns a
  `t:Localize.UnknownCalendarError.t/0`.

* `:format` is the format the text was written with, as `to_string/2` takes it: a standard format (`:short`, `:medium`, `:long` or `:full`), a skeleton atom such as `:yMd`, a `Localize.DateTime.SemanticSkeleton` or a pattern string such as `"d/M/y"`. The text is read with that format and no other, after the calendar's own notation, so a date written by a skeleton whose fields stand in another order than the locale's standard formats' reads back as itself: `mt`'s `:yMd` writes 3 April 2024 as "4/3/2024", which is 4 March where no format is given. A pattern string is read before the notation, which is never what it writes, and the notation where the pattern reads nothing. A format of fewer fields than a date has, such as `:yMMM`, needs `as: :map`. The default is `nil`: the text is read in whichever of the locale's formats reads it first.

* `:reference_date` is the `t:Date.t/0` that partial input is completed
  against, taken in the calendar the input is read in. A week written
  without its year is a week of the reference date's week-based year,
  which is not the year of its days about the new year. The default is
  today.

* `:as` is `:struct` or `:map`. `:map` returns only the fields the input
  actually carried, rather than completing them. They must still be
  fields some date has, so `"June 31"` is an error in both forms while
  `"February 29"` is a partial date. A date read in another calendar and
  converted, as a composite calendar reads one of an earlier calendar,
  comes back whole, as a partial date has no fields in the other
  calendar. What names no day to convert is the exception: a year is
  `%{year: 2026}`, and a year and a quarter are the two. The default is
  `:struct`.

### Returns

* `{:ok, value}` where `value` is a `t:Date.t/0`, or

* `{:error, exception}` if the string does not parse, a
  `Localize.DateTimeFormatError` or a
  `Localize.DateTimeUnresolvedFormatError` if `:format` is no
  format of a date, or a `t:Localize.InvalidValueError.t/0` if `string`
  is not a string or an option is malformed.

### Examples

    iex> Localize.Date.parse("22.03.2026", locale: :de)
    {:ok, ~D[2026-03-22]}

    iex> Localize.Date.parse("March 22, 2026", locale: :en)
    {:ok, ~D[2026-03-22]}

    iex> Localize.Date.parse("4/3/2024", locale: :en)
    {:ok, ~D[2024-04-03]}

    iex> Localize.Date.parse("4/3/2024", locale: :en, format: "d/M/y")
    {:ok, ~D[2024-03-04]}

# `to_parts`

```elixir
@spec to_parts(map(), Keyword.t()) ::
  {:ok, [%{type: atom(), value: String.t()}]} | {:error, Exception.t()}
```

Formats a date into typed parts, mirroring ECMA-402's `formatToParts`.

The parts concatenate to exactly the string `to_string/2` produces with the same options. Each pattern field is tagged with its type: `:year`, `:month`, `:day`, `:weekday`, `:era`, and `:literal` for separators.

### Arguments

* `date` is a `t:Date.t/0` or any map with date keys.

* `options` is a keyword list of options.

### Options

See `to_string/2` for the supported options.

### Returns

* `{:ok, parts}` where `parts` is a list of `%{type: atom(), value: String.t()}` maps.

* `{:error, exception}` if the date cannot be formatted.

### Examples

    iex> Localize.Date.to_parts(~D[2017-07-10], locale: :en)
    {:ok,
     [
       %{type: :month, value: "Jul"},
       %{type: :literal, value: " "},
       %{type: :day, value: "10"},
       %{type: :literal, value: ", "},
       %{type: :year, value: "2017"}
     ]}

# `to_parts!`

```elixir
@spec to_parts!(map(), Keyword.t()) :: [%{type: atom(), value: String.t()}]
```

Same as `to_parts/2` but raises on error.

### Arguments

* `date` is a `t:Date.t/0` or any map with date keys.

* `options` is a keyword list of options. See `to_parts/2`.

### Returns

* A list of `%{type: atom(), value: String.t()}` maps.

### Raises

* Raises an exception if the date cannot be formatted.

### Examples

    iex> Localize.Date.to_parts!(~D[2017-07-10], locale: :en) |> length()
    5

# `to_string`

```elixir
@spec to_string(map(), Keyword.t()) :: {:ok, String.t()} | {:error, Exception.t()}
```

Formats a date according to a CLDR format pattern.

### Arguments

* `date` is a `t:Date.t/0` or any map with one or more of
  `:year`, `:month`, `:day` keys.

* `options` is a keyword list of options.

### Options

* `:format` is a standard format name (`:short`, `:medium`,
  `:long`, `:full`), a format skeleton atom, a
  `Localize.DateTime.SemanticSkeleton` or a format pattern
  string. The default is `:medium`. For a partial date a
  standard format derives its skeleton from the fields present,
  with the month numeric at `:short`, abbreviated at `:medium`
  and wide at `:long` and `:full`. Every calendar's date is
  written from its year, its month and its day: a calendar built
  of weeks, such as `Calendrical.ISOWeek`, has the months of its
  pattern of weeks, named as CLDR's generic calendar names them
  (`"M06 16, 2026 AD"`), and its week is written by a format that
  names one (`:yw`, `"week 25 of 2026"`).

* `:locale` is a locale identifier. The default is `:en`.

* `:number_system` is a CLDR numbering system name (for example, `:thai`). All numeric fields render in that system; a `-u-nu-` locale extension may be used instead. The default is the locale's number system.

* `:numeric_date_separator` is a string replacing the locale's `numericDateSeparator` wherever it separates the fields of a numeric-month date, as TR35 allows an implementation to offer. `Localize.DateTime.numeric_separators/2` returns the locale's own. The default is the locale's separator.

* `:numeric_time_separator` is a string replacing the locale's `numericTimeSeparator` wherever it separates time fields. The default is the locale's separator.

* `:prefer` selects between CLDR `alt` variants. Accepts an
  atom or a list of atoms in priority order. Recognised values:
  `:standard` / `:variant` (locales like en-CA publish both an
  ISO pattern `"y-MM-dd"` and a locale-variant `"d/M/yy"`),
  and `:unicode` / `:ascii` (NBSP and curly quotes vs ASCII).
  Examples: `prefer: :variant`, `prefer: [:variant, :ascii]`.
  The default is `[:standard, :unicode]`.

### Returns

* `{:ok, formatted_string}` on success.

* `{:error, exception}` if the date cannot be formatted.

### Examples

    iex> Localize.Date.to_string(~D[2017-07-10], locale: :en)
    {:ok, "Jul 10, 2017"}

    iex> Localize.Date.to_string(~D[2017-07-10], format: :full, locale: :en)
    {:ok, "Monday, July 10, 2017"}

    iex> Localize.Date.to_string(~D[2017-07-10], format: :short, locale: :en)
    {:ok, "7/10/17"}

    iex> Localize.Date.to_string(~D[2017-07-10], format: :short, locale: :fr)
    {:ok, "10/07/2017"}

    iex> Localize.Date.to_string(%{year: 2024, month: 6}, format: :yMMM, locale: :fr)
    {:ok, "juin 2024"}

    iex> Localize.Date.to_string(%{year: 2024, month: 6}, format: :long, locale: :en)
    {:ok, "June 2024"}

# `to_string!`

```elixir
@spec to_string!(map(), Keyword.t()) :: String.t()
```

Same as `to_string/2` but raises on error.

### Arguments

* `date` is a `t:Date.t/0` or any map with one or more of
  `:year`, `:month`, `:day` keys.

* `options` is a keyword list of options.

### Options

See `to_string/2` for the supported options.

### Returns

* A formatted string.

* Raises an exception if the date cannot be formatted.

### Examples

    iex> Localize.Date.to_string!(~D[2017-07-10], locale: :en)
    "Jul 10, 2017"

    iex> Localize.Date.to_string!(%{year: 2024, month: 6}, format: :yMMM, locale: :fr)
    "juin 2024"

---

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