As a partial solution to some problems with how repeating events report their date, I wrote some code for use in a CCK Computed Field that will calculate and display the next upcoming date-time. The thread is here. I'm posting this separately to generate a more understandable Title for people searching for this sort of thing. Also, I'm just learning PHP, so any review of the code would be appreciated.

Using Computed Field, the node view's section for fields can display something like:

Next upcoming date and time:
  Jan 27 2009 8:30pm
Location:
  Amina 's home
Contact:
  Amina
Date of first event in series, then repeats (See "Repeats" above):
  Oct 28 2008 8:30pm America/Toronto
  Repeats every month fourth Tuesday until Tue Oct 25 2011 except Tue Dec 23 2008, Tue Dec 22 2009

Note that I retained the standard repeated events datetime field at the end for now, because I can't hide it without also losing the "Repeats" tab. The funky Label for that field is a vain attempt at trying to explain why what follows is not the date of the event, but rather a past date of the first iteration of the repeating event.

Anyway, there are still problems associated with the fact that the "next upcoming date" doesn't update unless the node is edited and saved again, but that's a not uncommon problem with Computed Field if you want to use it in Views. More work has to be done to deal with that...

Comments

ericm’s picture

Title: Computed Field module for calculating next upcoming repeated event » Computed Field calculates upcoming repeated event date

Tidied the issue title.

ericm’s picture

Status: Active » Closed (fixed)

Here is the final code I came up with for displaying a Computed Field showing the next upcoming event date in the node display, as shown in the example at the top. I'll try to get around to writing this up for the Computed Field Code Snippets page. Note that this code has been tested against Drupal 6.8 and Date 6.x-2.0-rc6. Your mileage may vary.

COMPUTED CODE:

/** 
 * Returns a datetime string for a repeating event's next upcoming date, based on its rrule.
 * You MUST customize the $datetime_repeating value below to match your field's name.
 */
// IMPORTANT: Note that my repeating event nodes have a datetime field named 'field_datetime_repeating'
// but you should change the line below to your repeating event node's field name for this value. 
    $datetime_repeating = "field_datetime_repeating";

// The following line is needed for date_ical_parse_rrule() below.
require_once('./'. drupal_get_path('module', 'date_api') .'/date_api_ical.inc');
// ** Get the default timezone for the user if set, else the site's **
$timezone = date_default_timezone_name();
// ** Get "RRULE" **
// The following line retrieves a string value with "RRULE:" as prefix.
// e.g. "RRULE:FREQ=MONTHLY;INTERVAL=1;BYDAY=4TU;UNTIL=20111025T040000Z;WKST=SU"
$rrule = $node->{$datetime_repeating}[0]['rrule'];
// ** Set start date **
$start = date_now($timezone);
// ** Set end date and exceptions **
// End date should be the "UNTIL" value from the rrule for this event.
$parts = date_repeat_split_rrule($rrule);
$rrule_array = $parts[0];
$exceptions = $parts[1];
// If there's no UNTIL found, set it to an arbitrary date of one year from now.
if ($rrule_array['UNTIL'] == "") {
  $end = date_format_date(date_make_date(time() + 31622400, $timezone, DATE_UNIX), 'custom', 'Y-m-d H:i:s');
}
else {
  $end = date_format_date(date_ical_date($rrule_array['UNTIL']), 'custom', 'Y-m-d H:i:s');
}

// ** Finally, get the upcoming dates array and take the first upcoming date if any. **
$upcoming = date_repeat_calc($rrule, $start, $end, $exceptions, $timezone);
if (count($upcoming) < 2) {
//  No upcoming dates.
  $node_field[0]['value'] = "";
}
else {
// Retrieve the event's fromdate in the database's UTC timezone, adjust it to the local timezone,
// and prepare a version in datetime format
  $fromdate_text = $node->field_datetime_repeating[0]['value'];
  $fromdate = date_make_date($fromdate_text, 'UTC');
  date_timezone_set($fromdate, timezone_open($timezone));
  $fromdate_text = date_format_date($fromdate, 'custom', 'Y-m-d H:i:s');
// Set the upcoming event's time to the actual event's time, and pass on a datetime STR.
  $fromdate_array = explode(" ", $fromdate_text);
// Note that the first item in the resulting array is always the $start (as per _date_repeat_calc()
// in date/date_repeat/date_repeat_calc.inc), so take the second one.
  $nextdate_array = explode(" ", $upcoming[1]);
  $nextdatetime = $nextdate_array[0] . " " . $fromdate_array[1];
  $node_field[0]['value'] = $nextdatetime;
}

