Hugo time.Format 函数完全指南:日期时间格式化、时区与本地化实战
2026/9/19 7:58:12 网站建设 项目流程

Hugo time.Format 函数完全指南:日期时间格式化、时区与本地化实战

【免费下载链接】hugoThe world’s fastest framework for building websites.项目地址: https://gitcode.com/gh_mirrors/hu/hugo

Hugo 模板中的time.Format函数用于把time.Time值或可解析的日期/时间字符串,按照自定义布局或本地化标记格式化为字符串输出。本指南将围绕该函数在 Hugo 项目中的实际应用场景,完整讲解其基本用法、时区优先级、Go 参考时间布局、本地化令牌与源码级实现原理,帮助你在站点模板中精确控制日期时间的显示效果。

函数签名与别名

根据 docs/content/en/functions/time/Format.md 中的 front matter 定义:

  • 签名:time.Format LAYOUT INPUT
  • 返回类型:string
  • 别名:dateFormat

别名注册位于 tpl/time/init.go,模板中可直接使用dateFormat

{{ dateFormat "Monday, Jan 2, 2006" "2015-01-21" }} → Wednesday, Jan 21, 2015

该映射由ns.AddMethodMapping(ctx.Format, []string{"dateFormat"}, ...)注册,同时保留了time.Format的正式名称。

基本用法

配合 time.Time 值使用

先通过time.AsTime把字符串转换为time.Time,再交给time.Format

{{ $t := time.AsTime "2023-10-15T13:18:50-07:00" }} {{ time.Format "2 Jan 2006" $t }} → 15 Oct 2023

配合可解析的字符串使用

time.Format内部会先尝试把输入值转换为time.Time(见下文源码解析),因此可以直接传入字符串:

{{ $t := "15 Oct 2023" }} {{ time.Format "January 2, 2006" $t }} → October 15, 2023

管道写法

{{ .Date | time.Format "January 2, 2006" }}

Hugo 的页面变量(如.Date.Lastmod)本身就是time.Time值,可以直接传入。

可解析的日期/时间字符串格式

以下格式(摘自 docs/content/en/_common/parsable-date-time-strings.md)都可以直接作为time.Format的输入:

格式时区
2023-10-15T13:18:50-07:00America/Los_Angeles
2023-10-15T13:18:50-0700America/Los_Angeles
2023-10-15T13:18:50ZEtc/UTC
2023-10-15T13:18:50默认Etc/UTC
2023-10-15默认Etc/UTC
15 Oct 2023默认Etc/UTC

后三个示例没有完全限定时区,将默认使用Etc/UTC时区。

时区确定顺序

