intldate

Date formatting for gleam_time following the JavaScript Intl.DateTimeFormat() API.

This module provides a type-safe wrapper around the Intl.DateTimeFormat API, allowing you to format dates and times according to locale-specific conventions.

Works on both the JavaScript and Erlang runtimes. On JavaScript it delegates to the native Intl.DateTimeFormat(), while on Erlang it uses a pure Gleam reimplementation that mirrors the same behaviour, so the output stays consistent whichever target you compile to.

Error handling

format never fails: if the time zone, locale, or calendar cannot be resolved, it returns a human-readable, English-only message describing the error (via describe_error), regardless of the requested locale.

If you’d rather handle the error yourself, use try_format, which returns a Result(String, IntlError).

Types

The calendar system to use for date formatting.

  • CalendarBuddhist: Buddhist calendar
  • CalendarChinese: Chinese calendar
  • CalendarCoptic: Coptic calendar
  • CalendarDangi: Dangi calendar (Korean)
  • CalendarEthioaa: Ethiopic Amete Alem calendar
  • CalendarEthiopic: Ethiopic calendar
  • CalendarGregory: Gregorian calendar
  • CalendarHebrew: Hebrew calendar
  • CalendarIndian: Indian national calendar
  • CalendarIslamic: Islamic calendar
  • CalendarIslamicUmalqura: Islamic calendar (Umm al-Qura)
  • CalendarIslamicTbla: Islamic calendar (tabular, astronomical epoch)
  • CalendarIslamicCivil: Islamic calendar (tabular, civil epoch)
  • CalendarIslamicRgsa: Islamic calendar (Saudi Arabia sighting)
  • CalendarIso8601: ISO 8601 calendar (Gregorian with ISO week numbering)
  • CalendarJapanese: Japanese imperial calendar
  • CalendarPersian: Persian calendar
  • CalendarRoc: Republic of China calendar
pub type Calendar {
  CalendarBuddhist
  CalendarChinese
  CalendarCoptic
  CalendarDangi
  CalendarEthioaa
  CalendarEthiopic
  CalendarGregory
  CalendarHebrew
  CalendarIndian
  CalendarIslamic
  CalendarIslamicUmalqura
  CalendarIslamicTbla
  CalendarIslamicCivil
  CalendarIslamicRgsa
  CalendarIso8601
  CalendarJapanese
  CalendarPersian
  CalendarRoc
}

Constructors

  • CalendarBuddhist
  • CalendarChinese
  • CalendarCoptic
  • CalendarDangi
  • CalendarEthioaa
  • CalendarEthiopic
  • CalendarGregory
  • CalendarHebrew
  • CalendarIndian
  • CalendarIslamic
  • CalendarIslamicUmalqura
  • CalendarIslamicTbla
  • CalendarIslamicCivil
  • CalendarIslamicRgsa
  • CalendarIso8601
  • CalendarJapanese
  • CalendarPersian
  • CalendarRoc

Configuration for date/time formatting.

This type allows you to specify which date and time components to include in the formatted output and how they should be represented.

Create a new configuration with new() and customize it with the various with_* functions.

pub type DateTimeFormatConfig {
  DateTimeFormatConfig(
    locale_matcher: option.Option(LocaleMatcher),
    calendar: option.Option(Calendar),
    weekday: option.Option(Weekday),
    era: option.Option(Era),
    year: option.Option(Year),
    month: option.Option(Month),
    day: option.Option(Day),
    hour: option.Option(Hour),
    minute: option.Option(Minute),
    second: option.Option(Second),
    time_zone_name: option.Option(TimeZoneName),
    format_matcher: option.Option(FormatMatcher),
    hour12: option.Option(Bool),
  )
}

Constructors

One structured part of a formatted date/time string.

pub type DateTimeFormatPart {
  DateTimeFormatPart(
    kind: DateTimePartKind,
    value: String,
    source: DateTimePartSource,
  )
}

Constructors

A part type returned by format_to_parts and format_range_to_parts.

pub type DateTimePartKind {
  DateTimePartLiteral
  DateTimePartWeekday
  DateTimePartEra
  DateTimePartYear
  DateTimePartRelatedYear
  DateTimePartYearName
  DateTimePartMonth
  DateTimePartDay
  DateTimePartDayPeriod
  DateTimePartHour
  DateTimePartMinute
  DateTimePartSecond
  DateTimePartFractionalSecond
  DateTimePartTimeZoneName
  DateTimePartUnknown(inner: String)
}

