0

I am importing events from an iCal feed and have managed to get everything working great except for events that take place all day. Currently they are coming in and defaulting to a xx/xx/xxxx 7:00pm to xx/xx +1/xxxx 7:00pm date when they should fall on the same day without a time. I've tried hardcoding 00:00:00 as the time but that get's ignored. I've also made sure that there are no default time settings on the field.

There is a checkbox for All Day but nothing seems to mark it as checked while I'm trying to create the node and it doesn't appear to be saved in the node object anywhere so not sure how I am suppose to set the checkbox while I'm creating the node.

Current code I am using while looping through each of the events in the feed:

// Use the UID to look up existing events. 
if(!in_array($uid, $uids)){

    if(strtotime($startDt->format ( 'm/d/Y h:ia' )) > strtotime("-1 month")){
        try {                   
            $node = new stdClass();
            $node->type = "calendar_event";
            $node->uid = 1;
            $node->language = 'en';
            $node->title = $eventName;
            $node->body['und'][0]['value'] = stripslashes($eventLocation);
            $node->body['und'][0]['format'] = 'full_html';
            $node->field_uid['und'][0]['value'] = $uid;
            $node->field_date['und'][0]['value'] = $startCom;
            $node->field_date['und'][0]['value2'] = $endCom;  

            // this doesn't work
            $node->field_date['und'][0]['all_day'] = 1; 

            $node->status = 1;          
            node_save($node);

            $values = array(
                'entity_type' => 'node',
                'entity' => $node->nid,
                'state' => OG_STATE_ACTIVE,
                'membership_type' => OG_MEMBERSHIP_TYPE_DEFAULT,
                'field_name' => 'og_group_ref'
            );
            og_group('node', $groupID, $values);
            $newCount++;
        } catch (Exception $e) {
            watchdog_exception('school_calendar', $e); 
        }
    }
} else { // uid existed, maybe we want to update if needed.
}
0

I found a "hacky" way of doing this. A couple things I noticed after investigating further is that the All Day single day events in Drupal are set to the same time on both the start and end dates. So first I changed the time of each date format to 05:00:00, just a random time but the same time for both.

This seemed to trigger the All Day checkbox which is great. But single day events were still showing as if they spanned over 2 days, not 1.

Upon further review of how iCal specifies formatting an all day single event, it wants the DTEND to actually be offset by 1 day, so I it comes in like this for a single all day event:

DTSTART 01/01/2018 DTEND 01/02/2018

So I added this to my DTEND handling:

if(isset($icsEvent['DTEND;VALUE=DATE'])){
    $end = $icsEvent['DTEND;VALUE=DATE'];
    $endDt = new DateTime ( $end );
    $difference = $startDt->diff($endDt);
    if($difference->days == 1){
        $endDt->modify('-1 day');   
    }
    $endCom = $endDt->format ( 'Y-m-d 05:00:00');
}

This modifies the end date to offset -1 day, so it ends up being the same day as the start. This is seems work great now for single all day events.

It appears though that I need to also apply this to spans of all day events, like a winter recess break that last all week. Even though it's supposed to be Monday - Friday, because of the offset in iCal, it's stretches to Saturday.

So probably instead of the difference check, I should just offset the endDt all the time by -1 day.

---- Update to Answer ---

The above worked great but I was finding some events that were supposed to be all day, showing as starting at 1am. Not sure why, the timezone looked right but some events started showing as this.

But if I set the date field to "no timezone conversion" first, then do the following with my start and end dates.

// Start Date
if(isset($icsEvent['DTSTART;VALUE=DATE'])){
    $start = $icsEvent['DTSTART;VALUE=DATE'];
    $startDt = new DateTime ($start);
    $startCom = $startDt->format ( 'Y-m-d 00:00:00' );
} else {
    $start = $icsEvent['DTSTART'];
    $UTC = new DateTimeZone("UTC");
    $newTZ = new DateTimeZone("America/New_York");
    $startDt = new DateTime ($start, $UTC );
    $startDt->setTimezone( $newTZ );
    $startCom = $startDt->format ( 'Y-m-d H:i:s' );
}

// End Date
if(isset($icsEvent['DTEND;VALUE=DATE'])){
    $end = $icsEvent['DTEND;VALUE=DATE'];
    $endDt = new DateTime ($end);
    $endDt->modify('-1 day');   
    $endCom = $endDt->format ( 'Y-m-d 00:00:00');
} elseif(isset($icsEvent['DTEND'])) {
    $end = $icsEvent ['DTEND'];
    $UTC = new DateTimeZone("UTC");
    $newTZ = new DateTimeZone("America/New_York");
    $endDt = new DateTime ( $end, $UTC );
    $endDt->setTimezone( $newTZ );
    $endCom = $endDt->format ( 'Y-m-d H:i:s' );
}

Basically if there is no time set, and it's just an event that spans as All Day, set no timezone and default to midnight. If it has a time, set the new york time zone.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.