glintl
Format dates and times in many languages, on Erlang and JavaScript.
Glintl lazy-loads locales for performance. On Erlang it aims to have the same output as JavaScript’s Intl.DateTimeFormat.
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"
}
It is recommended to reuse formatters for performance, because making one is expensive and does lookup work.
Styles
| Style | Date | Time |
|---|---|---|
Full | Sunday, 25 October 2026 | 23:40:58 GMT+01:00 |
Long | 25 October 2026 | 23:40:58 GMT+1 |
Medium | 25 Oct 2026 | 23:40:58 |
Short | 25/10/2026 | 23:40 |
Locales
-
Import the ones you need:
import glintl/locale/ja. -
Pick one from a tag with
locales.from_tag("en-GB").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) -
glintl/localesimports every locale. Only use it if you don’t know the locale until run time.
Calendars
- Each locale uses its own calendar by default. Thai uses Buddhist.
- Pick another with
glintl.with_calendar(locale, glintl.Hebrew). - All of ICU’s calendars: Gregorian, ISO 8601, Buddhist, Japanese, Republic of China, Persian, Indian, Hebrew, Chinese, Dangi, Coptic, Ethiopic (2 eras), and 3 Islamic calendars.
How it works
On Erlang:
- Formats come from ICU when glintl is built, not when your app runs.
- Each locale is an Erlang module. It loads the first time you use it, and stays loaded.
- The data is shared by every process. It is never copied or garbage collected.
- Releases in “embedded mode” load every module at start-up instead.
On JavaScript:
- glintl calls
Intl.DateTimeFormat. - A locale is just its tag, so your bundle has no locale data.
Limits
- Today, time zones in Glintl are passed as offsets. You get
GMT+1, notBritish Summer Time. - Today, Glintl does not allow you to pick single fields like month and year only.
- On Erlang, calendars with their own months cover the years 1 to 4000. Other dates fall back to Gregorian.
Known differences
- Erlang vs JavaScript: Erlang uses the ICU in Bun on Linux. JavaScript uses your runtime’s ICU. Differences can exist, usually manifesting in small details like spaces and commas.
- ICU bugs glintl copies: ICU 78.3 puts Chinese New Year 2027 and 2030 a day off. JavaScript does the same.
- ICU bug glintl doesn’t copy yet: near AD 284 and AD 622, the Coptic and Islamic calendars can show the wrong year around midnight.
Contributing
bun install --cwd codegen
bun fmt --cwd codegen && bun lint --cwd codegen && bun check --cwd codegen
gleam test --target erlang
gleam test --target javascript
gleam run -m glintl_bench
bun codegen/conformance.ts 1000000
- The generator, JavaScript tests and conformance run need the Bun in
.bun-version, on Linux. CI does this. - On a Mac, run the generator in Docker. It takes about 10 minutes:
docker run --rm -v "$PWD":/repo -w /repo oven/bun:$(cat .bun-version) bun codegen/generate.ts
gleam format src test