Constructors

  • DateTimePartLiteral
  • DateTimePartWeekday
  • DateTimePartEra
  • DateTimePartYear
  • DateTimePartRelatedYear
  • DateTimePartYearName
  • DateTimePartMonth
  • DateTimePartDay
  • DateTimePartDayPeriod
  • DateTimePartHour
  • DateTimePartMinute
  • DateTimePartSecond
  • DateTimePartFractionalSecond
  • DateTimePartTimeZoneName
  • DateTimePartUnknown(inner: String)

Where a range part came from.

pub type DateTimePartSource {
  DateTimePartSourceNone
  DateTimePartSourceStartRange
  DateTimePartSourceShared
  DateTimePartSourceEndRange
}

Constructors

  • DateTimePartSourceNone
  • DateTimePartSourceStartRange
  • DateTimePartSourceShared
  • DateTimePartSourceEndRange

Options resolved by a date/time formatter.

pub type DateTimeResolvedOptions {
  DateTimeResolvedOptions(
    locale: String,
    calendar: String,
    numbering_system: String,
    time_zone: String,
    hour_cycle: option.Option(String),
    hour12: option.Option(Bool),
    weekday: option.Option(String),
    era: option.Option(String),
    year: option.Option(String),
    month: option.Option(String),
    day: option.Option(String),
    hour: option.Option(String),
    minute: option.Option(String),
    second: option.Option(String),
    time_zone_name: option.Option(String),
  )
}

Constructors

The representation of the day.

  • DayNumeric: Numeric representation (e.g., “5”)
  • Day2Digit: Two-digit numeric representation (e.g., “05”)
pub type Day {
  DayNumeric
  Day2Digit
}

Constructors

  • DayNumeric
  • Day2Digit

The representation of the era.

  • EraLong: Full era name (e.g., “Anno Domini”, “après Jésus-Christ”)
  • EraShort: Abbreviated era name (e.g., “AD”, “ap. J.-C.”)
  • EraNarrow: Narrow era name (e.g., “A”, “ap. J.-C.”)
pub type Era {
  EraLong
  EraShort
  EraNarrow
}

Constructors

  • EraLong
  • EraShort
  • EraNarrow

The format matching algorithm to use.

  • FormatMatcherBestFit: The runtime is allowed to choose the best format based on the requested components and the locale.
  • FormatMatcherBasic: Use a basic algorithm that prioritizes matching the requested components in order.
pub type FormatMatcher {
  FormatMatcherBestFit
  FormatMatcherBasic
}

Constructors

  • FormatMatcherBestFit
  • FormatMatcherBasic

The representation of the hour.

  • HourNumeric: Numeric representation (e.g., “5”)
  • Hour2Digit: Two-digit numeric representation (e.g., “05”)
pub type Hour {
  HourNumeric
  Hour2Digit
}

Constructors

  • HourNumeric
  • Hour2Digit
pub type IntlError {
  FailedToLoadTimeZone(inner: String)
  FailedToLoadLocale(inner: String)
  FailedToLoadCalendar(inner: String)
  FailedToLoadData(inner: String)
  SystemTimeZoneUnavailable
  Unknown(inner: String)
}

Constructors

  • FailedToLoadTimeZone(inner: String)

    The requested time zone could not be loaded or resolved.

  • FailedToLoadLocale(inner: String)

    The requested locale could not be loaded or resolved.

  • FailedToLoadCalendar(inner: String)

    The requested calendar could not be loaded or resolved.

  • FailedToLoadData(inner: String)

    The bundled locale data could not be loaded or validated.

  • SystemTimeZoneUnavailable

    The system local time zone could not be detected.

  • Unknown(inner: String)

    Any error not accounted for by this type.

The locale matching algorithm to use.

  • LocaleMatcherBestFit: The runtime is allowed to choose the best matching locale, potentially considering extension keys and other options.
  • LocaleMatcherLookup: Use the BCP 47 lookup algorithm to find the best matching locale.
pub type LocaleMatcher {
  LocaleMatcherBestFit
  LocaleMatcherLookup
}

Constructors

  • LocaleMatcherBestFit
  • LocaleMatcherLookup

