computed date property on a datetime field is unreliable and polluted by the field formatter if a user timezone is set

Created on 18 June 2023, over 1 year ago
Updated 20 June 2023, over 1 year ago

Problem/Motivation

If an entity has a datetime field with a time component, the 'date' property returns a DrupalDateTime object. This is handled by the DateTimeComputed class.

When an entity is first loaded, this returns a DrupalDateTime with the timezone set to UTC.

However, if the current user has a personal timezone set, viewing the field pollutes this value and subsequent accessing of it has its timezone set to the user timezone.

This does not occur if the user is set to UTC and the site is set to a specific timezone. This DOES occur if the user has a specific timezone and the site timezone is the same as this.

Steps to reproduce

1. Create a datetime field on a node type
2. Create a node of this type and set the field value
3. Run this code:

    $node = $this->entityTypeManager->getStorage('node')->load(NID);
    dsm($node->my_date_field->date->getPhpDateTime());
    $node->my_date_field->view();
    dsm($node->my_date_field->date->getPhpDateTime());

Both datetimes should be in UTC.

4. Set the user's timezone to something else.
5. Run the code again. The second dsm() produces a datetime in the user's timezone.

Proposed resolution

Data should not be changed by the act of viewing it!

Remaining tasks

User interface changes

API changes

Data model changes

Release notes snippet

🐛 Bug report
Status

Active

Version

10.1

Component
Datetime 

Last updated 2 days ago

Created by

🇬🇧United Kingdom joachim

Live updates comments and jobs are added and updated live.
  • Contributed project blocker

    It denotes an issue that prevents porting of a contributed project to the stable version of Drupal due to missing APIs, regressions, and so on.

Sign in to follow issues

Comments & Activities

  • Issue created by @joachim
  • 🇬🇧United Kingdom joachim

    This affects https://www.drupal.org/project/action_link , for example - outputting a date field action link in the same place as the controlled date field is rendered (such as in a view) makes the link broken, because it gets the wrong date value from the entity field.

  • 🇮🇳India yogen.prasad

    I debug this issue and this is the root cause for the issue:

    File: DateTimeFormatterBase.php

    protected function buildDateWithIsoAttribute(DrupalDateTime $date) {
      // Create the ISO date in Universal Time.
      $iso_date = $date->format("Y-m-d\TH:i:s") . 'Z';
    
      $this->setTimeZone($date);
    
      $build = [
        '#theme' => 'time',
        '#text' => $this->formatDate($date),
        '#attributes' => [
          'datetime' => $iso_date,
        ],
        '#cache' => [
          'contexts' => [
            'timezone',
          ],
        ],
      ];
    
      return $build;
    }
    

    here line $this->setTimeZone($date);
    is the reason for saving the invalid date.

  • 🇬🇧United Kingdom joachim

    Thanks!

    I can confirm that if I replace the two calls to setTimeZone() in DateTimeFormatterBase with:

        $clone = clone($date);
        $this->setTimeZone($clone);
    

    then the problem is fixed.

    I don't think that's the way to fix it though, as a child class might also call setTimeZone() and cause the same problem.

    We probably need to remove setTimeZone() and replace it with a method which returns a cloned date rather than modifies the original.

  • Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    18:16
    18:16
    Queueing
  • @yogenprasad opened merge request.
Production build 0.71.5 2024