Fixing Date Format Errors in AI-Generated Schema
Dates look like the easiest part of structured data, yet generated markup gets them wrong more often than almost anything else. A language model has no clock, learned from text written before a cutoff, and reads dates the way a person skimming a page would.
The result is US-style dates, missing time zones, a summer offset stamped on a January post, last year where this year belongs, or a dateModified that records the day you ran the generator. This guide explains each pattern, how to correct it, and how to stop generated dates going stale once they are live.
Why generated dates go wrong
Four habits of language models explain nearly every date problem in generated markup.
- No sense of today. A model does not know the current date unless it is told. When it has to infer a year, it leans towards the years it saw most during training, which are always in the past. A post published this spring can come back dated a year or two earlier.
- Reading dates as prose. "Updated last Tuesday", "Posted 3 weeks ago" and "Spring 2026" are meaningful to a reader but give the model nothing exact. It either guesses a day or copies the phrase into the markup as text.
- Mixed conventions. Training text is full of American dates. A page that says 04/05/2026 means 4 May to a UK reader, and 5 April to much of what the model has read.
- The generation day as a default. If the model or a script around it fills
dateModifiedwith "now", every page appears to have been updated on the day you generated its markup, whether or not the content changed.
Each of these produces a date that may be valid in format but wrong in fact, which is why the checks below compare values with your CMS rather than only running a validator.
The format schema.org and Google expect
Date properties such as datePublished, dateModified, uploadDate
and startDate take an ISO 8601 value. There are two shapes you will use, and one variant
of the second.
| Shape | Pattern | Example | Use it for |
|---|---|---|---|
| Date only | YYYY-MM-DD | 2026-03-14 | Birth dates, founding dates, a day-long event with no set start time |
| Date and time with offset | YYYY-MM-DDThh:mm:ss+hh:mm | 2026-03-14T10:30:00+00:00 | Publication and update dates, events, video uploads |
| Date and time in UTC | YYYY-MM-DDThh:mm:ssZ | 2026-03-14T10:30:00Z | The same, when your system stores times in UTC |
Google's Article documentation recommends including time zone information in datePublished
and dateModified; without it, Google falls back to the time zone Googlebot uses, which may
shift your date by a day around midnight. For events, a start time without an offset is ambiguous for
anyone searching from another zone.
What generated markup produces instead
| Generated value | Problem | Corrected |
|---|---|---|
"14/03/2026" | Slash format, not ISO 8601; ambiguous between day-first and month-first | "2026-03-14" |
"March 14, 2026" | Written date; parsers may reject or misread it | "2026-03-14" |
"2026-03-14 10:30" | Space instead of T, no seconds, no offset | "2026-03-14T10:30:00+00:00" |
"2026-03-14T10:30:00" | No offset, so the moment is unclear | "2026-03-14T10:30:00+00:00" |
"2026-3-4" | Month and day need two digits | "2026-03-04" |
"last week" | Relative text, not a date | The real date from your CMS |
"2026" in datePublished | A bare year is valid ISO 8601 but too vague for publication dates | The full date and time |
The UK offset trap
This one catches UK sites in particular. The UK uses Greenwich Mean Time, offset +00:00,
in winter, and British Summer Time, offset +01:00, from the last Sunday in March to the
last Sunday in October. The right offset depends on the date being described, not on the date you generate
the markup.
A model told the site is in the UK, or copying an offset it saw elsewhere on the page, will often apply one offset to every date. That gives results like this:
"datePublished": "2026-01-12T09:00:00+01:00" wrong: January is GMT
"datePublished": "2026-01-12T09:00:00+00:00" right
"dateModified": "2026-07-03T16:20:00+00:00" wrong if the edit was at 16:20 local time
"dateModified": "2026-07-03T16:20:00+01:00" right
A wrong offset moves the moment by an hour. That rarely matters for an article, but it changes the start time of an event shown in search, and a post published just after midnight can appear to have been published the previous day.
Z.
2026-07-03T15:20:00Z is exactly the same moment as 2026-07-03T16:20:00+01:00.
What matters is that the value describes the right moment, not which form you choose.Events that straddle a clock change need each date given its own offset. A course that starts on a
Saturday in late October and ends the following weekend has a startDate in BST and an endDate
in GMT.
Dates that are well formed but wrong
Once every value is in ISO 8601, check that the dates make sense together and against the page. These are the logic errors generated markup produces most often.
- The training-cutoff year.
datePublisheda year or more earlier than the date shown on the page. Always compare the year, not only the day and month. - dateModified before datePublished. Usually the two were swapped, or the model read an "originally published" note as the update date.
- dateModified equal to the generation day. If every block you generated this week has this week's date, it is recording your tool run, not a content change.
- Visible date and markup disagree. Google advises showing a clear date on the page and keeping it consistent with the structured data. If the page says "Updated 2 June" and the markup says 9 June, fix whichever is wrong.
- A future datePublished. A scheduled post generated before it went live may carry its scheduled date, or a guessed date later than today. Publication dates should never be in the future.
- endDate before startDate on an Event or Course instance, often because the model read a date range in the day-first order and the end date in month-first order.
- Expired offers. A generated
priceValidUntilin the past tells search engines the price has lapsed. Leave the property out unless the page states when the price ends.
When to change dateModified
Update dateModified when the main content changes in a way a reader would care about:
new information, corrected facts, a rewritten section. Do not change it for a typo, a new sidebar widget
or regenerated markup. Bumping the date without a real change does not make a page fresher in any useful
sense, and a date that moves every time you touch the template becomes meaningless to readers and search
engines alike.
The fix, step by step
Step 1
Find every date property in the block
Search the generated JSON-LD for properties that hold dates or times: datePublished,
dateModified, dateCreated, uploadDate, startDate,
endDate, datePosted, validThrough, priceValidUntil,
foundingDate and birthDate. Include nested objects such as offers and event
instances. Write them down with their current values so you can check each one, because generated blocks
often contain extra dates you did not ask for and would not otherwise notice.
Step 2
Take the real values from your CMS
Open the post, product or event in your CMS and note the actual published date, last updated date and any event times, including the time of day where the system records it. These values are the truth; whatever the model inferred from the page text is only a guess. If the page shows no date at all, decide whether it should, and do not keep a generated publication date you cannot confirm anywhere.
Step 3
Rewrite each value in ISO 8601
Replace
every date with the four-digit year, two-digit month and two-digit day separated by hyphens. For values
that include a time, add a capital T, then hours, minutes and seconds with colons, then
an offset such as +00:00 or a Z for UTC. Remove written dates, slash dates
and relative phrases entirely. Keep date-only values for things with no meaningful time, such as a founding
date.
Step 4
Apply the right UK offset for each date
For every value with a time, work out whether that particular date fell in British Summer
Time or Greenwich Mean Time. Dates between the last Sunday in March and the last Sunday in October take
+01:00; the rest take +00:00. Do not copy one offset across all dates in the
block. If your CMS stores times in UTC, you can instead give every value with a Z and no
conversion.
Step 5
Check the dates against each other
Confirm
that dateModified is the same as or later than datePublished, that no publication
date is in the future, that every endDate follows its startDate, and that the
year matches the page. Compare the dates with those shown to readers and correct whichever side is wrong.
Delete any priceValidUntil or validThrough that the page does not state, rather
than keeping a guessed expiry.
Step 6
Move dates out of the pasted snapshot
A
generated block pasted into a page is frozen: its dateModified will still show the old date
after your next edit. Where your platform allows it, keep the generated structure but output the date
properties from the template, using the post's own published and modified fields. If you cannot template
them, add checking the markup dates to your routine for every content update, then retest the live page.
Outputting dates from your platform
The most durable fix is to stop typing dates into markup at all. Keep the rest of the generated block, and fill the date properties from the same fields that drive the visible date.
WordPress
In a theme template, get_the_date( 'c' ) and get_the_modified_date( 'c' )
return ISO 8601 values with the site's offset applied for that date, so BST and GMT are handled for you,
provided the time zone in Settings, General is set to a city such as London rather than a fixed UTC offset.
Most SEO plugins already output these dates in their own Article markup, which is another reason not
to duplicate Article in a generated block.
"datePublished": <?php echo wp_json_encode( get_the_date( 'c' ) ); ?>,
"dateModified": <?php echo wp_json_encode( get_the_modified_date( 'c' ) ); ?>
Shopify
Liquid's date filter accepts strftime codes. For a blog article, {{ article.published_at | date: '%Y-%m-%dT%H:%M:%S%:z' }}
gives a value with an offset. Check the store's time zone in the admin settings first, because the output
uses it.
Custom sites and frameworks
In JavaScript, new Date(value).toISOString() gives a UTC value ending in Z,
which is valid and avoids offset arithmetic. In PHP, $date->format( DATE_ATOM ) on a
DateTime with the Europe/London zone gives the correct seasonal offset. In a static site
generator, most date helpers have an ISO format option; use the file's front matter dates, not the build
time, or every page will show the day of the last deploy.
dateModified with the current time at build will stamp every page with the deploy date.
That is the same mistake as the generator's "today" default, made by your own code.Type-specific date rules worth knowing
| Type | Date properties | Watch for |
|---|---|---|
| Article, BlogPosting, NewsArticle | datePublished, dateModified | Recommended rather than required by Google, but should always match the visible dates. |
| Event | startDate (required), endDate | Local start time
with the offset for the venue on that date. Postponed events keep the original date in previousStartDate. |
| VideoObject | uploadDate (required) | The date the video was first published, not the date the page was built. |
| JobPosting | datePosted (required), validThrough | Remove
or update listings once validThrough passes. |
| Product offers | priceValidUntil | Only when a sale end date is stated. Never a guess. |
| Recipe, Course | Durations such as cookTime | Not dates at all: these
use ISO 8601 durations such as PT45M or PT1H30M, never "45 minutes". |
Durations deserve a note because generators often mix them up with dates. A duration begins with P,
and anything under a day needs the T before hours and minutes: PT20M is twenty
minutes, while P20M means twenty months.
1. Why does the AI generator give my post the wrong year?
A language model has no built-in knowledge of today's date and learned from text written before its training cutoff. When the page does not state a full date clearly, or states it in a form the model misreads, it fills the gap with a year that feels likely, which tends to be one it saw often in training. The fix is to take the published and modified dates from your CMS and check the year on every generated block before publishing.
2. Do I have to include a time and time zone in datePublished?
A date on its own is valid ISO 8601 and will not break the markup, but Google recommends including time zone information for article dates. Without an offset, Google falls back to the time zone Googlebot uses, which can move a post published close to midnight onto the wrong day. Giving the full date and time with an offset, or in UTC with a Z, removes any doubt about the moment you mean and costs nothing.
3. Should UK sites use +00:00 or +01:00?
Both, depending on the date. The offset must match the date being described: +01:00 during British Summer Time, from the last Sunday in March to the last Sunday in October, and +00:00 for the rest of the year. A post published in January and updated in July needs a different offset on each date. If working that out is awkward, convert everything to UTC and end each value with Z, which is equally correct.
4. Is it a problem if dateModified is newer than the actual last edit?
It misleads readers and search engines about how current the content is. Google asks sites to update dateModified when the content has meaningfully changed, and says visible dates should agree with structured data. A generated block that records the day you ran the tool, or a template that stamps every page with the build time, makes the date meaningless. Set dateModified from the last genuine content update stored in your CMS instead.
5. Why are my dates wrong again after I edited the post?
The generated JSON-LD was pasted into the page as fixed text, so it does not change when the post does. Your CMS updated its own modified date and the visible date, but the markup still carries the values from the day it was generated. Either output the date properties from the template so they follow the post automatically, or make checking the markup part of every content edit. The first option is much more reliable over time.
6. How do I write an event that runs across the clock change?
Give each date its own correct offset. An event starting on a Saturday before the clocks go back in October and ending after it would have a startDate ending in +01:00 and an endDate ending in +00:00. Use the local time at the venue, since that is what attendees will see on the page. For online events aimed at several countries, you can state the times in UTC with a Z instead, and still show local times to readers.
7. The generator wrote cookTime as 30 minutes. Is that a date problem?
It is a closely related format problem. Properties such as cookTime, prepTime, totalTime and duration take an ISO 8601 duration rather than a date or plain text. Thirty minutes is written PT30M, and an hour and a half is PT1H30M. The T is essential for hours and minutes, because P30M means thirty months. Check that the duration matches what the recipe or course page actually states, and remove it if the page gives no time.
The AI Schema Generator reads your page content with an AI model, writes JSON-LD for the content type and validates it against schema.org and Google rich result criteria, ready for you to confirm the dates before publishing.
Open AI Schema Generator Fixes โ