Skip to content

fix(apps-blog): emit JSON-LD dates as ISO date-times with a timezone - #638

Merged
aka-sacci-ccr merged 4 commits into
mainfrom
fix/blog-jsonld-datetime-tz
Oct 8, 2026
Merged

aka-sacci-ccr merged 4 commits into
mainfrom
fix/blog-jsonld-datetime-tz

Conversation

@aka-sacci-ccr

@aka-sacci-ccr aka-sacci-ccr commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

Summary

SeoBlogPost emits BlogPost.date verbatim as the BlogPosting's datePublished. That value is usually a bare YYYY-MM-DD (the admin's @format date picker), which Google's Rich Results Test flags as an invalid datetime with a missing timezone.

toBlogPosting (packages/apps-blog/src/utils/jsonLD.ts) now normalizes datePublished and dateModified through a new toISODateTime helper in utils/date.ts:

  • 2025-06-01 → 2025-06-01T08:00:00.000Z. A bare date has no time of day; 08:00 UTC rather than midnight keeps it on the same calendar day from UTC-08:00 to UTC+14:00, so search results in the Americas don't show the post a day early.
  • An offset-less date-time is pinned to UTC; one with an offset keeps its instant.
  • Parsing uses scheduledTime's strict ISO check. An impossible date such as 2024-02-31, or a non-ISO string, is dropped instead of emitted as invalid structured data. The Unix epoch is kept, not treated as a failure.

Same fix for the Deno app in deco-cx/apps: deco-cx/apps#1685

Test plan

  • bun run test in packages/apps-blog (165 passed, new cases in date.test.ts and seoSections.test.ts)
  • bun run typecheck in packages/apps-blog
  • biome check on the changed files
  • Rich Results Test on a blog post page after deploy

🤖 Generated with Claude Code


Summary by cubic

Fixes BlogPosting structured data so datePublished and dateModified are emitted as full ISO 8601 date-times with a timezone, satisfying Google's Rich Results Test.

  • Adds a toISODateTime helper: bare YYYY-MM-DD values are placed at 08:00 UTC so the calendar day stays the same from UTC-08:00 to UTC+14:00, offset-less date-times are pinned to UTC, and date-times with an offset keep their instant.
  • Parses through scheduledTime's strict ISO check, so impossible calendar dates (like 2024-02-31) and non-ISO strings are dropped instead of emitting invalid structured data, while the Unix epoch is still kept.

Written for commit 320f118. Summary will update on new commits.

View guided diff Turn on auto-fix

BlogPosting's datePublished/dateModified were emitted verbatim, so a
bare YYYY-MM-DD from the admin's date picker failed Google's Rich
Results Test (invalid datetime, missing timezone). Normalize them via
a new toISODateTime helper, pinned to UTC like dateToTime, and drop
values that can't be parsed.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Midnight UTC is the previous evening across the Americas, so search
results could show a post a day early. 08:00 UTC lands on the same
calendar day from UTC-08:00 to UTC+14:00.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
JonasJesus42
JonasJesus42 previously approved these changes Oct 8, 2026
decobot and others added 2 commits October 8, 2026 16:23
…heck

dateToTime is lenient: Date rolls an impossible 2024-02-31 over into
March, reads non-ISO strings in server-local time, and its 0-on-failure
sentinel dropped a valid Unix-epoch date. scheduledTime range-checks the
calendar fields and signals failure with null, so invalid dates are
omitted and the epoch survives.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
…zation side by side

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
@aka-sacci-ccr
aka-sacci-ccr merged commit 16441f9 into main Oct 8, 2026
1 check passed
@github-actions

github-actions Bot commented Oct 8, 2026

Copy link
Copy Markdown

🎉 This PR is included in version 7.77.3 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants