Hugo 模板中的 time.Time.Year 方法:提取年份的完整实战指南
2026/9/19 17:17:20 网站建设 项目流程

Hugo 模板中的 time.Time.Year 方法:提取年份的完整实战指南

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

导读

在 Hugo 模板中,Year是作用于time.Time值的方法,用于返回该时间的年份(整数)。无论是基于页面前置元数据中的date渲染文章年份,还是根据当前时间生成版权年份,Year都是最基础、最常用的时间提取方法之一。本文以 Year.md 文档为核心,结合仓库中 tpl/time/time.go、tpl/time/init.go 等源码实现,系统讲解Year的签名、用法、时区语义及典型实战场景,帮助你彻底掌握在 Hugo 模板中提取年份的正确姿势。

方法概览

Year是 Go 标准库time.Time结构体自带的方法,Hugo 模板引擎将其直接暴露给模板开发者,无需任何参数:

项目说明
签名TIME.Year
返回类型int
是否接受参数
作用返回给定time.Time值的年份

由于该方法属于time.Time值本身,因此它只适用于模板中已经是time.Time类型的变量。如果你持有的是时间字符串,需要先用time.AsTime(或time函数)将其转换为time.Time才能调用.Year

基本用法:从时间字符串提取年份

Year文档中给出的示例是先通过time.AsTime将带时区偏移的 ISO 8601 字符串解析为time.Time,再调用.Year

{{ $t := time.AsTime "2023-01-27T23:44:58-08:00" }} {{ $t.Year }} → 2023

其中time.AsTime把"文本形式的时间表示转换为time.Time接口"(见 tpl/time/time.go 的源码注释与实现),解析成功后再由 Go 标准库的Year()方法返回年份整数。

除了通过time.AsTime显式解析,Hugo 还提供了等价写法——不带参数直接调用time函数时返回的是 time 命名空间;带 1 个参数时等价于调用AsTime。这一点在 tpl/time/init.go 的命名空间注册逻辑中清晰可见:case 1: return ctx.AsTime(args[0]),并且在AddMethodMapping中就有对应的验证用例:

{{ (time "2015-01-21").Year }} → 2015

因此以下两种写法结果完全相同:

{{ $t1 := time.AsTime "2023-01-27T23:44:58-08:00" }} {{ $t1.Year }} → 2023 {{ $t2 := time "2023-01-27T23:44:58-08:00" }} {{ $t2.Year }} → 2023

获取 time.Time 值的常见途径

Year能发挥作用的前提是模板中存在time.Time类型的变量。在 Hugo 站点中,常见的来源有以下几类:

1. 页面日期字段

Hugo 会解析页面前置元数据中的日期字段,并将其作为time.Time暴露给模板。在 hugolib/page__meta.go 中可以确认以下四个字段均返回time.Time

  • Date():页面发布日期
  • PublishDate():计划发布时间
  • Lastmod():最后修改时间
  • ExpiryDate():过期时间

因此在页面模板(如single.html)中可以这样使用:

<p>发布于 {{ .Date.Year }} 年</p> <p>最后更新于 {{ .Lastmod.Year }} 年</p>

前端元数据示例(content/posts/hello.md):

--- title: Hello Hugo date: 2023-01-27T23:44:58-08:00 lastmod: 2024-05-10T10:00:00+08:00 ---

渲染结果中.Date.Year2023.Lastmod.Year2024

2. 当前时间

通过time.Now获取当前本地时间(见 tpl/time/time.go 中的Now实现),常用于页脚版权年份:

© {{ time.Now.Year }} Your Name

3. Unix 时间戳转换

使用time.Unix可以将 Unix 时间戳转换为time.Time后再提取年份:

{{ $t := time.Unix 1696000000 }} {{ $t.Year }} → 2023

时区与偏移对 Year 的影响

Year返回的是time.Time在其所在时区/偏移下呈现的年份,因此时区会直接影响结果,尤其是跨年边界的时间。

time.AsTime支持第二个可选参数指定 IANA 时区名称。从 tpl/time/time.go 的实现可以看到,当传入第二个参数时,会通过time.LoadLocation加载对应时区;解析时若字符串本身携带 UTC 偏移(如-08:00),则偏移优先于时区生效。

{{ $t := time.AsTime "2023-01-27T23:44:58-08:00" }} {{ $t.Year }} → 2023
{{ $t := time.AsTime "2024-01-01T01:30:00" "America/New_York" }} {{ $t.Year }} → 2024

