Broken ics output for All Day events
-
Here’s a php script I wrote and use that fixes “The Event Calendar”‘s objectively broken ics file output.
<?php
/*
This script takes the non standard "ics" format output by WordPress' "The Events Calendar" and fixes it and returns it in the actual standard ics format.
"The Events Calendar" is objectively incorrect in how it outputs "All Day" events. It uses (hack) datetimes for "All Day" events when it should not. It also specifies the wrong end day for "All Day" events which in ics format is the day after the last day of the "All Day" event.
If "The Events Calendar" were ever to be fixed to output valid ics, this script would not change the correct output because a valid ics file presumably would never use the telltale hack time of "23:59:59" that this script looks for before it changes anything;
Central to this bug in "The Events Calendar" is the misconception that an "All Day" event has the same universal start and end time everywhere when it does not. In fact, the same January 1 "All Day" event (eg. "New Year's Day") would be almost over in Auckland, New Zealand when it is only just getting started in Vancouver, Canada. If that's not so in the case of your event, then it is not an "All Day" event and you should enter it as a regular event with a specified start and end time.
Leif Harmsen 2025
leif@harmsen.net
Bluesky: @harmsen.net
*/
$url = 'https://queeraoke.ca/events/list/?ical=1'; // Define the URL of the non standard ICS file output by "The Events Calendar"
$file_content = file_get_contents($url); // Fetch the content of the file from the URL
if ($file_content === false) {
echo "Failed to open the file from the URL.";
exit;
}
$lines = explode("\n", $file_content); // Split the text file into single lines of text
$modified_lines = []; // Initialize an empty array to store modified lines or text
// Iterate over the lines and process them to make full day events compliant with the pubic ics standard...
for ($i = 0; $i < count($lines); $i++) {
$line = trim($lines[$i]);
// Check if the current line starts with "DTSTART" and ends with "T000000" AND the next line starts with "DTEND" and ends with "T235959"...
if (preg_match('/^DTSTART.*T000000$/', $line) && isset($lines[$i + 1]) && preg_match('/^DTEND.*T235959$/', trim($lines[$i + 1]))) {
$modified_lines[] = "DTSTART;VALUE=DATE:" . substr($line,-15,8);
} else if (preg_match('/^DTEND.*T235959$/', $line)) { // assuming nobody will ever manually enter this time as an end time so no need to double check.
$lastday = date_create_from_format('Ymd',substr($line,-15,8)); // last day is the last date of the all day single or multi day event.
$endday = $lastday->modify('+1 day'); // end day is the next day after the last day of the event.
$modified_lines[] = "DTEND;VALUE=DATE:" . $endday->format('Ymd');
} else {
$modified_lines[] = $line; // if none of the above, then copy the line as is.
} // end if.
} // end for loop.
echo implode("\n", $modified_lines); // join the modified lines into a single text file
?>You’re welcome.
Viewing 2 replies - 1 through 2 (of 2 total)
Viewing 2 replies - 1 through 2 (of 2 total)
- You must be logged in to reply to this topic.