原文档明确指出,时区的确定遵循以下优先级:

  1. 日期/时间字符串中自带的时区偏移(如-07:00Z
  2. 项目配置中指定的timeZone
  3. Etc/UTC时区

在 Hugo 源码中,该配置字段定义于 config/allconfig/allconfig.go 的TimeZone string,并在 config/allconfig/allconfig.go 中传给每个语言配置。配置文件示例(hugo.toml):

timeZone = "America/Los_Angeles"

若模板中传入的时间字符串带有时区偏移,则偏移优先于配置;否则使用配置的timeZone;两者都没有时才回退到Etc/UTC

布局字符串(Layout string)

time.Format的布局基于 Go 的参考时间:

Mon Jan 2 15:04:05 MST 2006

布局组件(摘自 docs/content/en/_common/time-layout-string.md):

描述有效组件
"2006" "06"
"Jan" "January" "01" "1"
星期"Mon" "Monday"
日(月内)"2" "_2" "02"
日(年内)"__2" "002"
"15" "3" "03"
"4" "04"
"5" "05"
上午/下午标记"PM"
时区偏移"-0700" "-07:00" "-07" "-070000" "-07:00:00"

若希望 UTC 时区输出Z而非偏移量,可将布局中的符号替换为Z

描述有效组件
时区偏移(Z 形式)"Z0700" "Z07:00" "Z07" "Z070000" "Z07:00:00"

组合示例:

{{ $t := "2023-01-27T23:44:58-08:00" }} {{ $t = time.AsTime $t }} {{ $t = $t.Format "Jan 02, 2006 3:04 PM Z07:00" }} {{ $t }} → Jan 27, 2023 11:44 PM -08:00

时区缩写与时区偏移的区别

原文档特别强调了两点易混淆的概念:

  • 字符串如PSTCET不是时区,而是时区缩写(abbreviations)
  • 字符串如-07:00+01:00不是时区,而是时区偏移(offsets)
  • 时区是拥有相同本地时间的地理区域。例如PSTPDT(视夏令时而定)所对应的时区是America/Los_Angeles

本地化(Localization)

使用time.Format可以为当前语言和区域本地化time.Time值。有两种方式:

方式一:直接使用本地化令牌

{{ .Date | time.Format ":date_medium" }} → Jan 27, 2023

方式二:使用布局字符串

布局字符串同样支持本地化。原理是:Hugo 先把time.Time按布局格式化,再将英文的月份/星期名称替换为本地化名称(见下文源码解析)。

本地化令牌及示例结果

本地化为 en-US(美国英语):

令牌结果
:date_fullFriday, January 27, 2023
:date_longJanuary 27, 2023
:date_mediumJan 27, 2023
:date_short1/27/23
:time_full11:44:58 pm Pacific Standard Time
:time_long11:44:58 pm PST
:time_medium11:44:58 pm
:time_short11:44 pm

本地化为 de-DE(德语):

令牌结果
:date_fullFreitag, 27. Januar 2023
:date_long27. Januar 2023
:date_medium27.01.2023
:date_short27.01.23
:time_full23:44:58 Nordamerikanische Westküsten-Normalzeit
:time_long23:44:58 PST
:time_medium23:44:58
:time_short23:44

locale 配置与语言回退

日期、货币、数字和百分比的本地化由bep/golocales包执行。Hugo 使用locale配置确定区域设置,若未设置则回退到语言键本身,解析结果必须是该包支持的 locale(详见 docs/content/en/_common/functions/locales.md)。

源码级实现原理

Format 方法:先转换,后格式化

核心实现在 tpl/time/time.go:

func (ns *Namespace) Format(layout string, v any) (string, error) { t, err := htime.ToTimeInDefaultLocationE(v, ns.location) if err != nil { return "", err } return ns.timeFormatter.Format(t, layout), nil }

关键点:

  • 输入vany类型,统一经htime.ToTimeInDefaultLocationE转换为time.Time
  • 转换时使用ns.location(即项目配置的时区)作为默认位置,这正是"配置时区优先于Etc/UTC"的实现基础
  • 转换支持多种输入形态:AsTimeProvider(如 go-toml 的LocalDate/LocalDateTime)、time.Time(会先格式化为 RFC3339 再交给cast包)、以及普通字符串/时间戳

TimeFormatter:自定义布局与本地化替换

本地化替换逻辑位于 common/htime/time.go:

func (f TimeFormatter) Format(t time.Time, layout string) string { if layout == "" { return "" } if layout[0] == ':' { // It may be one of Hugo's custom layouts. switch strings.ToLower(layout[1:]) { case "date_full": return f.ltr.FormatDateFull(t) // ... date_long / date_medium / date_short // ... time_full / time_long / time_medium / time_short } } s := t.Format(layout) monthIdx := t.Month() - 1 dayIdx := t.Weekday() if strings.Contains(layout, "January") { s = strings.ReplaceAll(s, longMonthNames[monthIdx], f.ltr.MonthsWide()[monthIdx]) } else if strings.Contains(layout, "Jan") { s = strings.ReplaceAll(s, shortMonthNames[monthIdx], f.ltr.MonthsAbbreviated()[monthIdx]) } if strings.Contains(layout, "Monday") { s = strings.ReplaceAll(s, longDayNames[dayIdx], f.ltr.WeekdaysWide()[dayIdx]) } else if strings.Contains(layout, "Mon") { s = strings.ReplaceAll(s, shortDayNames[dayIdx], f.ltr.WeekdaysAbbreviated()[dayIdx]) } return s }

这段代码印证了两个实现事实:

  • :开头的布局被识别为 Hugo 自定义本地化令牌,直接调用bep/golocales翻译器的FormatDateFullFormatTimeShort等方法
  • 普通布局字符串先由 Go 标准库time.Format格式化,再把英文月份名(January/Jan)和星期名(Monday/Mon)替换为当前 locale 对应的翻译;空布局返回空字符串

Namespace 的构造依赖

time命名空间通过 tpl/time/time.go 的New构造,接收htime.TimeFormatter(携带 locale 翻译器)、*time.Location(默认时区)和deps.Deps,并使用dynacache缓存时区加载结果(/tmpl/time/in分区,ClearNever策略),用于time.In等函数。

测试验证

common/htime/time.go 中的英文名称切片与替换逻辑,在 tpl/time/time_test.go 中有完整测试覆盖,可验证以下行为:

  • 自定义布局与字符串输入:{"Monday, Jan 2, 2006", "2015-01-21", "Wednesday, Jan 21, 2015"}
  • 非日期布局字符串原样返回:{"This isn't a date layout string", "2015-01-21", "This isn't a date layout string"}
  • RFC3339 与 RFC1123 格式互转
  • 本地化令牌:{":date_medium", "2015-01-21", "Jan 21, 2015"}
  • 时区感知:使用America/Los_Angeles时,time.Format(":time_full", "2020-03-09T11:00:00")输出11:00:00 am Pacific Daylight Time(对应 Issue #9084)

实战组合示例

博客文章页面的日期展示

<time datetime="{{ .Date | time.Format "2006-01-02T15:04:05Z07:00" }}"> {{ .Date | time.Format "January 2, 2006" }} </time>

多语言站点按 locale 输出

{{ if eq site.Language.LanguageCode "de-DE" }} <p>{{ .Date | time.Format ":date_long" }}</p> {{ else }} <p>{{ .Date | time.Format "January 2, 2006" }}</p> {{ end }}

首页"最后更新时间"提示

<p>Last updated: {{ .Lastmod | time.Format "2 Jan 2006 15:04 MST" }}</p>

小结

time.Format是 Hugo 模板中处理日期时间输出的核心函数:它接受time.Time值或可解析字符串,遵循"字符串偏移 > 项目timeZone配置 >Etc/UTC"的时区优先级;布局基于 Go 参考时间Mon Jan 2 15:04:05 MST 2006;以:开头的本地化令牌(如:date_medium:time_full)可输出贴合当前 locale 的语言化结果。理解其源码实现(转换→格式化→本地化替换)后,你可以在多语言与多时区场景下精准掌控日期时间的呈现。

【免费下载链接】hugoThe world’s fastest framework for building websites.项目地址: https://gitcode.com/gh_mirrors/hu/hugo

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询