Skip to content

Commit

Permalink
RRule: Include set timezone in serialized result
Browse files Browse the repository at this point in the history
fixes #37
  • Loading branch information
nilmerg committed Mar 30, 2023
1 parent 473c3c6 commit e22c2de
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 2 deletions.
9 changes: 7 additions & 2 deletions src/RRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use BadMethodCallException;
use DateTime;
use DateTimeInterface;
use DateTimeZone;
use Generator;
use InvalidArgumentException;
use ipl\Scheduler\Contract\Frequency;
Expand Down Expand Up @@ -185,6 +186,8 @@ public function startAt(DateTimeInterface $start): self
// When the start time contains microseconds, the first recurrence will always be skipped, as
// the transformer operates only up to seconds level. See also the upstream issue #155
$startDate->setTime($start->format('H'), $start->format('i'), $start->format('s'));
// In case start time uses a different tz than what the rrule internally does, we force it to use the same
$startDate->setTimezone(new DateTimeZone($this->rrule->getTimezone()));

$this->rrule->setStartDate($startDate);

Expand Down Expand Up @@ -277,13 +280,15 @@ public function getNextRecurrences(
public function jsonSerialize(): array
{
$data = [
'rrule' => $this->rrule->getString(),
'rrule' => $this->rrule->getString(RecurrRule::TZ_FIXED),
'frequency' => $this->frequency
];

$start = $this->getStart();
if ($start) {
$data['start'] = $start->format(static::SERIALIZED_DATETIME_FORMAT);
$data['start'] = (clone $start)
->setTimezone(new DateTimeZone('UTC'))
->format(static::SERIALIZED_DATETIME_FORMAT);
}

return $data;
Expand Down
29 changes: 29 additions & 0 deletions tests/RRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -156,4 +156,33 @@ public function testJsonSerializeAndDeserialize()

$this->assertEquals($rrule, RRule::fromJson(json_encode($rrule)));
}

public function testSerializationAndDeserializationHandleTimezonesCorrectly()
{
$oldTz = date_default_timezone_get();
date_default_timezone_set('Europe/Berlin');

try {
$startWithTz = new DateTime('01-06-2023T12:00:00', new DateTimeZone('America/New_York'));
$endWithTz = new DateTime('01-06-2024T07:00:00', new DateTimeZone('America/New_York'));

$rrule = RRule::fromJson(json_encode(RRule::fromFrequency(RRule::DAILY)
->startAt($startWithTz)
->endAt($endWithTz)
->jsonSerialize()));

$this->assertSame(
'18',
$rrule->getStart()->format('H'),
'fromJson(jsonSerialize()) does not restore the start date with a timezone correctly'
);
$this->assertSame(
'13',
$rrule->getEnd()->format('H'),
'fromJson(jsonSerialize()) does not restore the end date with a timezone correctly'
);
} finally {
date_default_timezone_set($oldTz);
}
}
}

0 comments on commit e22c2de

Please sign in to comment.