The representation of the minute.

  • MinuteNumeric: Numeric representation (e.g., “8”)
  • Minute2Digit: Two-digit numeric representation (e.g., “08”)
pub type Minute {
  MinuteNumeric
  Minute2Digit
}

Constructors

  • MinuteNumeric
  • Minute2Digit

The representation of the month.

  • MonthNumeric: Numeric representation (e.g., “2”)
  • Month2Digit: Two-digit numeric representation (e.g., “02”)
  • MonthLong: Full month name (e.g., “February”, “février”)
  • MonthShort: Abbreviated month name (e.g., “Feb”, “févr.”)
  • MonthNarrow: Narrow month name (e.g., “F”, “F”)
pub type Month {
  MonthNumeric
  Month2Digit
  MonthLong
  MonthShort
  MonthNarrow
}

Constructors

  • MonthNumeric
  • Month2Digit
  • MonthLong
  • MonthShort
  • MonthNarrow

The representation of the second.

  • SecondNumeric: Numeric representation (e.g., “3”)
  • Second2Digit: Two-digit numeric representation (e.g., “03”)
pub type Second {
  SecondNumeric
  Second2Digit
}

Constructors

  • SecondNumeric
  • Second2Digit

The localized representation of the time zone name.

  • TimeZoneNameShort: Short time zone name (e.g., “EST”, “PST”)
  • TimeZoneNameLong: Long time zone name (e.g., “Eastern Standard Time”)
  • TimeZoneNameShortOffset: Short GMT offset (e.g., “GMT+9”)
  • TimeZoneNameLongOffset: Long GMT offset (e.g., “GMT+09:00”)
  • TimeZoneNameShortGeneric: Short generic non-location format (e.g., “ET”, “PT”)
  • TimeZoneNameLongGeneric: Long generic non-location format (e.g., “Eastern Time”)
pub type TimeZoneName {
  TimeZoneNameShort
  TimeZoneNameLong
  TimeZoneNameShortOffset
  TimeZoneNameLongOffset
  TimeZoneNameShortGeneric
  TimeZoneNameLongGeneric
}

Constructors

  • TimeZoneNameShort
  • TimeZoneNameLong
  • TimeZoneNameShortOffset
  • TimeZoneNameLongOffset
  • TimeZoneNameShortGeneric
  • TimeZoneNameLongGeneric

The representation of the weekday.

  • WeekdayLong: Full weekday name (e.g., “Monday”, “lundi”)
  • WeekdayShort: Abbreviated weekday name (e.g., “Mon”, “lun”)
  • WeekdayNarrow: Narrow weekday name (e.g., “M”, “L”)
pub type Weekday {
  WeekdayLong
  WeekdayShort
  WeekdayNarrow
}

Constructors

  • WeekdayLong
  • WeekdayShort
  • WeekdayNarrow

The representation of the year.

  • YearNumeric: Full numeric representation (e.g., “2026”)
  • Year2Digit: Two-digit numeric representation (e.g., “26”)
pub type Year {
  YearNumeric
  Year2Digit
}

Constructors

  • YearNumeric
  • Year2Digit

Values

pub fn describe_error(error: IntlError) -> String

Convert an error into a human-readable description.

Example

let assert "Failed to load time zone: Invalid/TimeZone" =
  describe_error(FailedToLoadTimeZone("Invalid/TimeZone"))
pub fn format(
  date date: timestamp.Timestamp,
  time_zone time_zone: option.Option(String),
  locale locale: option.Option(String),
  config config: DateTimeFormatConfig,
) -> String

Format a timestamp according to the specified locale and configuration.

Parameters

  • date: The timestamp to format
  • time_zone: The time zone to use (IANA time zone name like “America/New_York”). If None, uses the system’s local time zone.
  • locale: The locale to use for formatting (BCP 47 language tag like “en-US”, “fr-FR”). If None, uses the system’s default locale.
  • config: The configuration object specifying which date/time components to include

Why Timestamp Instead of Calendar?

This function depends directly on the timestamp module and not calendar from gleam_time because Calendar represents a day and time separately without any timezone information, and the built-in timestamp to calendar conversion in gleam_time does not have complete support for time zones as described by IANA. Therefore, it can only represent time zones as offsets and does not take countries with daylight saving time into account. Since the Intl.DateTimeFormat model works directly with a date in UTC and resolves the time zone display from the IANA database, it is more logical to use a timestamp for this purpose.

