Schema.org dates must be ISO 8601 — anything else gets silently ignored by Google. A common mistake is templates that output localised date strings ("January 15, 2024") into JSON-LD instead of the YYYY-MM-DD format. Article freshness signals, event scheduling, offer validity all depend on parseable dates. This guide covers the date format, datePublished vs dateModified distinctions, time zone handling, and the CMS-level fixes that prevent recurrence.
Schema.org's Date and DateTime types both require ISO 8601:
// Date-only (no time) "2024-01-15" // Full timestamp with UTC "2024-01-15T14:30:00Z" // Full timestamp with time-zone offset "2024-01-15T14:30:00+00:00" "2024-01-15T09:30:00-05:00" // US Eastern // INVALID "January 15, 2024" "15/01/2024" "2024-1-15" // missing zero-padding "2024-01-15 14:30" // space instead of T "2024-01-15T14:30" // missing seconds and TZ
strftime("%B %d, %Y") into JSON"datePublished": "" — CMS field not setTemplates shouldn't format dates. Pass ISO strings from the data layer into the template as-is.
// functions.php or schema plugin
$schema = [
'@type' => 'Article',
'datePublished' => get_the_date('c', $post), // 'c' is ISO 8601
'dateModified' => get_the_modified_date('c', $post),
];
The 'c' format token outputs ISO 8601 with time zone offset.
{% assign date_iso = article.published_at | date: '%Y-%m-%dT%H:%M:%S%z' %}
"datePublished": "{{ date_iso }}"
// Use Date.toISOString() for UTC
{
"datePublished": article.publishedAt.toISOString() // 2024-01-15T14:30:00.000Z
}
// Or date-fns formatISO()
import { formatISO } from 'date-fns';
{
"datePublished": formatISO(article.publishedAt)
}
from datetime import datetime, timezone
article.published_at.isoformat() # 2024-01-15T14:30:00+00:00
# Django template filter
{{ article.published_at|date:"c" }}
dateModified to today on every page load to game "freshness". Google detects this and may apply penalties. Only update dateModified when content genuinely changes.Z. Display layer converts to user's local time.What you can't do: mix. Some pages UTC, others site-local, creates temporal inconsistency.
// Database: stored as UTC publishedAt: 2024-01-15T14:30:00Z // Schema output: UTC "datePublished": "2024-01-15T14:30:00Z" // HTML display: user's local time via JS <time datetime="2024-01-15T14:30:00Z">15 January 2024</time>
Similar rules apply to startDate, endDate (Event), priceValidUntil (Offer), validFrom (various).
// Event with start and end
{
"@type": "Event",
"startDate": "2025-06-15T19:00:00+01:00",
"endDate": "2025-06-15T22:00:00+01:00",
"eventStatus": "https://schema.org/EventScheduled"
}
// Offer with expiry
{
"@type": "Offer",
"price": "29.99",
"priceCurrency": "USD",
"priceValidUntil": "2025-12-31",
"availability": "https://schema.org/InStock"
}
Past priceValidUntil dates trigger Google warnings — "Offer expired". Update the date or remove the field for ongoing offers.