/ AI Schema Fixes / AI Schema Dates

How to Fix AI Schema Date Errors

AI schema generators commonly produce three date problems: wrong format (not ISO 8601), missing timezone, and stale years from the LLM's training cutoff. These break Google Rich Results eligibility and confuse AI engines deciding content freshness. This guide covers the format, the override patterns, and the dateModified discipline.

1. ISO 8601 format

TypeFormatExample
Date onlyYYYY-MM-DD2026-05-18
Datetime UTCYYYY-MM-DDTHH:MM:SSZ2026-05-18T14:30:00Z
Datetime + offsetYYYY-MM-DDTHH:MM:SS±HH:MM2026-05-18T15:30:00+01:00
Datetime with millisYYYY-MM-DDTHH:MM:SS.sssZ2026-05-18T14:30:00.123Z

2. Bad patterns AI generators produce

Pattern 1: US-format dates

"datePublished": "05/18/2026"   ❌ MM/DD/YYYY
"datePublished": "18/05/2026"   ❌ DD/MM/YYYY
"datePublished": "May 18, 2026" ❌ written format

Pattern 2: Datetime without timezone

"datePublished": "2026-05-18T14:30:00"   ⚠️ ambiguous
<!-- Parser assumes user-local; unpredictable across users -->

Pattern 3: Training-cutoff stale year

"datePublished": "2024-05-18"   ❌ generator's training data is from 2024
<!-- Even if the page is 2026, the LLM defaulted to its cutoff year -->

Pattern 4: Inconsistent precision

"datePublished": "2026-05-18",
"dateModified": "2026-05-18T14:30:00Z"   ❌ mixed precision
<!-- Both fields should match precision: both date or both datetime -->

Pattern 5: Future dates

"datePublished": "2027-12-01"   ❌ scheduled date treated as published
<!-- Schema datePublished is when it became publicly available, not authored -->

3. The correct pattern

{
  "@type": "Article",
  "headline": "How to choose a CRM",
  "datePublished": "2026-01-15T09:00:00Z",
  "dateModified": "2026-04-22T14:30:00Z",
  "author": {
    "@type": "Person",
    "name": "Jane Baker"
  }
}

<!-- For an event scheduled in future -->
{
  "@type": "Event",
  "name": "Workshop",
  "startDate": "2026-09-15T10:00:00+01:00",
  "endDate": "2026-09-15T16:00:00+01:00"
}

4. Pass dates explicitly to the generator

Don't let the LLM guess from prose — feed it the real values:

// Bad: rely on LLM to extract from "Published last week"
const schema = await ai.generateSchema(htmlContent);

// Good: pass explicit dates from your CMS
const schema = await ai.generateSchema({
  content: htmlContent,
  metadata: {
    datePublished: post.publishedAt.toISOString(),  // ← from DB
    dateModified: post.updatedAt.toISOString(),     // ← from DB
    author: { name: post.author.name, url: post.author.profileUrl }
  }
});

// Generator must use the metadata, not infer from content

5. Override training-cutoff errors

If your generator can't be re-configured, post-process the output:

function correctSchemaDates(schema, actualPublished, actualModified) {
  function walk(obj) {
    if (typeof obj !== 'object' || obj === null) return;
    if (obj.datePublished) {
      obj.datePublished = actualPublished;  // ← always override
    }
    if (obj.dateModified) {
      obj.dateModified = actualModified;
    }
    for (const v of Object.values(obj)) {
      if (typeof v === 'object') walk(v);
    }
  }
  walk(schema);
  return schema;
}

// In your CMS publish pipeline
const generated = await ai.generateSchema(content);
const corrected = correctSchemaDates(generated, post.publishedAt, post.updatedAt);
embedInPage(corrected);

6. dateModified discipline

Set dateModified ONLY on genuine content change. Track in your CMS:

// On save
async function savePost(postId, newContent) {
  const old = await db.getPost(postId);
  const contentHash = hash(newContent);
  
  // Only update dateModified if content actually changed
  if (contentHash !== old.contentHash) {
    await db.updatePost(postId, {
      content: newContent,
      contentHash,
      dateModified: new Date()
    });
  }
  // Otherwise: still save (typo fix, image swap) but don't bump dateModified
}

7. Common date fields by schema type

Schema typeDate fields
Article / BlogPostingdatePublished, dateModified, dateCreated
EventstartDate, endDate, previousStartDate
Product / OfferpriceValidUntil, validFrom, validThrough
RecipedatePublished, dateModified
JobPostingdatePosted, validThrough
CoursestartDate, endDate, courseSchedule
ReviewdatePublished, dateCreated

8. Validate

Step 1
Schema.org validator
validator.schema.org flags date-format errors as warnings. Run after generation.
Step 2
Programmatic check
// ISO 8601 regex
const ISO8601 = /^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2}))?$/;

function validateSchemaDates(schema) {
  const errors = [];
  function walk(obj, path = '') {
    if (typeof obj !== 'object' || obj === null) return;
    for (const [k, v] of Object.entries(obj)) {
      if (k.match(/^(date|start|end|valid)[A-Z]/) && typeof v === 'string') {
        if (!ISO8601.test(v)) {
          errors.push(`${path}.${k}: not ISO 8601 "${v}"`);
        }
      }
      if (typeof v === 'object') walk(v, `${path}.${k}`);
    }
  }
  walk(schema);
  return errors;
}
💡 Stale dates from training cutoff are the silent killer — schema validates, looks correct in casual review, but AI engines see your "fresh" content as a year old and rank it accordingly. Always override datePublished and dateModified from your CMS truth, never trust the generator's inference.

🤖 Re-run AI Schema Generator

Validate dates in fresh output.

Run AI Schema Generator →
Related Guides: AI Schema Fixes  ·  Fix Hallucinations  ·  Fix Author Trust  ·  Fix Required Fields
💬 Got a problem?