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:

MethodEffectDate example (en-GB)Time example
Short()Compact02/01/202615:04
Medium()Default2 Jan 202615:04:05
Long()Explicit2 January 202615:04:05 GMT (in winter) or 15:04:05 BST (in summer)
Full()Most verboseMonday, 2 January 202615: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:

LocaleShort dateTime format
en-GBDD/MM/YYYY24-hour
en-USMM/DD/YYYY12-hour AM/PM
de-DEDD.MM.YYYY24-hour
ja-JPYYYY/MM/DD24-hour
zh-CNYYYY/MM/DD24-hour

A single LF(t).Short() call renders the right format for whichever locale the request resolves to.

See also