Another year, another run-in. :)

I was told by a secretary today that the agenda block on the website was again showing the wrong dates for some of our events. I checked and, sure enough, some days were off by one. There was also the odd case where it appeared that the events of two days were incorrectly merged as one.

See attached photo (agenda-block-before.png).

  • The yellow events are from the first calendar listed in Agenda; it's DST offset in Google Calendar (GMT-6) matches the offset provided to the Date module in Drupal. As you can see, all-day events after the DST rollover (March 11th, where we switch to GMT-5) are early by one day.
  • The gray events are from the second calendar listed in Agenda; it's DST offset matches the first calendar. The events in this calendar appear correctly, but none are all-day events.
  • The UTC time and date shown in Agenda debug matches what is shown on my server.
  • In addition, there is a second odd problem that occurs on April 4th. The 'No School - Spring Vacation' event should actually occur on April 5th, with all subsequent events needing to be moved down a day.

Here is a parsed entry from Agenda debug:

    [title] => No School - Spring Vacation
    [where] => 
    [description] => 
    [start original] => 2012-04-05
    [start timestamp] => 1333602000
    [start date] => Wed, April 4th
    [start time] => 
    [end original] => 2012-04-06
    [end timestamp] => 1333688400
    [end date] => 
    [end time] => 
    [published] => Mon, September 19th
    [updated] => Thu, February 23rd
    [when] => 2012-04-04

Immediately, there is a problem. 'start original' and 'start date' show a mismatch; 'start original' is correct, and 'start date' is a day early. The first is generated, I believe, directly in PHP, whereas the second is generated using format_date.

Looking into the code in agenda.module, I noticed this section; it was added previously to fix the issue with DST times.

  // If the Date API is installed, we can do better at DST times
  if (module_exists('date_api')) {
    $start               = date_make_date($event['start timestamp'], NULL, DATE_UNIX);
    $event['start time'] = date_format_date($start, 'custom', $block->timeformat);

    $end                 = date_make_date($event['end timestamp'], NULL, DATE_UNIX);
    $event['end time']   = date_format_date($end, 'custom', $block->timeformat);
  } 

This solves the problems in relation to event times, but it doesn't solve the problem with event dates. Because $event['start date'] and $event['end date'] still being handled by format_date, it appears that they are not getting the proper matched DST offset applied. This appears to cause the issue where these all-day events are offset by a day, if the block is viewed before the DST change occurs, because the all-day events technically have a start time of midnight. My guess is that it also affects regular events but, as we don't have any that occur at midnight, it's unaffected by a shift from GMT-6 to GMT-5.

I modified the code as such:

  // If the Date API is installed, we can do better at DST times
  if (module_exists('date_api')) {
    $start               = date_make_date($event['start timestamp'], NULL, DATE_UNIX);
    $event['start time'] = date_format_date($start, 'custom', $block->timeformat);

    $end                 = date_make_date($event['end timestamp'], NULL, DATE_UNIX);
    $event['end time']   = date_format_date($end, 'custom', $block->timeformat);

  // timkedojeh: We can also do better with DST dates
    $event['when']       = date_format_date($start, 'custom', 'Y-m-d');
    $event['start date'] = date_format_date($start, 'custom', $block->customdate);
    $event['end date']   = date_format_date($end, 'custom', $block->customdate);
  } 

This patch fixed the debug as follows, but didn't fix the display of the dates in the Agenda block.

    [title] => No School - Spring Vacation
    [where] => 
    [description] => 
    [start original] => 2012-04-05
    [start timestamp] => 1333602000
    [start date] => Thu, April 5th
    [start time] => 
    [end original] => 2012-04-06
    [end timestamp] => 1333688400
    [end date] => 
    [end time] => 
    [published] => Mon, September 19th
    [updated] => Thu, February 23rd
    [when] => 2012-04-05

To fix the actual display on the Agenda block, I have to dive into agenda-block.tpl.php.

  <?php foreach ($events as $day): ?>
  <?php
  $date = format_date($day[0]['start timestamp'], $block->dateformat, $block->customdate);

  // Substitute today/yesterday/tomorrow
  if (isset($keyed_labels[$day[0]['when']])) {
    $date = $keyed_labels[$day[0]['when']];
  }
  ?>
  <p><?php echo $date; ?></p>

This is the code that creates the date headers for each day in the block. Again, it uses format_date to do the work; this can be done with better respect for DST by using date_format_date.

  <?php foreach ($events as $day): ?>
  <?php
  $date = format_date($day[0]['start timestamp'], $block->dateformat, $block->customdate);

  // timkedojeh: With date_api, we can do better with DST dates
  if (module_exists('date_api')) {
    $tkstartd = date_make_date ($day[0]['start timestamp'], NULL, DATE_UNIX);
    $date = date_format_date($tkstartd, 'custom', $block->customdate);
  }

  // Substitute today/yesterday/tomorrow
  if (isset($keyed_labels[$day[0]['when']])) {
    $date = $keyed_labels[$day[0]['when']];
  }
  ?>
  <p><?php echo $date; ?></p>

With this patch in place (after clearing cache in both Agenda and Drupal), the block displays properly. See attached photo (agenda-block-after.png).

I hope this puts an end to these pesky DST issues. :)

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

timkedojeh’s picture

That's odd; I tried attaching some pictures, but it wouldn't let me. Trying again.

timkedojeh’s picture

Version: 6.x-1.9 » 6.x-1.12

Correcting version number (we are using the latest recommended release for Drupal 6, 6.x-1.12).

kriscarp’s picture

I was having the same problem for our school events. I just installed the DST module and it seemed to fix the problem. http://drupal.org/project/dst

timkedojeh’s picture

I was having the same problem for our school events. I just installed the DST module and it seemed to fix the problem. http://drupal.org/project/dst

That does look like an acceptable solution, too, as the DST module modifies how format_date works (by applying PHP's timezone to it, it seems). However, in the interests of simplicity, it's probably for the best that either one or the other solution be applied.

Either:

  • use the Date module and make the changes noted, or
  • use the DST module and revert the earlier fix that added the date_api if statements.
timkedojeh’s picture

Issue summary: View changes

Forgot a line of modified code; $event['when'] = date_format_date