glintl

Format dates and times in many languages, on Erlang and JavaScript.

gleam add glintl gleam_time
import gleam/time/duration
import gleam/time/timestamp
import glintl
import glintl/locale/en_gb
import glintl/locale/fr

pub fn main() {
  let now = timestamp.system_time()
  let offset = duration.hours(1)

  glintl.date_time_formatter(en_gb.locale(), date: glintl.Long, time: glintl.Short)
  |> glintl.format(now, offset:)
  // -> "25 October 2026 at 23:40"

  glintl.date_formatter(fr.locale(), style: glintl.Full)
  |> glintl.format(now, offset:)
  // -> "dimanche 25 octobre 2026"

  glintl.time_formatter(en_gb.locale(), style: glintl.Short)
  |> glintl.format(now, offset:)
  // -> "23:40"
}

You should try to reuse formatters, as making one is expensive and does lookup work, so that formatting is quite cheap.

Styles

There are four styles, the same as dateStyle and timeStyle in JavaScript’s Intl.DateTimeFormat. In British English:

StyleDateTime
FullSunday, 25 October 202623:40:58 GMT+01:00
Long25 October 202623:40:58 GMT+1
Medium25 Oct 202623:40:58
Short25/10/202623:40

Locales

Locales are defined in their own modules, this makes it easier to load only as much as you need.

import glintl/locale/fr
import glintl/locale/ja

To pick one from a tag, such as an Accept-Language header, use glintl/locales:

import glintl/locales

locales.from_tag("en-GB")  // -> Ok(en_gb.locale())
locales.from_tag("en-XX")  // -> Ok(en.locale())
locales.from_tag("xx")     // -> Error(Nil)

Note that glintl/locales imports every locale, so use it only when the locale isn’t known until run time.

How it works

On Erlang, codegen/generate.ts writes ICU information to Erlang modules as literals, this lets BEAM share the ICU data between processes without ever copying or garbage collecting them. This saves memory usage and cpu time.

On JavaScript, Glintl simply defers to Intl.DateTimeFormat via Gleam’s FFI. Therefore no locale information from Glintl is included in a bundle.

Differences between targets

Output across the two targets can differ because Glintl on Erlang uses the ICU that glintl was generated while Glintl on JavaScript defers to the runtime. These differences usually manifest in small details like commas or spaces.

Limits

Contributing

These will need these commands in order to contribute:

# Install deps for the generator
bun install --cwd codegen

# Run a typecheck on the generator
bun check --cwd codegen

# Run the generator
bun codegen/generate.ts

# Run Gleam tests
gleam test --target erlang
gleam test --target javascript
✨ Search Document