Date range - offset one day

Created on 5 February 2023, almost 2 years ago
Updated 1 December 2023, about 1 year ago

Problem/Motivation

If used daterange field.
We see one day offset at end date value.

Test: 02/02/2023 - 10:00 - 02/03/2023 - 11:00
Test2: 02/20/2023 - 08:00 - 02/22/2023 - 10:00

viz. calendar - daterange - offset.jpg

πŸ› Bug report
Status

Fixed

Version

2.0

Component

Code

Created by

πŸ‡¨πŸ‡ΏCzech Republic jaroslav červenΓ½

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

  • Issue created by @jaroslav červenΓ½
  • Status changed to Needs review almost 2 years ago
  • Thank you very much for reporting this issue.

    I do not reproduce it on 2.0.x though.

    See test in attached screenshot.

    Can you please try again using the dev branch?

    FYI I'm working on a new version and will publish a new release soon.

  • Status changed to Postponed: needs info over 1 year ago
  • Marking this issue as Postponed as I cannot reproduce it.

    Feel free to reopen it with further details if you encounter the same issue.

  • πŸ‡ΊπŸ‡¦Ukraine tfrajj

    Looks like the issue is reproducible when:

    1. Field settings Date type is All Day
    2. Storage timezone and user timezone are different
  • πŸ‡©πŸ‡°Denmark robotjox

    same problem for me. All day events using date range are offset by 2 hours.

  • Assigned to matthieuscarset
  • Status changed to Needs work over 1 year ago
  • Thanks for reporting the issue again.

    There is certainly something missing with the timezone when it comes to preprocessing the view results.

    Assigning this issue to me and working on it.

  • πŸ‡¨πŸ‡¦Canada sdsheridan Toronto

    This may be related. I'm using date range field, and it would appear that the calendar is using the underlying UTC times (as stored in the database for date range values), and not converting them to the timezone selected for the calendar (specifically set to Toronto), not to the site's time (also Toronto) in the absence of the calendar's timezone, nor the user's timezone (also set to Toronto). So looks to me like the module is missing some time-zone adjustment for the start and end time values.

    Not sure where this is best remedied, as it seems to be affecting both how the span box is drawn, as well as the title attribute of the node title link (both using the UTC dates).

    However, the hierarchy should probably be something like:

    if ( calendar timezone is set ) {
      adjust dates based on calendar timezone offset;
    }
    elseif ( user timezone is set ) {
      adjust dates based on user's timezone offset;
    }
    elseif ( site timezone is set ) {
      adjust dates based on site's timezone offset;
    }
    

    shawn

  • πŸ‡¨πŸ‡¦Canada sdsheridan Toronto

    Just following up, looks like there might be three places that need adjustments:

    1. You might want to create a method in class CalendarViewBase that established the timezone to use as per the above.
    2. Use that method in function getRowValues when setting the $values{'title'] at the end of the function to pass to the $this->dateFormatter->format(...) calls.
    3. Looks like the last spot might be the populateCalendar method, where the computation of $start_day and $end_day would need to be adjusted for the same timezone offset as above.

    Hope that helps!

    shawn

  • πŸ‡¨πŸ‡¦Canada sdsheridan Toronto

    So as a follow up to my follow-up, I tried the above, and for some reason the dateFormatter->format(...) is ignoring the timezone / not making an adjustment for the timezone offset; not sure why. So I hacked this temporarily to add the offset to the timestamps in getRowValues(). The title and rendering are not showing correctly in the calendar with this hack.

    shawn

  • The title and rendering are not showing correctly in the calendar with this hack.

    Did you mean title and rendering are now showing correctly? If yes, could you please share your diff?

  • πŸ‡¨πŸ‡¦Canada sdsheridan Toronto

    Whoops! Yes, that should have been "...are now showing correctly...".

    I'll try to generate a diff, but in the meantime, here's what I did (both in src/Plugin/views/style/CalendarViewBase.php):
    1. Created a new helper function getTImeZone that i placed right before getRowValues:

      /**
       * Helper function to determine what timezone to use if formatting and start-
       * and end-date rendering determination.
       *
       * @param EntityField $field The date field being used.
       * @return string The timezone string.
       */
      public function getTimeZone(EntityField $field) {
        $timezone = 'UTC';
        if ( !empty($field->options['settings']['timezone_override']) ) {
          $timezone = $field->options['settings']['timezone_override'];
        }
        elseif ( ( $user_timezone = \Drupal::currentUser()->getTimeZone() ) && !empty($user_timezone) ) {
          $timezone = $user_timezone;
        }
        elseif ( ( $system_timezone = \Drupal::config('system.date')->get('timezone')['default'] ) && !empty($system_timezone) ) {
          $timezone = $system_timezone;
        }
        $tz = new \DateTimeZone($timezone);
        $time_now = new \DateTime('now', $tz);
        $offset = $tz->getOffset($time_now);
    
        return ['timezone' => $timezone, 'offset' => $offset];
      }
    
    

    2. Modified the getRowValues function to use the new timezone function as follows:

      /**
       * Get the value out of a view Result for a given date field.
       *
       * @param \Drupal\views\ResultRow $result
       *   A given view result.
       * @param \Drupal\views\Plugin\views\field\EntityField $field
       *   A given date field.
       *
       * @return array
       *   Either the timestamp or nothing.
       */
      public function getRowValues(ResultRow $row, EntityField $field) {
        $delta = 0;
        if ($delta_field = $field->aliases['delta'] ?? NULL) {
          $delta = $row->{$delta_field} ?? 0;
        }
    
        // Get the result we need from the entity.
        $this->view->row_index = $row->index ?? 0;
        $items = $field->getItems($row) ?? [];
        $item = $items[$delta]['raw'] ?? $items[0]['raw'] ?? NULL;
        $values = $item instanceof FieldItemInterface ? $item->getValue() : [];
        unset($this->view->row_index);
    
        // Skip empty fields.
        if (empty($values) || empty($values['value'])) {
          return [];
        }
    
        $timezone = $this->getTimeZone($field); // PATCHED to adjust timezone.
    
        // Make sure values are timestamps.
        $values['value'] = $this->ensureTimestampValue($values['value']) + $timezone['offset'];  // PATCHED to add timezone offset to UTC value.
        $values['end_value'] = ( $this->ensureTimestampValue($values['end_value'] ?? $values['value']) ) + $timezone['offset'];  // PATCHED to add timezone offset to UTC value.
    
        // Get first item value to reorder multiday events in cells.
        $all_values = $field->getValue($row);
        $all_values = \is_array($all_values) ? $all_values : [$all_values];
        $values['first_instance'] = reset($all_values);
    
        // Expose the date field if other modules need it in preprocess.
        $config = $field->configuration ?? [];
        $field_id = $config['field_name'] ?? $config['entity field'] ?? $config['id'] ?? NULL;
        $values['field'] = $field_id;
    
        // Get a unique identifier for this event.
        /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
        $entity = $field->getEntity($row);
        $key = $entity->getEntityTypeId() . ':' . $entity->id() . ':' . $field_id;
        $values['hash'] = md5($key . $delta);
    
        // Prepare a title by default (e.g. on hover).
        $start = $values['value'];
        $end = $values['end_value'] ?? $start;
        $title_string = $start && ($start !== $end) ? '@title from @start to @end' : '@field: @title @date';
        $values['title'] = $this->t($title_string, [
          '@field' => $field->label(),
          '@title' => $entity->label(),
          '@date' => $this->dateFormatter->format($start, 'long', '', $timezone['timezone']),    // PATCHED - even though passed the timezone to dateFormatter,
          '@start' => $this->dateFormatter->format($start, 'short', '', $timezone['timezone']),  // seemed to make no diff until adjusted for the offset above, 
          '@end' => $this->dateFormatter->format($end, 'short', '', $timezone['timezone']),      // so these could probably return to the way they were.
        ]);
    
        return $values;
      }
    
    

    Will try the dev version when i get a chance. Pushing to get this project to beta right now, so hopefully after that.

    shawn

  • πŸ‡ΊπŸ‡ΈUnited States hockey2112

    Any word on this? I am experiencing the same thing with multi-day fields stretching into an extra day.

  • πŸ‡ΊπŸ‡ΈUnited States jwineichen

    I've attempted to put this change into a patch. First time but I've tried to follow the patching documentation, so I think it's correct. It seems to be working on my local.

  • Just here to report that I have used the patch on #14 and it seems to correct the same issue for me.

  • @matthieuscarset opened merge request.
  • Status changed to Needs review over 1 year ago
  • Thanks a lot once again for reporting this issue and for providing patches.

    The fix is merged on 2.1.x.

    Marking this issue as NEED REVIEW so please, test the 2.1.x-dev branch and let me know if it fix your situations.

    I'll then release a new version.

    Looking forward to hearing from you.

  • Issue was unassigned.
  • I'm actually trying to troubleshoot an issue which I do not think is related to this patch. But since I was using 2.1.1 and updated with the patch to 2.1.3, I am not sure where the problem is coming from...

    When I am logged in, I do not see the events, but when I log out, everything is fine...

    I'll start by trying the dev branch and see if it resolves the issue.

  • Ok, so far I've tried the dev branch and the problem persists. I rolled back to 2.1.1 ensured the events were showing as expected, then updated to 2.1.2 and the events are gone while I'm logged in, and back when I'm logged out. If anyone has any ideas on what I can try, please let me know, but I'm going through the code diff and seeing if I can spot the issue.

    Also, I'm guessing this should be a new issue at this point since the patch seems to be unrelated.

  • Heh... don't mind me, I seem to have had some weird caching glitch somewhere... all of a sudden I was able to see the events again... All is good on the dev branch.

  • Status changed to Fixed over 1 year ago
  • Thank you for testing.

    Marking as fixed!

    Release coming soon.

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

  • Status changed to Fixed about 1 year ago
  • πŸ‡¨πŸ‡¦Canada sdsheridan Toronto

    It would seem we're not quite there yet. Just downloaded the latest release, and we have an offset problem in the bubble. There's an error in the logic in CalendarViewBase::getRowValues(). In particular, this bit of code:

        // Get offset to fix start/end datetime values.
        $timezone = $this->getTimezone($field);
        $same_tz = date_default_timezone_get() == $timezone;
        $offset = $same_tz ? 0 : $this->getTimezoneOffset('now', $timezone);
        $values['value'] += $offset;
        $values['end_value'] += $offset;
    

    If the site's timezone is anything other than UTC, and the field's timezone is the same as the site's timezone (which will often be the case), then the offset will be zero, and the start and end values will not be modified. However, the start and end values are in UTC (that's how they're stored in the DB), not in the site's or the field's timezones (unless they're UTC), and so the start and end values remain UTC, not those of the site or field's timezones.

    For example (i.e., how to replicate this), my php.ini timezone is America/Toronto, as is my site's timezone, and the calendar and field use the default timezone (i.e., no timezone specified, to they fall back to the site's timezone). So date_default_timezone_get() will return "America/Toronto", as will $this->getTimezone($field), resulting in a zero offset, and leaving the bubble/title start and end times in GMT, even though they should be adjusted for the offset to Toronto time.

    So, I think the test for same timezone should be removed, and the offset should simply be computed. Thus, the above code should be:

        // Get offset to fix start/end datetime values.
        $timezone = $this->getTimezone($field);
        $offset = $this->getTimezoneOffset('now', $timezone);
        $values['value'] += $offset;
        $values['end_value'] += $offset;
    

    What's interesting is that the text of the displayed calendar item does have the correct date/time value(s), including after this change. I've not taken the time to hunt down why that is, but I assume the rendering of the item is handling the timezone offset properly (views and some other module rendering the "When" field independent of this function call), and not using the values from this function call.

    shawn

  • Status changed to Active about 1 year ago
  • πŸ‡ΊπŸ‡ΈUnited States GBlicharz

    I tried the changes suggested in #25 πŸ› Date range - offset one day Needs review using the latest version of this module (v2.1.6), and it solved the offset by one day issue we were having. I have not written a patch before, and it's unclear to me how the suggested changes would work along side the changes in this branch (3339333).

  • πŸ‡¨πŸ‡¦Canada ciesinsg

    Is there any work around for this issue while we wait for a patch/update?

    Regarding #27 πŸ› Date range - offset one day Needs review , unfortunately I don't know how to make a patch for this either, but hopefully someone sees your comment and gives some input on how this can be done.

  • Status changed to Needs review about 1 year ago
  • Thanks a lot to you all for your contribution and efforts. Sorry for the inconvenience

    There is a new release 2.1.7 β†’ which should fix this bug.

    Please test/review and let me know!

  • Status changed to Active about 1 year ago
  • πŸ‡ΊπŸ‡ΈUnited States GBlicharz

    I confirmed that version 2.1.7 solved the issue we had been seeing. Thank you!

  • Status changed to Fixed about 1 year ago
  • Automatically closed - issue fixed for 2 weeks with no activity.

Production build 0.71.5 2024