From e99f27ec0691aa3a277cb34125600498617216c7 Mon Sep 17 00:00:00 2001 From: zhangskz Date: Mon, 5 Feb 2024 17:20:05 -0500 Subject: [PATCH] Fix inconsistent timestamp json encode/decode (#12396) (#15726) Protobuf php lib encodes 123_000_000 nano like this: 2000-01-01T00:00:00.**123**Z but then it gets decoded into 123 nanoseconds instead of 123_000_000. There were issue opened some time ago that also describes this behaviour #4335 Closes #12396 COPYBARA_INTEGRATE_REVIEW=https://github.com/protocolbuffers/protobuf/pull/12396 from kindratmakc:bugfix/inconsistent-timestamp-json-encode-decode df47c96567d8aa2b1136aa7227b0764cb22d85db PiperOrigin-RevId: 603118615 Co-authored-by: kindratmakc --- php/src/Google/Protobuf/Internal/GPBUtil.php | 4 ++++ php/tests/EncodeDecodeTest.php | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/php/src/Google/Protobuf/Internal/GPBUtil.php b/php/src/Google/Protobuf/Internal/GPBUtil.php index cac2a4a4b3ec9..4c1fadcd0301f 100644 --- a/php/src/Google/Protobuf/Internal/GPBUtil.php +++ b/php/src/Google/Protobuf/Internal/GPBUtil.php @@ -462,6 +462,10 @@ public static function parseTimestamp($timestamp) $nanoseconds = substr($timestamp, $periodIndex + 1, $nanosecondsLength); $nanoseconds = intval($nanoseconds); + if ($nanosecondsLength < 9) { + $nanoseconds = $nanoseconds * pow(10, 9 - $nanosecondsLength); + } + // remove the nanoseconds and preceding period from the timestamp $date = substr($timestamp, 0, $periodIndex); $timezone = substr($timestamp, $periodIndex + $nanosecondsLength + 1); diff --git a/php/tests/EncodeDecodeTest.php b/php/tests/EncodeDecodeTest.php index 113f200afee79..276528d26e9ab 100644 --- a/php/tests/EncodeDecodeTest.php +++ b/php/tests/EncodeDecodeTest.php @@ -992,6 +992,16 @@ public function testEncodeTimestamp() $m->serializeToJsonString()); } + public function testEncodeDecodeTimestampConsistency() + { + $m = new Google\Protobuf\Timestamp(); + $m->setSeconds(946684800); + $m->setNanos(123000000); + $m->mergeFromJsonString($m->serializeToJsonString()); + $this->assertEquals(946684800, $m->getSeconds()); + $this->assertEquals(123000000, $m->getNanos()); + } + public function testDecodeTopLevelValue() { $m = new Value();