Provides localized formatting of DateTime, NaiveDateTime,
and datetime-like maps.
The primary function is to_string/2 which accepts a datetime
value and an options keyword list. Format patterns are defined
in CLDR and described in
TR35.
Ordinal days are a technical preview
The ddd field formats the day as a date ordinal ("Jul 6th"). TR35
designates the section a technical preview, so both the output and the
surface may change. Localize.Date documents the detail.
Predefined formats
:short— abbreviated date and time (e.g., "1/2/25, 3:04 PM").:medium— standard date and time (default).:long— includes time zone name.:full— verbose day-of-week, date, and time zone.
Custom CLDR skeleton strings and raw format patterns are also
supported via the :format option.
Summary
Functions
Returns the numeric date and time separators a locale uses.
Parses a localized date and time string.
Formats a datetime into typed parts, mirroring ECMA-402's formatToParts.
Same as to_parts/2 but raises on error.
Formats a datetime according to a CLDR format pattern.
Same as to_string/2 but raises on error.
Functions
@spec numeric_separators(Localize.locale(), atom()) :: {:ok, map()} | {:error, Exception.t()}
Returns the numeric date and time separators a locale uses.
These are CLDR 49's numericDateSeparator and numericTimeSeparator, which
TR35 designates a technical preview — the data and the behaviour may change.
TR35 offers them so an implementation can let a caller choose a
separator — dates as "05/06/2006" or "05-06-2006", times as "23:59" or
"23.59" — which to_string/2 does through its :numeric_date_separator
and :numeric_time_separator options. Read them to show a caller what
the locale uses before they override it.
Arguments
localeis any locale returned byLocalize.all_locale_ids/0or aLocalize.LanguageTag.t/0. The default isLocalize.get_locale/0.calendar_typeis a CLDR calendar name. The default is:gregorian.
Returns
{:ok, separators}whereseparatorsis a map with the keys:numeric_date_separatorand:numeric_time_separator.{:error, exception}if the locale or calendar is unknown, or the locale carries no separator data.
Examples
iex> Localize.DateTime.numeric_separators(:en)
{:ok, %{numeric_date_separator: "/", numeric_time_separator: ":"}}
iex> Localize.DateTime.numeric_separators(:fi)
{:ok, %{numeric_date_separator: ".", numeric_time_separator: "."}}
@spec parse(String.t(), Keyword.t()) :: {:ok, NaiveDateTime.t() | DateTime.t()} | {:error, Exception.t()}
Parses a localized date and time string.
Accepts any shape the locale accepts, including the locale's CLDR short, medium, long and full patterns and ISO 8601.
ISO 8601 is read in every form it joins a date to a time with a T:
the date as a calendar date, a day of the year ("2026-167") or a week
date ("2026-W25-2"), the time with its seconds, or its minutes and
seconds, left out ("2026-06-16T10:30"), and either without its
separators ("20260616T103000"). A fraction is the second's alone: a
fraction of a minute or of an hour is not read.
An input carrying a fixed UTC offset resolves to a DateTime.t/0,
whether written as an ISO 8601 offset (+05:30, Z) or in the
locale's GMT format (GMT+10:30, UTC-5). Its time zone is the offset
itself, "+05:30", as ECMA-262 Temporal and RFC 9557 name the zone of
a fixed offset, and "Etc/UTC" for no offset at all; see
Localize.TimeZoneDatabase for the functions of DateTime that look
such a zone up. A named zone (PST,
Asia/Tokyo) carries no offset of its own and needs a time-zone
database, which the companion
calendrical package supplies;
without it the zone is dropped and the result is a
NaiveDateTime.t/0.
Arguments
stringis a string in any shape the locale accepts, including the locale's CLDR short, medium, long and full patterns and ISO 8601.optionsis a keyword list of options.
Options
:localeis a locale identifier. The default is the locale returned byLocalize.get_locale/0.:calendaris a calendar module, such asCalendar.ISO(the default),Calendrical.GregorianorCalendrical.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"), is the calendar's own, as itsdate_from_week_date/3answers: ISO 8601's week forCalendar.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 itsinfo/0names as:parsing_calendar, and converted, asLocalize.Date.parse/2reads a date. 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), and a time after a space are the calendar's own, and where none does, or with ISO 8601'sT, the text is an ISO 8601 date and time, converted into the calendar. Anything that is not a calendar module, including a CLDR calendar name such as:hebrewor"gregorian", and a module that implements only theCalendarbehaviour, returns aLocalize.UnknownCalendarError.t/0.:formatis the format the date and time were written with, asto_string/2takes it: a standard format (:short,:medium,:longor:full), a skeleton atom such as:yMdHm, aLocalize.DateTime.SemanticSkeleton, or a pattern string such as"d/M/y HH:mm". Each half is read with its part of it and with nothing else, ISO 8601 included. A standard format is the date's and the time's alike. A skeleton is split into its date fields and its time fields, and so is a semantic skeleton, its zone going with its time. A pattern, which writes its date fields in one run and its time fields in another, is split at the text between them, where the input is split too. The default isnil: the text is read as ISO 8601 or in whichever of the locale's formats reads it first.:date_formatand:time_formatare the formats the date and the time were written with, each asLocalize.Date.parse/2andLocalize.Time.parse/2take:format, and take the place of the halves of:format. A half with no format is read in any of the locale's formats.:reference_dateis theDate.t/0that partial input is completed against, taken in the calendar the input is read in. The default is today.:asis:structor:map.:mapreturns only the fields the input actually carried, rather than completing them; a field no date or time has is an error in both forms. A zone adds theDateTime.t/0zone fields (:time_zone,:utc_offset,:std_offsetand:zone_abbr) as the struct form resolves them: a fixed offset always, and a named zone when the input gives the full date its offset depends on; otherwise:time_zoneholds the zone as written. A date and time read in another calendar and converted, as a calendar of weeks reads one, comes back whole, but for a week written without its day, which is the calendar's year and week. The default is:struct.
Returns
{:ok, value}wherevalueis aNaiveDateTime.t/0, or aDateTime.t/0when the input carried a resolvable zone, or{:error, exception}if the string does not parse, or aLocalize.InvalidValueError.t/0ifstringis not a string or an option is malformed.
Examples
iex> Localize.DateTime.parse("22.03.2026, 14:30", locale: :de)
{:ok, ~N[2026-03-22 14:30:00]}
iex> Localize.DateTime.parse("March 22, 2026, 2:30 PM", locale: :en)
{:ok, ~N[2026-03-22 14:30:00]}
iex> Localize.DateTime.parse("2026-W12-7T14:30", locale: :en)
{:ok, ~N[2026-03-22 14:30:00]}
iex> {:ok, map} = Localize.DateTime.parse("March 22, 2026, 2:30 PM GMT+5", locale: :en, as: :map)
iex> Map.take(map, [:hour, :time_zone, :utc_offset])
%{hour: 14, time_zone: "+05:00", utc_offset: 18000}
@spec to_parts(map(), Keyword.t()) :: {:ok, [%{type: atom(), value: String.t()}]} | {:error, Exception.t()}
Formats a datetime 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, :hour, :minute, :second, :day_period, :time_zone_name, :era, :fractional_second, :literal, …). Standard formats, skeleton atoms, explicit pattern strings, and combined date+time wrappers all decompose.
Arguments
datetimeis aDateTime.t/0,NaiveDateTime.t/0, or any map with date and time keys.optionsis a keyword list of options.
Options
See to_string/2 for the supported options.
Returns
{:ok, parts}wherepartsis a list of%{type: atom(), value: String.t()}maps.{:error, exception}if the datetime cannot be formatted.
Examples
iex> Localize.DateTime.to_parts(~N[2017-07-10 14:30:00], format: :hm, locale: :en, prefer: :ascii)
{:ok,
[
%{type: :hour, value: "2"},
%{type: :literal, value: ":"},
%{type: :minute, value: "30"},
%{type: :literal, value: " "},
%{type: :day_period, value: "PM"}
]}
Same as to_parts/2 but raises on error.
Arguments
datetimeis aDateTime.t/0,NaiveDateTime.t/0, or any map with date and time keys.optionsis a keyword list of options. Seeto_parts/2.
Returns
- A list of
%{type: atom(), value: String.t()}maps.
Raises
- Raises an exception if the datetime cannot be formatted.
Examples
iex> Localize.DateTime.to_parts!(~N[2017-07-10 14:30:00], format: :hm, locale: :en, prefer: :ascii) |> length()
5
@spec to_string(map(), Keyword.t()) :: {:ok, String.t()} | {:error, Exception.t()}
Formats a datetime according to a CLDR format pattern.
Arguments
datetimeis aDateTime.t/0,NaiveDateTime.t/0, or any map with date or time keys. A map holding only some of the date and time fields formats its date half and its time half separately and joins them; one holding only date keys or only time keys is formatted asLocalize.DateorLocalize.Timewould format it.optionsis a keyword list of options.
Options
:formatis a standard format name (:short,:medium,:long,:full), a format skeleton atom, aLocalize.DateTime.SemanticSkeletonor a format pattern string. The default is:medium. A standard format sets the width of the date and the time together;:date_formatand:time_formatoverride each axis separately. A value with no time zone, aNaiveDateTime.t/0or a map holding neither:time_zonenor:utc_offset, is written at:longand:fullwith the timeLocalize.Time.to_string/2writes for it, the format's fields without its zone.:date_formatand:time_formatare standard format names, skeleton atoms or semantic skeletons that set the date half and the time half independently, each defaulting to:format. Use them for the common "full date, short time" pairing:date_format: :full, time_format: :shortrenders "Wednesday, April 8, 2026, 12:00 PM". When:date_formatis given it also selects the wrapper width.:styleselects the CLDR pattern that joins the date and the time.:at(the default) uses the locale's "at time" wrapper ("April 8, 2026 at 12:00:00 PM", de "8. April 2026 um 12:00:00");:defaultuses the standard wrapper ("April 8, 2026, 12:00:00 PM").TR35 makes the "at time" wrapper the default for a single date combined with a single time — an event time — and asks that an API also offer the standard wrapper for a current time, which is what
:defaultis. CLDR defines the "at time" wrapper only for:fulland:long, so both styles agree at:mediumand:short.:localeis a locale identifier. The default is:en.:number_systemis 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_separatoris a string replacing the locale'snumericDateSeparatorwherever it separates the fields of a numeric-month date, as TR35 allows an implementation to offer.Localize.DateTime.numeric_separators/2returns the locale's own. The default is the locale's separator.:numeric_time_separatoris a string replacing the locale'snumericTimeSeparatorwherever it separates time fields. The default is the locale's separator.:preferselects between CLDRaltvariants. 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(mostly time formats — NBSP and curly quotes vs ASCII-only). Examples:prefer: :variant,prefer: [:variant, :ascii]. The default is[:standard, :unicode].
Returns
{:ok, formatted_string}on success.{:error, exception}if the datetime cannot be formatted.
Examples
iex> Localize.DateTime.to_string(~N[2017-07-10 14:30:00], locale: :en, prefer: :ascii)
{:ok, "Jul 10, 2017, 2:30:00 PM"}
iex> Localize.DateTime.to_string(~N[2017-07-10 14:30:00], format: :short, locale: :en, prefer: :ascii)
{:ok, "7/10/17, 2:30 PM"}
iex> Localize.DateTime.to_string(%{year: 2026, month: 6, day: 15, hour: 14}, locale: :en, prefer: :ascii)
{:ok, "Jun 15, 2026, 2 PM"}
Same as to_string/2 but raises on error.
Arguments
datetimeis aDateTime.t/0,NaiveDateTime.t/0, or any map with date and time keys.optionsis a keyword list of options.
Options
See to_string/2 for the supported options.
Returns
A formatted string.
Raises an exception if the datetime cannot be formatted.
Examples
iex> Localize.DateTime.to_string!(~N[2017-07-10 14:30:00], locale: :en, prefer: :ascii)
"Jul 10, 2017, 2:30:00 PM"
iex> Localize.DateTime.to_string!(~N[2017-07-10 14:30:00], format: :short, locale: :en, prefer: :ascii)
"7/10/17, 2:30 PM"