Error message

Deprecated function: implode(): Passing glue string after array is deprecated. Swap the parameters in drupal_get_feeds() (line 394 of /home1/tylerfra/public_html/includes/common.inc).

Drupal - Date Repeat Rule Change Theme of "Repeats every day until"

Category: 

In my use case, the most common date repeat rule used by authors is the "Repeats every day until". For example, an event spanning from October 2012 through April 2013, read something like this:

Repeats every day until Tue Apr 30 2013 .

Date is an awesome module, but this isn't an awesome way to show a date range. Let's change it to something like this instead:

October 5th, 2012 - April 30th, 2013

Looks better, eh? Charming, indeed.

So, how is it done? By implementing theme_date_repeat_display(), that's how. So inside your theme's template.php file:

/**
 * Implements theme_date_repeat_display().
 */
function MY_THEME_date_repeat_display(&$vars) {

  if (isset($vars['item']['rrule'])) {

    // Let's pull out the rrule properties. For example, take this:
    //   RRULE:FREQ=DAILY;INTERVAL=1;UNTIL=20130501T035959Z;WKST=SU
    // and turn it into:
    //   array(
    //     'FREQ' => 'DAILY',
    //     'INTERVAL' => '1' ,
    //     'UNTIL' => '20130501T035959Z',
    //     'WKST' => 'SU'
    //   );
    $rrule = array();
    $rules = explode(';', str_replace('RRULE:', '', $vars['item']['rrule']));
    foreach($rules as $rule) {
      $parts = explode('=', $rule);
      $key = $parts[0];
      $value = $parts[1];
      $rrule[$key] = $value;
    }

    // Now that we have our repeat rule, let's change the way it renders itself.
    
    // Change the 'Repeats every day until [date] .' display to our liking.
    if ($rrule['FREQ'] == 'DAILY' && $rrule['INTERVAL'] == 1) {
      $from = strtotime($vars['item']['value']);
      $to = strtotime($rrule['UNTIL']);
      $from_month = date('F', $from);
      $to_month = date('F', $to);
      $from_year = date('Y', $from);
      $to_year = date('Y', $to);
      $date = '';
      if ($from_year == $to_year) {
        // Same year.
        if ($from_month == $to_month) {
          // Same month.
          $date = date('F jS', $from) . ' - ' . date('jS, Y', $to);
        }
        else {
          // Different months.
          $date = date('F jS', $from) . ' - ' . date('F jS, Y', $to);  
        }
      }
      else {
        // Different year.
        $date = date('F jS, Y', $from) . ' - ' . date('F jS, Y', $to);
      }
      return '<div>' . $date . '</div>';
    }

  }

  // If we made it this far, then we assume that we didn't want to theme this
  // repeat rule in a custom way, so let's just render it normally.
  return theme_date_repeat_display($vars);
}

Flush Drupal's Theme Registry cache after adding this code to your template.php file. Now watch time fly by as your date repeat rule makes a little more sense, or so it seems.

Comments

Nice post!  Got me headed in the right direction for sure.  I ended up using the theme_preprocess_field() function so I could get rid of the default date or dates that display in addition to the text output by theme_date_repeat_display().

Here's what I came up with:


function addOrdinalNumberSuffix($num) {
    if (!in_array(($num % 100),array(11,12,13))){
      switch ($num % 10) {
        // Handle 1st, 2nd, 3rd
        case 1:  return $num.'st';
        case 2:  return $num.'nd';
        case 3:  return $num.'rd';
      }
    }
    return $num.'th';
}

