Bits of Simplicity

Time is hard

A common saying in the world of programming is "time is hard". You would think time would be easy, afterall we tell time everyday, but in reality time is very complex with many different variables. Here is an example I ran across recently.

If you work with WordPress for awhile there is a good chance you seen the Tribe Events plugin. It provides a events calender, and for the most part is a fantastic plugin, but it does have it's bugs. This particuler bug has to do with JSON-LD Schema data having the wrong date & time, which in turn means Goolge with display the wrong date. This is a reported bug, but Tribe doesn't seem to think it is a bug at all, but every site I have looked at all have the same issue. 

Before I can explain the issue lets talk a little bit about time. JSON-ld uses the ISO 8601 date format. Something like this: 2004-02-12T15:19:21+00:00

  • 2004-02-12 is the date (YYYY-DD-MM format)
  • T is a divider between date & time
  • 15:19:21 is the time (UTC/GMT)
  • +00:00 is the timezone offset

 

Using this format we can get a few things.

  1. Time in UTC - we can convert utc time to any timezone we want.
  2. Timezone offset - a "prefered" or originating time zone

 

So as an example:

2017-21-02T16:30:00-08:00

The UTC date time is 2/21/17 4:30 PM
The America Los Angeles time is 2/21/17 8:30 AM

If it was later in the day in America Los Angeles time, say 8:30 PM, it would be 4:30 AM the following day in UTC.

Alright now on to the issue.

Basically Tribe stores the UTC and originating timezone as different items in the database, and not as offsets.
When Tribe create the JSON-ld using ISO 8601 date format it uses the UTC value, but it doesn't apply the offset.

startDate: 2017-21-02T16:30:00-00:00

Just need to set the timezone to America Los Angeles. Sounds easy right? Well unfortunately not.
When you apply the offset using php it automatically converts the datetime object into the new timezone.

startDate: 2017-21-02T16:30:00+00:00

startDate: 2017-21-02T08:30:00-08:00

The UTC date time is 2/21/17 8:30 AM
The America Los Angeles time is 2/20/17 12:30 AM

But what we really want is

startDate: 2017-21-02T16:30:00-08:00

The UTC date time is 2/21/17 4:30 PM
The America Los Angeles time is 2/21/17 8:30 AM

Unfortanly there really isn't clean and easy way to do this in php, so this is what I came up with.

/* Tribe, modify json ld dates */
function tribe_modify_json_ld_event_dates ( $_data, $args, $event ) {

    $event_tz_string  = get_post_meta( $event->ID, '_EventTimezone', true );
    $tz_mode          = tribe_get_option( 'tribe_events_timezone_mode', 'event' );
    $tz_string        = $event_tz_string && $tz_mode === 'event' ? $event_tz_string : Tribe__Events__Timezones::wp_timezone_string();

    $offset = new DateTime();
    $offset = $offset->setTimezone( new DateTimeZone( $tz_string ) );
    $offset = $offset->format('P');

    $start = new DateTime($_data->startDate);
    if ($start->format('P') != $offset) {
        $_data->startDate = str_replace($start->format('P'), $offset, $_data->startDate);
    }

    $end = new DateTime($_data->endDate);
    if ($end->format('P') != $offset) {
        $_data->endDate = str_replace($end->format('P'), $offset, $_data->endDate);
    }
    return $_data;
}
add_filter( 'tribe_json_ld_event_object','tribe_modify_json_ld_event_dates', 10, 3 );

I am working on building a plugin that will fix the issue until Tribe creates a patch.