New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Handle summer time jumps in event recurrences #653
base: master
Are you sure you want to change the base?
Conversation
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## master #653 +/- ##
=========================================
Coverage 98.78% 98.78%
- Complexity 1869 1872 +3
=========================================
Files 71 71
Lines 5254 5265 +11
=========================================
+ Hits 5190 5201 +11
Misses 64 64 ☔ View full report in Codecov by Sentry. |
It looks better than my attempt. In the end wasn't it possible to store the "unaltered" datetime as mentioned here? One idea would be to have a new object that extends DateTime and overrides |
The "unaltered" time, for example "0230" is not a valid time on the date when summer time starts. So the There are other possible edge-cases, but they don't really happen. For example, if 2 recurrences in a row fall on the summer time start date, then reversing the hour-jump would have to be delayed. But in real-life, summer time usually starts on a Sunday morning. For a yearly event, the recurrence in the next year is always 1 or 2 days later in the week, so there can't be 2 Sunday's in a row for a yearly event. But someone could design an event that happens at 0230 every 52nd Sunday - and that could fall on the summer time start date for a few years in a row! |
} else { | ||
$increase = 0; | ||
do { | ||
++$increase; | ||
$tempDate = clone $this->currentDate; | ||
$tempDate = $tempDate->modify('+ '.($this->interval * $increase).' months'); | ||
$tempDate = $tempDate->modify('+ '.($this->interval * $increase).' months '.$this->startDate->format('H:i:s')); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick: We can re-use the function right?
$tempDate = $tempDate->modify('+ '.($this->interval * $increase).' months '.$this->startDate->format('H:i:s')); | |
$tempDate = $tempDate->advanceTheDate('+ '.($this->interval * $increase).' months '); |
@@ -349,7 +392,7 @@ protected function nextDaily(): void | |||
protected function nextWeekly(): void | |||
{ | |||
if (!$this->byHour && !$this->byDay) { | |||
$this->currentDate = $this->currentDate->modify('+'.$this->interval.' weeks'); | |||
$this->advanceTheDate('+'.$this->interval.' weeks'); | |||
|
|||
return; | |||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Question: Should we not handle the execution going to the rest of the function as well? I would well see a line at the very end to set the time straight:
$this->startDate->modify($this->startDate->format('H:i:s'));
if (0 === $this->hourJump) { | ||
// Remember if the clock time jumped forward on the next occurrence. | ||
// That happens if the next event time is on a day when summer time starts | ||
// and the event time is in the non-existent hour of the day. | ||
// For example, an event that normally starts at 02:30 will | ||
// have to start at 03:30 on that day. | ||
// If the interval is just 1 hour, then there is no "jumping back" to do. | ||
// The events that day will happen, for example, at 0130 0330 0430 0530... | ||
if ($this->interval > 1) { | ||
$expectedHourOfNextDate = ($hourOfCurrentDate + $this->interval) % 24; | ||
$actualHourOfNextDate = (int) $this->currentDate->format('G'); | ||
$this->hourJump = $actualHourOfNextDate - $expectedHourOfNextDate; | ||
} | ||
} else { | ||
// The hour "jumped" for the previous occurrence, to avoid the non-existent time. | ||
// currentDate got set ahead by (usually) 1 hour on that day. | ||
// Adjust it back for this next occurrence. | ||
$this->currentDate = $this->currentDate->sub(new \DateInterval('PT'.$this->hourJump.'H')); | ||
$this->hourJump = 0; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick:
With the comments it's adding a lot of lines to this function. Perhaps we can move the new code to a private function "AdjustForTimeJumps"
Issue #648
1st commit is the test code added by @schreven in PR #647
2nd commit is my first code that makes those test cases pass. It only touches the case of events that recur at an interval of days.
nextHourly
Thanks to @gharlan and @schreven for input, code suggestions etc.