Event calendar: repeating dates

We are working on a site featuring an event calendar. Each event is stored in a single page, containing a start and end date. Now we’d need the option to make events recuring in given intervals (every day, every week, every month, every year) with optional end date (“repeat until …”).

Are there any existing solutions to handle this scenario in Kirby?

Not that I know of. I had a project where I used a start date, end date and two additional fields: a select field for the interval, and a structure field for exceptions. Then calculated all events from this data.

I thought of something similar but it sounds computationally intensive for Kirby to get all dates related to – say – the current week. Or is this neglectable? We are not dealing with that many dates.

I would limit the end date, either through the date field itself or by setting your end date (if none is given) to let’s say 1 year or so in the future (or less, depending on interval). You can do this dynamically.

You can also cache your results, so I don’t see any problems.

1 Like

Okay, I think we just have to try this out and see how far it goes.

I actually need something like this too at the moment, but there is a small issue with repeating events. It works ok if the event is, for example, on the second Sunday of every month. That you can repeat easily but if the event is always the 13th day of the month, that gets harder. This year that day might be a Monday and the event should be on a Sunday. Being able to adjust the event to the 12th for that year is a tricky thing to implement.

We actually gave up and just use a structure field so that the specific dates can be picked manually for the next few years.

Haven’t had that case yet, so have to think first. But since I have to work, I don’t have time to think. Now that should make you think :wink:

Does it help to use PHPs DateInterval and DatePeriod?

Yep. DateInterval

Posting it for reference here, this example from the PHP docs might be helpful:


<?php

$begin = new DateTime( '2012-08-01' );
$end = new DateTime( '2012-08-31' );
$end = $end->modify( '+1 day' );

$interval = new DateInterval('P1D');
$daterange = new DatePeriod($begin, $interval ,$end);

foreach($daterange as $date){
    echo $date->format("Ymd") . "<br>";
}
?>
1 Like

May be you want to take the leap year into account…
But then note, that 2100 is NO leap year.

No, PHP’s DateTime class does that automatically.

Yes,

But our calculation, if we want to start on the same day of week, has to think of this.

If I run…

<?php

$begin = new DateTime( '2012-08-01' );
$end = new DateTime( '2022-08-31' );
// $end = $end->modify( '+1 day' );

$interval = new DateInterval('P1Y');
$daterange = new DatePeriod($begin, $interval ,$end);

foreach($daterange as $date){
    echo $date->format("l, Y-m-d") . "<br>";
}
?>

… I see, that the day of week for the first of august changes:

Wednesday, 2012-08-01
Thursday, 2013-08-01
Friday, 2014-08-01
Saturday, 2015-08-01
Monday, 2016-08-01
Tuesday, 2017-08-01
Wednesday, 2018-08-01
Thursday, 2019-08-01
Saturday, 2020-08-01
Sunday, 2021-08-01
Monday, 2022-08-01

and not everywhere by ONE day of week.

The result looks perfectly alright to me. I really don’t understand what your point it. It would be great if we could keep this thread clean.

@nilshoerrmann, this is one of the methods I used in my project (note Kirby 2 syntax, haven’t updated yet):

page::$methods['getEventDates'] = function($page) {

  $dates = [];

  $begin = new DateTime($page->startdate('Y-m-d'));
  $end = new DateTime($page->enddate('Y-m-d'));
  $end->modify('+1 day');
  $repeatOptions = ['1 day', '1 week', '2 weeks', '1 month'];
  $repeatValue = in_array($page->event_repeat(), $repeatOptions)? $page->event_repeat()->value(): '1 day';
  $interval = DateInterval::createFromDateString($repeatValue);

  // create an array of exceptions, these were entered manually into a structure field
  // to allow for public holidays, vacations etc.
  $exceptionDates = [];
  $exceptions = $page->exceptions()->toStructure();
  if($exceptions->count()) {
    $exceptionDates = $exceptions->pluck('date', ',');
  }
  // create a new DatePeriod object
  $period = new DatePeriod($begin, $interval, $end);

  //create date array for each child
  foreach ($period as $dt):
    $dates[] = $dt->getTimestamp();
  endforeach;
  // remove exceptions from the dates array
  $dates = array_diff($dates, $exceptionDates);

  return $dates;

}; 
1 Like

Thank you so much! That’s really helpful.

How would this work if the event started at say, 10pm one day but didn’t finish until 2am the next day, like a gig or something?. How would you repeat an event that does not start and end on the same day?