Problem/Motivation

The timestamp passsed to augmenters is sometimes wrong.

Cause

In SmartDatePluginTrait, the correct way to get the timestamp is:

public function viewElements(FieldItemListInterface $items, $langcode, $format = '') {
  ...
  $start_ts = $end_ts = $item->date->getTimestamp();

This timestamp is accurate becaise $item->date uses the storage timezone.

But later on we have:

        // @todo examine why we aren't using the $start_ts and $end_ts that are
        // already normalized above.
        $this->augmentOutput($elements[$delta], $augmenters['instances'], $item->value, $item->end_value, $timezone, $delta);

protected function augmentOutput(array &$output, array $augmenters, $start_ts, $end_ts, $timezone, $delta, $type 
  ...
  if (!is_numeric($start_ts)) {
    $start_ts = strtotime($start_ts);
  }

The problem is that strtotime default to using the timezone defined by date_default_timezone_get() which may not be the storage timezone.

Proposed resolution

Use the normalized timestamps already created from the field item's date object .

Remaining tasks

User interface changes

API changes

Data model changes

Issue fork smart_date-3509465

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

jonathanshaw created an issue. See original summary.

jonathanshaw’s picture

The reason why this wasn't done previously is probably this code:

      // If only one of start and end are displayed, alter accordingly.
      if ($parts['start'] xor $parts['end']) {
        if (in_array('start', $parts)) {
          $end_ts = $start_ts;
        }
        else {
          $start_ts = $end_ts;
        }
      }

The code modifies the timestamps permanently, effecting all the subsequent contexts in which they are used.

Some of these contexts - like the augmenter - need the original stord timestamps, but some of them probably want these modified timestamps. In my fix here, I have passed the stored timestamps to the augmenter only. Figuring out which other contexts need the stored timestamps and which the modified timestamps is beyond me though, that needs deep understanding of this module.

Fortunately, we don't have to solve that here. What I've done in this MR is a step forward, even if there's more that could be done.

jonathanshaw’s picture

Status: Active » Needs review
mandclu’s picture

Status: Needs review » Needs work

@jonathanshaw I'm on board with passing the normalized $start_ts and $end_ts values into separate parameters so that they can be passed unaltered to the augmenters.

Doing a quick scan of the code, I do also see augmentOutput() called in a number of places we aren't touching here, including:
- SmartDateDailyRangeFormatter
- SmartDateRecurrenceFormatter
- SmartDateDurationFormatter (even though it is officially deprecated)
- SmartDateRecurTrait

Most of these are also using the $item value and end_value, so we should make sure all of them use normalized timestamps before we implement a type hint to enforce an expectation that the start and end passed in will be timestamps.

jonathanshaw’s picture

Status: Needs work » Needs review

SmartDateDurationFormatter already passes the timestamps.

As I uderstand it: SmartDateDailyRangeFormatter, SmartDateRecurrenceFormatter and SmartDateRecurTrait all seem to built of top of the smartdate field type, which stores timestamps not iso_8601 strings and so already passes timestamps to the augmenter. And as the files aren't opted in to strict types, we don't need to explcitly cast to integer.

So I think we are ok?

  • mandclu committed ed359e88 on 4.2.x authored by jonathanshaw
    Issue #3509465 by jonathanshaw, mandclu: Augmenters receive inaccurate...
mandclu’s picture

@jonathanshaw thank you for all your work on this. Merged in, and I will try to get a new release out shortly.

mandclu’s picture

Status: Needs review » Fixed

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.