Why an Article's Created Date Can Lag Its Actual Publish Time by Hours

Look at the "created" date on a handful of consecutive articles from this site's automated pipeline, and you'd expect them to be scattered across a day — that's the whole point of scheduling posts hours apart instead of dumping them all at once. For three articles published during one run, they weren't. All three showed a created timestamp within minutes of each other, even though they'd gone live hours apart. The timestamps were lying about when the articles had actually appeared.

They weren't lying about when they were created, though — that part was accurate. They were created together, in one drafting session, then handed to Scheduler to go live one at a time later. The bug was in what "created" should have meant to a reader, versus what Drupal was actually recording.

Two different clocks, one field

Scheduler's article-type settings include a boolean called publish_touch. With it off — the default this site shipped with — a scheduled node keeps whatever created and changed values it had at draft time, permanently, even after cron flips it live. The API pipeline creates a node, sets a future publish_on, and Drupal stamps created at that moment: the instant the draft entered the system, not the instant a reader could see it. Hours later, Scheduler publishes it, and nothing updates that timestamp — the node has been sitting there unpublished the whole time, and Drupal has no separate concept of "the moment this specific one actually went live" unless something tells it to record one.

For a site that publishes on a fixed schedule and shows dates as part of its own credibility signal, that's a real problem, not a cosmetic one. A batch of five articles drafted in one evening session and scheduled to go out across the following two days would all display nearly the same "posted" date, undermining the entire reason for spreading them out in the first place.

The fix is the setting Scheduler already ships for exactly this: flip publish_touch to true in the article content type's third-party settings, and Scheduler updates both created and changed to the actual publish time when its cron job does the publishing.

Verifying it rather than trusting the setting name

I didn't want to assume a boolean called "touch" does exactly what it sounds like without checking, so I tested it the same way I'd tested the presave/Scheduler interaction the day before: created a real node with a publish_on a few minutes in the past, let it sit, then ran drush scheduler:cron and queried the row directly.

Before cron ran, node_field_data showed created and changed both set to the moment I'd made the API call — call it 09:06. After cron ran, both fields read 09:00 — the exact publish_on value, not the time cron itself happened to execute. Scheduler doesn't just bump the timestamp to "now" when it publishes; it sets it to the scheduled time specifically, so a node published a few minutes late by an infrequent cron run still shows the intended publish time, not the incidental moment a cron job happened to notice it was due.

The permission gate that made this a rebuild rather than a quick fix

Flipping the setting only fixes nodes published after the change. Three articles from earlier the same day had already gone live with the old, wrong timestamps, and the obvious next step — PATCH the created field on those three nodes back to their real publish times — hit the same wall as the status field does for this API account: Drupal gates direct writes to created behind the administer nodes permission, the same permission api_publisher is deliberately never granted, for the same reason it's never granted write access to status. A scoped account that could rewrite its own content's history on request is a meaningfully bigger liability than one that can't, regardless of how convenient it would be for exactly this kind of cleanup.

So the three already-published nodes got fixed with a direct SQL update against node_field_data, once, by hand, outside the API entirely — the correct tool for a one-time correction on data the automated account has no business touching, precisely because the same restriction that made the timestamp wrong in the first place is also what keeps that account from quietly rewriting dates on every future article whenever it feels like it. The five articles still scheduled at that point didn't need any manual intervention; they picked up the corrected behavior automatically the next time Scheduler's cron touched them.

What actually generalizes here

The interesting failure mode isn't "a setting had the wrong default." It's that a field named created quietly carries two different meanings — when a record entered the system, and when it became visible to anyone outside that system — and most of the time those two moments are close enough together that nobody notices they're different fields wearing one name. Scheduling breaks that assumption on purpose, by design, and any timestamp a reader actually sees needs to be checked against which of those two moments it's really recording, not assumed correct because the field sounds unambiguous.

Add new comment

Restricted HTML

  • Allowed HTML tags: <a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • Lines and paragraphs break automatically.
  • Web page addresses and email addresses turn into links automatically.