From 069445579caa79233d4490837d06154a772be55c Mon Sep 17 00:00:00 2001 From: Chris S Date: Mon, 7 Mar 2022 17:06:37 -0800 Subject: [PATCH] Fix conversion to UTC for DST changes The RepeatRuleDateTime constructor extracts the date's time zone then passes it to the parent class DateTime. Because PHP's DateTime has full support for time zones, it compensates for them when parsing a string. Normally this isn't a problem, because the opposite occurs when a DateTime is converted back into a string; the two adjustments cancel each other. Davical often converts a time to UTC by negating the time zone offset and adding it to the underlying DateTime (keeping the time zone intact). A problem occurs when the result is on the other side of a daylight- saving-time transition. In that case the adjustments do not cancel and an incorrect time string is returned. This bug is tricky because the problem doesn't manifest during the DST transition iself, but hours earlier or later depending on the original time zone. For example, 2022-03-12T18:30:00-08:00 (America/Los_Angeles) is 2022-03-13T02:30:00Z. Since 2022-03-13 is a 23-hour day in the Los Angeles time zone (the 2AM-3AM hour is skipped) this becomes 2022-03-13T03:30:00-07:00 after adding the negated offset. FloatOrUTC() would strip the new offset and simply return "20220313T033000". --- inc/RRule.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/inc/RRule.php b/inc/RRule.php index 0f55c1d6..9e058bad 100644 --- a/inc/RRule.php +++ b/inc/RRule.php @@ -410,9 +410,7 @@ class RepeatRuleDateTime extends DateTime { public function FloatOrUTC($return_floating_times = false) { $gmt = clone($this); if ( !$return_floating_times && isset($this->tzid) && $this->tzid != 'UTC' ) { - $dtz = parent::getTimezone(); - $offset = 0 - $dtz->getOffset($gmt); - $gmt->modify( $offset . ' seconds' ); + $gmt->setTimezone('UTC'); } if ( $this->is_date ) return $gmt->format('Ymd'); if ( $return_floating_times ) return $gmt->format('Ymd\THis');