关于时区解析行为,tpl/time/time_test.go 中的TestTimeLocation提供了大量可验证的测试用例,可以总结出如下规则:

  • 字符串不含偏移时:空时区默认按 UTC 解析,如"2020-10-20"2020-10-20 00:00:00 +0000 UTC
  • 指定时区生效:"2020-10-20"配合America/New_York得到2020-10-20 00:00:00 -0400 EDT,并会随夏令时切换(EST/EDT);
  • 字符串含显式偏移时:偏移覆盖时区设置,例如"2020-09-23T20:33:44-0700"无论是否传入America/New_York,解析结果都保持-0700
  • 非法时区(如"invalid-timezone")或非法时间值会导致AsTime返回错误。

这解释了为什么文档示例"2023-01-27T23:44:58-08:00"提取出的年份是2023:该时间在-08:00偏移下仍然是 1 月 27 日,没有跨年。

源码视角:Year 是如何被模板调用的

在 Hugo 中,模板方法(methods)由tpl/time包统一注册。其调用链为:

  1. Hugo 构建站点时,tpl/time/init.go 的init()注册time命名空间,并根据站点语言配置(langs.GetTimeFormatterlangs.GetLocation)创建Namespace实例;
  2. 模板中书写time.AsTime "..."时,实际调用 Namespace.AsTime,内部委托给common/htime包的ToTimeInDefaultLocationE完成解析;
  3. 解析得到标准库time.Time后,模板变量即可调用$t.Year$t.Month等 Go 方法。

需要特别说明的是:.Year本身并非 Hugo 自定义函数,而是 Gotime.Time的内置方法,Hugo 通过反射将其暴露给模板。这一点也解释了它不接受参数、返回int的行为特征。Hugo 在 tpl/time/init.go 中专门为AsTime注册了验证用例{{ (time "2015-01-21").Year }}2015,从侧面印证了.Year是模板中可直接使用的标准方法。

与相邻时间方法配合使用

Year属于time.Time方法家族,在同目录文档 docs/content/en/methods/time 中,还包含MonthDayYearDayWeekdayHourMinuteSecond等方法。它们可以自由组合,完成对时间的精细拆解:

{{ $t := time.AsTime "2023-01-27T23:44:58-08:00" }} {{ $t.Year }} → 2023 (年份) {{ $t.YearDay }} → 27 (当年第几天,平年范围 [1,365],闰年 [1,366]) {{ $t.Month }} → January (月份,类型 time.Month) {{ $t.Month | int }} → 1 (月份转为整数) {{ $t.Day }} → 27 (当月第几天) {{ $t.Weekday }} → Friday (星期几)

注意:Month的返回类型是time.Month,如需整数需用int管道转换(参考 Month.md);而Year直接返回int,无需任何转换。

实战场景

场景一:按年份归档文章

在列表模板中,可以利用.Date.Year对文章做分组归档:

{{ range .Pages.GroupByDate "2006" }} <h2>{{ .Key }}</h2> <ul> {{ range .Pages }} <li><a href="{{ .RelPermalink }}">{{ .Title }}</a></li> {{ end }} </ul> {{ end }}

这里的GroupByDate "2006"使用了 Go 参考时间布局(2006代表四位年份),与.Date.Year表达的是同一维度——按年聚合。

场景二:跨年时间段过滤

借助.Date.Year做年份区间过滤,例如只展示本年度文章:

{{ $currentYear := time.Now.Year }} {{ range where .Site.RegularPages "Date.Year" $currentYear }} <a href="{{ .RelPermalink }}">{{ .Title }}</a> {{ end }}

场景三:页脚版权年份

组合time.Now.Year与建站年份,避免每年手动修改:

{{ $since := 2020 }} © {{ $since }}{{ if ne $since (time.Now.Year) }}–{{ time.Now.Year }}{{ end }}

注意事项与限制

  1. 必须作用于 time.TimeYear只接受time.Time值,直接对字符串调用会失败,需先经time.AsTimetime转换;
  2. 时区敏感:年份按time.Time所在时区/偏移计算,跨年边界的值在不同时区下可能得到不同年份,请确保解析时使用的时区符合业务预期;
  3. 年份范围:返回值为普通整数,适用于公元纪年场景;对极端历史日期(如公元前)没有特殊语义;
  4. Format的取舍:若只需要"四位年份"这种格式化输出,也可以直接用time.Format,但.Year得到的是可参与运算的int,更适合条件判断、算术与分组。

相关资源

  • 本文对应文档:docs/content/en/methods/time/Year.md
  • time 方法目录索引:docs/content/en/methods/time/_index.md
  • 实现源码:tpl/time/time.go、tpl/time/init.go
  • 单元测试:tpl/time/time_test.go
  • 页面日期字段定义:hugolib/page__meta.go

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

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

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

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

立即咨询