Example

import gleam/option
import gleam/time/timestamp
import intldate

let assert Ok(date) = timestamp.parse_rfc3339("2026-02-24T17:48:22+04:00")

intldate.format(
  date:,
  time_zone: option.Some("Indian/Reunion"),
  locale: option.Some("fr-FR"),
  config: intldate.new()
    |> intldate.with_weekday(intldate.WeekdayLong)
    |> intldate.with_year(intldate.YearNumeric)
    |> intldate.with_month(intldate.MonthLong)
    |> intldate.with_day(intldate.DayNumeric)
    |> intldate.with_hour(intldate.HourNumeric)
    |> intldate.with_minute(intldate.MinuteNumeric),
)
// -> "mardi 24 février 2026 à 17:48"
pub fn format_range(
  date_start date_start: timestamp.Timestamp,
  date_end date_end: timestamp.Timestamp,
  time_zone time_zone: option.Option(String),
  locale locale: option.Option(String),
  config config: DateTimeFormatConfig,
) -> String

Format a range between two timestamps according to the specified locale and configuration, using the same options as format.

This mirrors the Intl.DateTimeFormat.prototype.formatRange API: it renders the two dates together, collapsing the parts they have in common.

Parameters

  • date_start: The timestamp marking the start of the range
  • date_end: The timestamp marking the end of the range
  • time_zone: The time zone to use (IANA time zone name like “America/New_York”). If None, uses the system’s local time zone.
  • locale: The locale to use for formatting (BCP 47 language tag like “en-US”, “fr-FR”). If None, uses the system’s default locale.
  • config: The configuration object specifying which date/time components to include

Like format, this never fails: if the time zone, locale, or calendar cannot be resolved, it returns a human-readable, English-only message describing the error (via describe_error).

Example

import gleam/option
import gleam/time/timestamp
import intldate

let assert Ok(start) = timestamp.parse_rfc3339("2026-02-24T17:48:22+04:00")
let assert Ok(end) = timestamp.parse_rfc3339("2026-02-27T17:48:22+04:00")

intldate.format_range(
  date_start: start,
  date_end: end,
  time_zone: option.Some("Indian/Reunion"),
  locale: option.Some("fr-FR"),
  config: intldate.new()
    |> intldate.with_year(intldate.YearNumeric)
    |> intldate.with_month(intldate.MonthLong)
    |> intldate.with_day(intldate.DayNumeric),
)
// -> "24–27 février 2026"
pub fn format_range_to_parts(
  date_start date_start: timestamp.Timestamp,
  date_end date_end: timestamp.Timestamp,
  time_zone time_zone: option.Option(String),
  locale locale: option.Option(String),
  config config: DateTimeFormatConfig,
) -> List(DateTimeFormatPart)

Format a range and return the structured parts of the formatted output.

This mirrors Intl.DateTimeFormat.prototype.formatRangeToParts. Parts that come from the start date, end date, or shared range text are marked with source.

pub fn format_to_parts(
  date date: timestamp.Timestamp,
  time_zone time_zone: option.Option(String),
  locale locale: option.Option(String),
  config config: DateTimeFormatConfig,
) -> List(DateTimeFormatPart)

Format a timestamp and return the structured parts of the formatted output.

This mirrors Intl.DateTimeFormat.prototype.formatToParts.

pub fn new() -> DateTimeFormatConfig

Create a new date/time format configuration with all options unset.

Use the various with_* functions to customize the configuration.

Example

intldate.new()
  |> intldate.with_year(intldate.YearNumeric)
  |> intldate.with_month(intldate.MonthLong)
  |> intldate.with_day(intldate.DayNumeric)
pub fn resolved_options(
  time_zone time_zone: option.Option(String),
  locale locale: option.Option(String),
  config config: DateTimeFormatConfig,
) -> Result(DateTimeResolvedOptions, IntlError)

Return the options resolved by the date/time formatter.

This mirrors Intl.DateTimeFormat.prototype.resolvedOptions.

pub fn try_format(
  date date: timestamp.Timestamp,
  time_zone time_zone: option.Option(String),
  locale locale: option.Option(String),
  config config: DateTimeFormatConfig,
) -> Result(String, IntlError)

Format a timestamp according to the specified locale and configuration, returning a Result instead of falling back to an error message.

