From 628723ab719f59654b28f81db0ac9a66d3a207c8 Mon Sep 17 00:00:00 2001 From: Dmitriy Derepko Date: Fri, 26 Dec 2025 15:42:20 +0400 Subject: [PATCH] fix: sync temporal with default timezone --- src/Worker/Environment/Environment.php | 2 +- src/Worker/Transport/Codec/JsonCodec.php | 6 +-- src/Worker/Transport/Codec/ProtoCodec.php | 6 +-- .../Workflow/DateTimeZoneWorkflowTest.php | 52 +++++++++++++++++++ 4 files changed, 59 insertions(+), 7 deletions(-) create mode 100644 tests/Acceptance/Extra/Workflow/DateTimeZoneWorkflowTest.php diff --git a/src/Worker/Environment/Environment.php b/src/Worker/Environment/Environment.php index 71809387c..8ef280536 100644 --- a/src/Worker/Environment/Environment.php +++ b/src/Worker/Environment/Environment.php @@ -20,7 +20,7 @@ class Environment implements EnvironmentInterface public function __construct() { - $this->tickTime = new \DateTimeImmutable('now', new \DateTimeZone('UTC')); + $this->tickTime = new \DateTimeImmutable('now'); } public function now(): \DateTimeInterface diff --git a/src/Worker/Transport/Codec/JsonCodec.php b/src/Worker/Transport/Codec/JsonCodec.php index 730435e79..1c1491c54 100644 --- a/src/Worker/Transport/Codec/JsonCodec.php +++ b/src/Worker/Transport/Codec/JsonCodec.php @@ -23,6 +23,7 @@ final class JsonCodec implements CodecInterface private int $maxDepth; private Decoder $parser; private Encoder $serializer; + private \DateTimeZone $hostTimeZone; public function __construct(DataConverterInterface $dataConverter, int $maxDepth = 64) { @@ -30,6 +31,7 @@ public function __construct(DataConverterInterface $dataConverter, int $maxDepth $this->parser = new Decoder($dataConverter); $this->serializer = new Encoder($dataConverter); + $this->hostTimeZone = new \DateTimeZone(\date_default_timezone_get()); } public function encode(iterable $commands): string @@ -50,15 +52,13 @@ public function encode(iterable $commands): string public function decode(string $batch, array $headers = []): iterable { - static $tz = new \DateTimeZone('UTC'); - try { $commands = \json_decode($batch, true, $this->maxDepth, \JSON_THROW_ON_ERROR); foreach ($commands as $command) { /** @psalm-suppress ArgumentTypeCoercion */ $info = new TickInfo( - time: new \DateTimeImmutable($headers['tickTime'] ?? 'now', $tz), + time: (new \DateTimeImmutable($headers['tickTime'] ?? 'now'))->setTimezone($this->hostTimeZone), historyLength: (int) ($headers['history_length'] ?? 0), historySize: (int) ($headers['history_size'] ?? 0), continueAsNewSuggested: (bool) ($headers['continue_as_new_suggested'] ?? false), diff --git a/src/Worker/Transport/Codec/ProtoCodec.php b/src/Worker/Transport/Codec/ProtoCodec.php index c9a300b9b..3c1c6a9db 100644 --- a/src/Worker/Transport/Codec/ProtoCodec.php +++ b/src/Worker/Transport/Codec/ProtoCodec.php @@ -26,11 +26,13 @@ final class ProtoCodec implements CodecInterface { private Decoder $parser; private Encoder $encoder; + private \DateTimeZone $hostTimeZone; public function __construct(DataConverterInterface $dataConverter) { $this->parser = new Decoder($dataConverter); $this->encoder = new Encoder($dataConverter); + $this->hostTimeZone = new \DateTimeZone(\date_default_timezone_get()); } public function encode(iterable $commands): string @@ -54,8 +56,6 @@ public function encode(iterable $commands): string public function decode(string $batch, array $headers = []): iterable { - static $tz = new \DateTimeZone('UTC'); - try { $frame = new Frame(); $frame->mergeFromString($batch); @@ -63,7 +63,7 @@ public function decode(string $batch, array $headers = []): iterable foreach ($frame->getMessages() as $msg) { /** @psalm-suppress ArgumentTypeCoercion */ $info = new TickInfo( - time: new \DateTimeImmutable($headers['tickTime'] ?? $msg->getTickTime(), $tz), + time: (new \DateTimeImmutable($headers['tickTime'] ?? $msg->getTickTime()))->setTimezone($this->hostTimeZone), historyLength: (int) ($headers['history_length'] ?? $msg->getHistoryLength()), historySize: (int) ($headers['history_size'] ?? $msg->getHistorySize()), continueAsNewSuggested: (bool) ($headers['continue_as_new_suggested'] ?? $msg->getContinueAsNewSuggested()), diff --git a/tests/Acceptance/Extra/Workflow/DateTimeZoneWorkflowTest.php b/tests/Acceptance/Extra/Workflow/DateTimeZoneWorkflowTest.php new file mode 100644 index 000000000..a611aa185 --- /dev/null +++ b/tests/Acceptance/Extra/Workflow/DateTimeZoneWorkflowTest.php @@ -0,0 +1,52 @@ +getResult(type: 'array'); + + self::assertEquals($result['system'], $result['current']); + } +} + +#[WorkflowInterface] +class MainWorkflow +{ + #[WorkflowMethod('Extra_Workflow_DateTimeZoneWorkflow')] + public function run() + { + yield Workflow::timer('1 seconds'); + + /** + * @var \DateTimeImmutable $currentDate + */ + $currentDate = yield Workflow::sideEffect(static fn(): \DateTimeImmutable => new \DateTimeImmutable()); + + return yield [ + 'current' => [ + 'timestamp' => $currentDate->getTimestamp(), + 'timezone.offset' => $currentDate->getTimeZone()->getOffset($currentDate), + ], + 'system' => [ + 'timestamp' => Workflow::now()->getTimestamp(), + 'timezone.offset' => Workflow::now()->getTimezone()->getOffset(Workflow::now()), + ], + ]; + } +}