文章 byline 写 “Published May 17, 2026”。view-source:JSON-LD 里 "datePublished": "2024-03-08"。Rich Results Test 通过(技术上合法),但 SERP 不显示带发布日期的 Article rich result。或者 SERP 显示的日期跟你的 byline 不一致。Google 用 datePublished 判断新鲜度、用 dateModified 在结果里显示 “Updated” 标签。两者跟可见 byline 不一致时,Google 哪个都不信,可能彻底压制 rich result。
本文讲日期为什么会漂移、怎么对齐、以及每次构建都 bump dateModified 的陷阱。
常见原因
按命中率从高到低。
1. datePublished 写死或取 build time
模板用 datePublished: new Date() 在构建时生成 JSON-LD,所有文章都显示今天的日期。或者写死成一个常量。
怎么判断:view-source 多篇文章。如果都共享同一个 datePublished(今天或固定值),就是模板。
2. dateModified 每次部署都更新
最常见的变体:dateModified: new Date().toISOString() 在构建时跑。你每周部署。所有文章看起来都是这周修改的。Google 能检测到这个模式,把日期信号打折。
怎么判断:对比你确定没改过的文章的 dateModified。都匹配最近部署日期就是这个 bug。
3. 时区导致 off-by-one 天
Frontmatter:publishedAt: 2026-05-17。模板:new Date('2026-05-17').toISOString() → UTC-8 用户看到 "2026-05-16T16:00:00Z"。可见 byline 是 “May 17”,JSON-LD 是 “May 16”。
怎么判断:ISO 日期串在 UTC 下的日期跟你时区下 byline 显示的日期不一样。
4. CMS 有两个日期字段、模板只用一个
CMS 有 firstPublished 和 lastEdited。模板只用 firstPublished 当 datePublished 和 dateModified,或反过来。
怎么判断:看模板的 JSON-LD 生成器。如果 datePublished 和 dateModified 都从同一个字段取,你永远拿不到正确的 “updated” 日期。
5. 迁移过的文章日期错了
CMS 迁移后,所有 datePublished 都被设成了迁移日期。原始发布日期丢失。
怎么判断:所有文章共享一个 datePublished = 你迁移的那一天。对照 git log 或老 CMS。
6. 可见 byline 读 dateModified、JSON-LD 读 datePublished(或反过来)
byline 写 “Updated May 22”。JSON-LD datePublished 是 May 17。两边各自都对,但读者只看到 “May 22”、Google 读到 “May 17” 当发布日。各自正确,整体不一致。
怎么判断:检查 byline,看它对应哪个 JSON-LD 字段。byline 写 “Published” 就应匹配 datePublished;“Updated” 就匹配 dateModified。
最短修复路径
第 1 步:建数据模型
每篇文章源里有两个独立日期:
---
publishedAt: 2024-03-08T00:00:00Z # 不变;不再改
modifiedAt: 2026-05-22T00:00:00Z # 只在有意义的编辑时改
---
ISO 8601 带显式时区(Z = UTC)。CMS、模板、byline、JSON-LD 统一一个时区。
第 2 步:修模板的 JSON-LD 生成器
---
const { article } = Astro.props;
const published = new Date(article.publishedAt).toISOString();
const modified = article.modifiedAt
? new Date(article.modifiedAt).toISOString()
: published; // fallback 回 published;不要回 build time
---
<script type="application/ld+json" set:html={JSON.stringify({
"@context": "https://schema.org",
"@type": "Article",
"datePublished": published,
"dateModified": modified,
// ...
})}></script>
绝对不要在构建时 new Date()。
第 3 步:byline 对齐
<p class="byline">
发布 {formatDate(article.publishedAt)}
{article.modifiedAt && article.modifiedAt > article.publishedAt && (
<span>• 更新于 {formatDate(article.modifiedAt)}</span>
)}
</p>
两个都显示,标清楚哪个是哪个。
第 4 步:定”有意义的编辑”规则
团队文档:
- 错别字 / 小措辞:不 bump
modifiedAt。 - 加/删章节、更新数据、修事实错误:bump
modifiedAt。 - 当新文重发:改
publishedAt,modifiedAt保持原样。
防止 modifiedAt 漂移。
第 5 步:从 git 历史回填错误日期
# 每篇文章找首次添加它的 commit
for f in src/content/articles/en/*.mdx; do
first_commit=$(git log --diff-filter=A --follow --format=%aI -- "$f" | tail -1)
echo -e "$f\t$first_commit"
done
当前 publishedAt 错误(比如等于迁移日期)的文章,用首 commit 日期回填。
第 6 步:CI 审日期
// scripts/check-dates.mjs
import fs from 'node:fs';
import matter from 'gray-matter';
const errors = [];
for (const file of fs.readdirSync('src/content/articles/en')) {
const { data } = matter(fs.readFileSync(`src/content/articles/en/${file}`, 'utf8'));
const p = new Date(data.publishedAt);
const m = data.modifiedAt ? new Date(data.modifiedAt) : null;
if (isNaN(p)) errors.push(`Invalid publishedAt: ${file}`);
if (m && isNaN(m)) errors.push(`Invalid modifiedAt: ${file}`);
if (m && m < p) errors.push(`modifiedAt before publishedAt: ${file}`);
if (m && Math.abs(m - p) < 60000) errors.push(`Suspicious: modifiedAt == publishedAt within minute: ${file}`);
}
if (errors.length) { console.error(errors.join('\n')); process.exit(1); }
第 7 步:重新请求收录
Search Console → URL Inspection 对几篇文章触发重抓。1-2 周内 Article rich result 应该重新出现。
哪些情况可能不是你操作错了
JSON-LD 矛盾时 Google 也可能从 URL 路径、正文、外部信号推断日期。你无法完全控制 SERP 显示哪个日期——只能控制你提供什么。
容易误判的情况
每次部署都 bump dateModified 想刷新鲜度。Google 能检测到这个模式(所有文章在同一天反复”修改”)并把日期信号整体打折。别玩这个。
预防建议
- 永远不要从 build time 设
dateModified,只在真实内容编辑时改。 - CMS / 模板 / byline / JSON-LD 一致用 UTC(或单一编辑部时区)。
- CI 校验断言
dateModified >= datePublished,两个都是有效 ISO 8601。 - 团队文档化”有意义编辑”规则。
- 回填老文章日期时,用 git history 作为原始发布日的可信源。
FAQ
dateModified能早于datePublished吗? 不能——非法,Google 会警告。- 修错别字要更新日期吗? 不要——只有改动信息的实质编辑才更新。
相关阅读
- 老文章不更新
- 结构化数据警告
- Last-Modified 响应头缺失
- 双语版本逐渐漂移
- 双语站 hreflang x-default 混乱
- 分享到 X/Twitter 不显示卡片图
- VideoObject Schema 没被 Search Console 识别
- Meta robots vs X-Robots-Tag——谁说了算
- 设了 noindex 但页面还在搜索结果里
- 改模板后结构化数据变无效:4 个原因 + 对症修复
- HowTo Schema 已被废弃但模板还在输出
- Product Schema 评论数与页面可见评论对不上
- Article Schema 缺少必填字段 author.name
- Sitemap lastmod 永远是今天,Google 不再信任
- JavaScript 动态设置的标题未被 Google 索引
- Title 标签与 H1 不一致导致 Google 改写