This is identical to format, except it lets you handle the IntlError yourself instead of getting a human-readable string when resolution fails.

Example

import gleam/option
import gleam/time/timestamp
import intldate

let assert Ok(date) = timestamp.parse_rfc3339("2026-02-24T17:48:22+04:00")

intldate.try_format(
  date:,
  time_zone: option.Some("Invalid/TimeZone"),
  locale: option.Some("fr-FR"),
  config: intldate.new()
    |> intldate.with_year(intldate.YearNumeric)
    |> intldate.with_month(intldate.MonthLong)
    |> intldate.with_day(intldate.DayNumeric),
)
// -> Error(intldate.FailedToLoadTimeZone("Invalid/TimeZone"))
pub fn try_format_range(
  date_start date_start: timestamp.Timestamp,
  date_end date_end: timestamp.Timestamp,
  time_zone time_zone: option.Option(String),
  locale locale: option.Option(String),
  config config: DateTimeFormatConfig,
) -> Result(String, IntlError)

Format a range between two timestamps according to the specified locale and configuration, returning a Result instead of falling back to an error message.

This is identical to format_range, except it lets you handle the IntlError yourself instead of getting a human-readable string when resolution fails.

pub fn try_format_range_to_parts(
  date_start date_start: timestamp.Timestamp,
  date_end date_end: timestamp.Timestamp,
  time_zone time_zone: option.Option(String),
  locale locale: option.Option(String),
  config config: DateTimeFormatConfig,
) -> Result(List(DateTimeFormatPart), IntlError)

Format a range to parts, returning a Result.

pub fn try_format_to_parts(
  date date: timestamp.Timestamp,
  time_zone time_zone: option.Option(String),
  locale locale: option.Option(String),
  config config: DateTimeFormatConfig,
) -> Result(List(DateTimeFormatPart), IntlError)

Format a timestamp to parts, returning a Result.

pub fn with_calendar(
  config: DateTimeFormatConfig,
  calendar: Calendar,
) -> DateTimeFormatConfig

Set the calendar system to use for date formatting.

pub fn with_day(
  config: DateTimeFormatConfig,
  day: Day,
) -> DateTimeFormatConfig

Set the representation of the day.

pub fn with_era(
  config: DateTimeFormatConfig,
  era: Era,
) -> DateTimeFormatConfig

Set the representation of the era.

pub fn with_format_matcher(
  config: DateTimeFormatConfig,
  format_matcher: FormatMatcher,
) -> DateTimeFormatConfig

Set the format matching algorithm.

The format matcher determines how the runtime selects the best format pattern based on the requested components and the locale.

pub fn with_hour(
  config: DateTimeFormatConfig,
  hour: Hour,
) -> DateTimeFormatConfig

Set the representation of the hour.

pub fn with_hour12(
  config: DateTimeFormatConfig,
  hour12: Bool,
) -> DateTimeFormatConfig

Set whether to use 12-hour time format.

  • True: Use 12-hour format with AM/PM (e.g., “5:48 PM”)
  • False: Use 24-hour format (e.g., “17:48”)

If not set, the hour format is determined by the locale.

pub fn with_locale_matcher(
  config: DateTimeFormatConfig,
  locale_matcher: LocaleMatcher,
) -> DateTimeFormatConfig

Set the locale matching algorithm.

The locale matcher determines how the runtime selects the best matching locale when the exact locale you requested isn’t available.

pub fn with_minute(
  config: DateTimeFormatConfig,
  minute: Minute,
) -> DateTimeFormatConfig

Set the representation of the minute.

pub fn with_month(
  config: DateTimeFormatConfig,
  month: Month,
) -> DateTimeFormatConfig

Set the representation of the month.

pub fn with_second(
  config: DateTimeFormatConfig,
  second: Second,
) -> DateTimeFormatConfig

Set the representation of the second.

pub fn with_time_zone_name(
  config: DateTimeFormatConfig,
  time_zone_name: TimeZoneName,
) -> DateTimeFormatConfig

Set the localized representation of the time zone name.

pub fn with_weekday(
  config: DateTimeFormatConfig,
  weekday: Weekday,
) -> DateTimeFormatConfig

Set the representation of the weekday.

pub fn with_year(
  config: DateTimeFormatConfig,
  year: Year,
) -> DateTimeFormatConfig

Set the representation of the year.

Search Document