这几天在给博客加几篇“歌名接龙体”的文章,比如:

  • 《我们的故事》(slug: 446)
  • 《晴天里的简单爱》(slug: 447)
  • 《K 歌之王》(slug: 448)

本地文件都在,draft: false,路径也都是 content/posts/*.md,按理说跑 hugo serve 的时候,在列表页和归档页里都应该能看到这三篇新文章。

但实际情况是:hugo serve 正常启动,其他文章都在,这三篇就是不出现,像是完全没被 Hugo 识别到一样。这篇算是整个排查过程的一个小记录,也顺便总结下 Hugo 里“未来文章 + 时区”的坑。


1. 现象:文件都在,但 hugo serve 里看不到文章

三篇文章的 frontmatter 大致是这样的:

---
title: "我们的故事"
categories: [ "音乐" ]
tags: [ "音乐" ]
draft: false
slug: "446"
date: "2026-03-12 20:08:00"
---

另外两篇只是标题、slug、时间有点差异:

slug: "447"
date: "2026-03-12 20:10:00"

slug: "448"
date: "2026-03-12 20:20:00"

构建的时间是本地(WSL)显示的:

date
Thu Mar 12 23:28:24 CST 2026

从“人类直觉”看:23:28 已经晚于 20:xx 了,怎么也不应该被当作未来文章。但 hugo serve 的页面上,就是看不到这三篇。


2. 第一反应:Hugo 把它们当成 future 了?

Hugo 提供了一个很有用的命令,可以列出“未来文章”:

hugo list future

输出直接把问题暴露了:

path,slug,title,date,expiryDate,publishDate,draft,permalink,kind,section
content/posts/448.md,448,K歌之王,2026-03-12T20:20:00Z,0001-01-01T00:00:00Z,2026-03-12T20:20:00Z,false,https://bianle.me/posts/448/,page,posts
content/posts/447.md,447,晴天里的简单爱,2026-03-12T20:10:00Z,0001-01-01T00:00:00Z,2026-03-12T20:10:00Z,false,https://bianle.me/posts/447/,page,posts
content/posts/446.md,446,我们的故事,2026-03-12T20:08:00Z,0001-01-01T00:00:00Z,2026-03-12T20:08:00Z,false,https://bianle.me/posts/446/,page,posts

注意上面时间的尾巴:T20:20:00ZT20:10:00ZT20:08:00Z这个 Z 表示的是 UTC 时间

换句话说,虽然我在东八区(CST)看是 23:28,但 Hugo 这边拿到的时间是:

  • 当前时间:2026-03-12 15:28:xx UTC
  • 文章时间:2026-03-12 20:08:00 / 20:10:00 / 20:20:00 UTC

在 UTC 视角下,这三篇当然还是“未来文章”,于是很自然地就被 Hugo 当成 future 给过滤掉了,最后在 hugo serve 和正式构建时都压根不会把它们生成出来,看起来就像“文件在仓库里,但项目里不存在”一样。


3. 结论:是 Hugo 的时区设置问题

问题的根源就是:Hugo 在处理日期时默认用的是 UTC,而我在 frontmatter 里写的是“本地时间”,没有带时区信息

比如:

date: "2026-03-12 20:08:00"

对于我来说,这是 “2026-03-12 20:08:00 CST(UTC+8)”;
但对 Hugo 来说,如果没有额外配置,它会把这当成 “2026-03-12 20:08:00 UTC” 来算。

因此,只要构建时间 < 文章的 UTC 时间,这篇文章就会出现在 hugo list future 里,并在正常构建时被过滤掉。


4. 解决方式:指定 timeZone + 视情况允许 future

4.1 在 Hugo 配置里指定时区(推荐)

hugo.yml 里增加(或确认已经存在):

timeZone: Asia/Shanghai

这样 Hugo 会按 Asia/Shanghai 时区来解析不带时区的 date 字段,就不会再出现“人类看起来不是未来、但 Hugo 眼里是未来”的情况。

改完之后,可以重新跑一下:

hugo list future

如果一切正常,这三篇文章就不会再出现在列表里了。

4.2 允许构建 future 文章(按需使用)

有时候你故意想把某些文章当成“未来投稿”,或者干脆不在意时间提前一点,可以在配置里允许构建 future 文章:

build:
  future: true

或者在构建命令里加参数:

hugo --buildFuture

这样即便 Hugo 认为某些文章是 future,也会照常生成,不会 404。
不过这个选项更像是兜底,根本原因还是要把时区和时间写准

4.3 在 frontmatter 里写带时区的时间(更严格)

如果想写得更明确一点,可以在 frontmatter 里直接写 ISO 8601 带时区的时间:

date: "2026-03-12T20:08:00+08:00"

这样无论 Hugo 用什么时区默认值,这个时间都表示“东八区的 20:08:00”,不会被误判。


5. 可以快速排查的命令小抄

之后再遇到“文章写了,在 hugo serve 里却看不到”的情况,可以直接按这个顺序排查:

  1. 看是不是 future 或 draft

    hugo list future
    hugo list drafts
    
  2. 确认访问路径

    对于 content/posts/446.mdslug: "446" 的文章,一般访问路径是:

    /posts/446/
    

    而不是 /446/

  3. 检查时区和 timeZone 配置

    • 运行 date 看构建机本地时间;

    • 运行 hugo list future 看 Hugo 眼里的时间(注意是否带 Z);

    • hugo.yml 里加上:

      timeZone: Asia/Shanghai
      
  4. 必要时允许 future

    build:
      future: true
    

    或者临时:

    hugo --buildFuture
    

6. 小结

这次的坑,本质上是:

本地时间是东八区,frontmatter 里也按东八区在写,但 Hugo 默认按 UTC 来理解这些时间,结果文章刚写完,在 Hugo 眼里还是 future,于是构建时直接被吃掉了。

解决方案很简单:

  • 明确告诉 Hugo:timeZone: Asia/Shanghai
  • 或者在需要时加上 build.future: true / --buildFuture
  • 更严谨一点的话,在 frontmatter 里用带时区的 ISO 时间。

记住一个命令就行:

hugo list future

以后只要文章“明明存在却消失不见”,先问问 Hugo:
在你眼里,我是不是还活在未来?