Skip to content

Fix indexer state updated value not being parsable as a datetime (#38411)#40979

Open
lbajsarowicz wants to merge 2 commits into
magento:2.4-developfrom
lbajsarowicz:fix/38411-indexer-state-datetime
Open

Fix indexer state updated value not being parsable as a datetime (#38411)#40979
lbajsarowicz wants to merge 2 commits into
magento:2.4-developfrom
lbajsarowicz:fix/38411-indexer-state-datetime

Conversation

@lbajsarowicz

Copy link
Copy Markdown
Contributor

Description (*)

Magento\Indexer\Model\Indexer\State::beforeSave() and
Magento\Indexer\Model\Mview\View\State::beforeSave() set the updated
field to a raw Unix timestamp via time():

public function beforeSave()
{
    $this->setUpdated(time());
    return parent::beforeSave();
}

The updated column is a datetime, and the DB adapter formats the integer
on INSERT, so the persisted value is correct. However, the in-memory model
retains the raw integer after saving (Magento does not reload the entity after
save()).

Magento\Indexer\Model\Indexer::getLatestUpdated() then feeds that value
straight into a \DateTime constructor:

$indexerUpdatedDate = new \DateTime($this->getState()->getUpdated());
$viewUpdatedDate = new \DateTime($this->getView()->getUpdated());

When the state has been saved but not reloaded within the same request (e.g. by
third-party code, observers, or ESI blocks), getUpdated() returns the raw
integer, and new \DateTime("1783697110") throws:

Exception: Failed to parse time string (1783697110) at position 8 (1): Unexpected character

Fix

Store the value pre-formatted as Y-m-d H:i:s in both beforeSave() methods —
identical to what the DB adapter already persists — so the in-memory value is
consistent with the persisted one and remains parsable by \DateTime:

$this->setUpdated((new \DateTimeImmutable())->format('Y-m-d H:i:s'));

The persisted DB value is unchanged; only the in-memory representation is
corrected.

Related Pull Requests

None

Fixed Issues (*)

Fixes #38411

Manual testing scenarios (*)

  1. Load an indexer whose state has just been saved (without reloading it from
    the database), e.g.:
    $indexer = $objectManager->create(\Magento\Indexer\Model\Indexer::class);
    $indexer->load('customer_grid');
    $indexer->getState()->setStatus(\Magento\Framework\Indexer\StateInterface::STATUS_VALID)->save();
    $indexer->getLatestUpdated();
  2. Before the fix: getLatestUpdated() throws
    Failed to parse time string.
  3. After the fix: getLatestUpdated() returns a valid datetime string with
    no exception.

Questions or comments

The persisted database values are unaffected — the DB adapter already stored the
adapter-formatted datetime. This change only aligns the in-memory value with the
persisted one.

Contribution checklist (*)

  • Pull request has a meaningful description of its purpose
  • All commits are accompanied by meaningful commit messages
  • All new or changed code is covered with unit tests (regression tests added
    for both State models)
  • All automated tests passed successfully (unit, integration, static)

Indexer\Model\Indexer\State and Mview\View\State stored `updated` as a
raw Unix timestamp via time(). Indexer::getLatestUpdated() feeds that
value into new \DateTime(), which throws "Failed to parse time string"
when the state is read from memory before being reloaded from the DB.
Store the value pre-formatted as Y-m-d H:i:s, identical to what the DB
adapter already persists, so in-memory reads stay parsable.

Fixes magento#38411
@m2-assistant

m2-assistant Bot commented Jul 10, 2026

Copy link
Copy Markdown

Hi @lbajsarowicz. Thank you for your contribution!
Here are some useful tips on how you can test your changes using Magento test environment.
❗ Automated tests can be triggered manually with an appropriate comment:

  • @magento run all tests - run or re-run all required tests against the PR changes
  • @magento run <test-build(s)> - run or re-run specific test build(s)
    For example: @magento run Unit Tests

<test-build(s)> is a comma-separated list of build names.

Allowed build names are:
  1. Database Compare
  2. Functional Tests CE
  3. Functional Tests EE
  4. Functional Tests B2B
  5. Integration Tests
  6. Magento Health Index
  7. Sample Data Tests CE
  8. Sample Data Tests EE
  9. Sample Data Tests B2B
  10. Static Tests
  11. Unit Tests
  12. WebAPI Tests
  13. Semantic Version Checker

You can find more information about the builds here
ℹ️ Run only required test builds during development. Run all test builds before sending your pull request for review.


For more details, review the Code Contributions documentation.
Join Magento Community Engineering Slack and ask your questions in #github channel.

@lbajsarowicz

Copy link
Copy Markdown
Contributor Author

@magento run all tests

@lbajsarowicz

Copy link
Copy Markdown
Contributor Author

@magento run all tests

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Indexer - timestamp is passed to DateTime constructor

1 participant