How to format dates and times for a locale
Two paths render dates and times in the active locale. Use TimeVar to embed a time.Time inside a translation string. Use LF (the locale-aware format builder) for standalone formatting outside a translation. Both honour the four standard styles. The styles are short, medium, long, and full. For binding non-temporal values see how to bind typed variables to translations.
Embed a time in a translation
For a sentence like "Event starts at ${date}", bind a time.Time with TimeVar:
{{ T("event.starts").TimeVar("date", state.EventAt) }}
TimeVar formats with the locale's medium style by default. For other styles, format outside the translation with LF and pass the result as a string:
{{ T("event.starts").StringVar("date", LF(state.EventAt).Long().DateOnly()) }}
LF returns a *FormatBuilder that implements fmt.Stringer, so the templater renders it inline.
Format a date or time standalone
When the locale-aware string is not embedded in a translation, use LF directly. From templates:
<time :datetime="state.EventAt.Format(time.RFC3339)">
{{ LF(state.EventAt).Long().DateOnly() }}
</time>
From Go:
formatted := r.LF(record.CreatedAt).Short().String()
Pick a formatting style
Each style produces a progressively more verbose rendering. The methods chain on the FormatBuilder:
| Method | Effect | Date example (en-GB) | Time example |
|---|---|---|---|
Short() | Compact | 02/01/2026 | 15:04 |
Medium() | Default | 2 Jan 2026 | 15:04:05 |
Long() | Explicit | 2 January 2026 | 15:04:05 GMT (in winter) or 15:04:05 BST (in summer) |
Full() | Most verbose | Monday, 2 January 2026 | 15:04:05 GMT (in winter) or 15:04:05 BST (in summer) |
The Long and Full styles render the time-zone abbreviation taken from the underlying time.Time value at render time. For UK times that resolves to GMT outside daylight-saving and BST during it. The abbreviation tracks the request, not the locale. Pin the rendering to UTC with UTC() if a stable suffix matters, or stick to Short or Medium where the abbreviation does not appear.
Filter the output to date or time only with DateOnly() and TimeOnly(). Convert to UTC before formatting with UTC():
r.LF(t).Short() // "02/01/2026 15:04"
r.LF(t).Long().DateOnly() // "2 January 2026"
r.LF(t).Full().TimeOnly() // "15:04:05 GMT" or "15:04:05 BST", per the value's zone
r.LF(t).UTC().Medium() // converts to UTC, then medium style
Compare locale-specific patterns
The same time.Time renders differently per locale without changes to the call site:
| Locale | Short date | Time format |
|---|---|---|
| en-GB | DD/MM/YYYY | 24-hour |
en-US | MM/DD/YYYY | 12-hour AM/PM |
| de-DE | DD.MM.YYYY | 24-hour |
| ja-JP | YYYY/MM/DD | 24-hour |
| zh-CN | YYYY/MM/DD | 24-hour |
A single LF(t).Short() call renders the right format for whichever locale the request resolves to.
See also
- i18n API reference for
LFand the full*Translationsurface. - How to bind typed variables to translations for the broader binder API.
- How to interpolate variables and reference other keys in translations for the placeholder syntax inside translation strings.
- About i18n for the design rationale behind locale-aware formatting.