DISPLAY FORMAT:

if ($node_field_item['value'] == "") {
  $display = "No upcoming repeats";
}
else {
//  $display = date_format_date(date_make_date($node_field_item['value'], date_default_timezone_name()), 'small');
// customized format example below
  $display = date_format_date(date_make_date($node_field_item['value'], date_default_timezone_name()), 'custom', 'M j Y g:ia');
}

OTHER RELEVANT COMPUTED FIELD SETTINGS:

Number of values: 1
Display this field: checked
Store using the database settings below: UNCHECKED (important!)
ericm’s picture

Assigned: Unassigned » ericm

Ignore the note about "Anyway, there are still problems associated with the fact that the "next upcoming date" doesn't update..." in the top item. That was solved elsewhere (more fully described here).

ericm’s picture

Status: Closed (fixed) » Active

There seem to be some problems with the Computed Field code I gave earlier. A minor one is that it doesn't take into account the event's time properly, so on the day of the event but before the time of the event it reports the Next Event to be the one after that day, as if that day's event is already past. I know how to fix that (I haven't set the actual event time before the calculation, so it is probably using midnight).

The more confusing problem is with repeating events that are annual. When the event is set to repeat every 1 year, the Computed Field code is returning a day several days after the correct one. The Date module's "Repeats" tab is showing the correct repeating days, so it must be something in my code. I'll post a fix if (and when) I find one. Any ideas or suggestions would be welcome.

karens’s picture

Status: Active » Fixed

I just committed a new feature to -dev that should take care of this and more. The formatters now have settings so you can do choose to show or not show the repeat rule, display all repeats or the first repeat or the next repeat from today or whatever. You can also choose if you want to display both the from and to dates, or just the 'From' date or just the 'To' date.

If you use Advanced Help you'll see some popup help for this. The formatter settings are on the Display fields page and when you add Date fields to views.

I'm sure it will still need some tweaking to produce the right results everywhere, but so far in my testing it works to make this all very customizable.

If there are no immediate bugs, I'm planning to roll a new release with this in it.

ericm’s picture

That sounds terrific! A much better solution than mine, for sure.

Status: Fixed » Closed (fixed)

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

nrasmus’s picture

Version: 5.x-2.6 » 6.x-2.0-rc6
Status: Active » Closed (fixed)

Sorry for re-opening, but I'm hoping to get this to work on a 5.x install. I'm assuming that since views1 does not have a "Display fields" page, that the committed changes referenced in #5 is a 6.x only resolution to this--if I'm mistaken, I apologize (and hope someone will point me in the right direction).

@ #2, One thing to note, I believe you must also redefine the "field_datetime_repeating" field to your field name on line 41

$fromdate_text = $node->field_datetime_repeating[0]['value'];

That aside, it's not working correctly. When I do make that change, the next time appears correctly, but the date is displayed as +1 day from now for all events with no repeats (instead of the "No upcoming repeats"), and all events with repeat dates are +7 days. I'm assuming there are changes to some function(s) from 5.x to 6.x, but that's about as far as my personal expertise will carry me. Any ideas?

nrasmus’s picture

Version: 6.x-2.0-rc6 » 5.x-2.6
Status: Closed (fixed) » Active
arlinsandbulte’s picture

Version: 6.x-2.0-rc6 » 5.x-2.6
Status: Closed (fixed) » Closed (won't fix)

No features being added to 5.x-2.x...

webengr’s picture

Anyone have suggestions for solution #2 that was for drupal 6
to work with Drupal 7.x and DATE 7.x-2.10
the above did not work for that because of function changes going from drupal 6 to 7,
??? date_default_timezone_name(); is now date_default_timezone();
??? date_make_date() was replaced with new DateObject()
???