function THEME_preprocess_field(&$variables) {
    if($variables['element']['#field_name'] == 'field_MY_DATE_FIELD') {
        if (isset($variables['element']['#items'][0]['rrule'])) {
            
            $rrule = array();
            $rules = explode(';', str_replace('RRULE:', '', $variables['element']['#items'][0]['rrule']));
            foreach($rules as $rule) {
              $parts = explode('=', $rule);
              $rrule[$parts[0]] = $parts[1];
            }
                    
            $from = strtotime($variables['element']['#items'][0]['value'].' UTC');
            if (isset($variables['element']['#items'][1]['value'])) {
                $seconddate = strtotime($variables['element']['#items'][1]['value'].' UTC');
            } else {
                $seconddate = strtotime($variables['element']['#items'][0]['value'].' UTC');
            }
            $to = strtotime($rrule['UNTIL']);
            $from_month = date('F', $from);
            $to_month = date('F', $to);
            $from_year = date('Y', $from);
            $to_year = date('Y', $to);
            $date = '';

        
            // DAILY display
            if ($rrule['FREQ'] == 'DAILY') {          
              if ($rrule['INTERVAL'] == 1 && !isset($rrule['BYDAY'])) {
                $date .= t('Every Day at @time',array('@time' => date('g:i A', $from)));
              }
              elseif ($rrule['INTERVAL'] > 1 && !isset($rrule['BYDAY'])) {
                $date .= t('Every @interval Days at @time',array('@interval' => $rrule['INTERVAL'], '@time' => date('g:i A', $from)));
              }
              else {
                $date .= t('Recurring Event');
              }
              // $variables['items'][0]['#markup'] = $date;
            }
            
            
            // WEEKLY display
            if ($rrule['FREQ'] == 'WEEKLY') {
              if (isset($rrule['BYDAY'])) {
                $weekday = date('l \a\t g:i A', $seconddate );
              }
              else {
                $weekday = date('l \a\t g:i A', $from);
              }
              
              if ($rrule['INTERVAL'] == 1) {
                $date .= t('Every @day, ',array('@day' => $weekday));
              }
              elseif ($rrule['INTERVAL'] == 2) {
                $date .= t('Every Other @day, ',array('@day' => $weekday));
              }
              else {
                $date .= t('Every @interval Weeks, @day, ',array('@interval' => $rrule['INTERVAL'], '@day' => $weekday));
              }
              
              if ($from_year == $to_year) {
                // Same year.
                if ($from_month == $to_month) {
                  // Same month.
                  $date .= date('F jS', $from) . ' - ' . date('jS, Y', $to);
                }
                else {
                  // Different months.
                  $date .= date('F jS', $from) . ' - ' . date('F jS, Y', $to);  
                }
              }
              else {
                // Different year.
                $date .= date('F jS, Y', $from) . ' - ' . date('F jS, Y', $to);
              }
              
            }
            
            // MONTHLY display
            if ($rrule['FREQ'] == 'MONTHLY') {
                
              if (isset($rrule['BYMONTHDAY']) && $rrule['INTERVAL'] == 1) {
                $date .= t('Monthly on the @day',array('@day' => addOrdinalNumberSuffix($rrule['BYMONTHDAY']) ) );
              }
              elseif (isset($rrule['BYMONTHDAY']) && $rrule['INTERVAL'] == 2) {
                $date .= t('Every Other Month on the @day',array('@day' => addOrdinalNumberSuffix($rrule['BYMONTHDAY']) ) );
              }
              
              if (isset($rrule['BYDAY'])) {
                $weekday = date('l', $seconddate );
                $time = date('g:i A', $from );
                $plusminus = substr($rrule['BYDAY'], 0, 1);
                $num = substr($rrule['BYDAY'], 1, 1);
                
                if ($plusminus.$num == '-1') {
                    $date .= t('Last @weekday of the Month',array('@weekday' => $weekday ) );
                }
                else {
                    $date .= t('@day @weekday of the Month',array('@day' => addOrdinalNumberSuffix($num),'@weekday' => $weekday ) );
                }    
                
              }
              
            }
            
            foreach ($variables['element']['#items'] as $item) {
                if (strtotime($item['value']) > strtotime('now')) {
                    $date .= '<br/>Next: '.date('F j - g:ia',strtotime($item['value'].' UTC'));
                    break;
                }        
            }
            
            if (!empty($date)) {
                $variables['items'][0]['#markup'] = $date;
            }
        
        }
    }
}

Thanks Tyler! You can also use theme_date_display_combination to determine how the repeat date display is used with the date.