From 0a09f1faa35f5a678c63eb40e47129f6a73c802e Mon Sep 17 00:00:00 2001 From: Yuriy Belenko Date: Tue, 4 Jan 2022 08:41:22 +0300 Subject: [PATCH] [php][bug] Fix DateTime microseconds bug in ObjectSerializer (#11213) * fixing precision for php * remove a bracket * handling whitespace * format comment * Use regexp to trim needless microseconds That way we can save timezone suffix. Co-authored-by: Carmen Quan --- .../resources/php/ObjectSerializer.mustache | 21 +++++-- .../lib/ObjectSerializer.php | 21 +++++-- .../tests/ObjectSerializerTest.php | 62 +++++++++++++++++++ 3 files changed, 96 insertions(+), 8 deletions(-) diff --git a/modules/openapi-generator/src/main/resources/php/ObjectSerializer.mustache b/modules/openapi-generator/src/main/resources/php/ObjectSerializer.mustache index 6d1193099c5..7d48d3557c3 100644 --- a/modules/openapi-generator/src/main/resources/php/ObjectSerializer.mustache +++ b/modules/openapi-generator/src/main/resources/php/ObjectSerializer.mustache @@ -120,6 +120,20 @@ class ObjectSerializer } } + /** + * Shorter timestamp microseconds to 6 digits length. + * + * @param string $timestamp Original timestamp + * + * @return string the shorten timestamp + */ + public static function sanitizeTimestamp($timestamp) + { + if (!is_string($timestamp)) return $timestamp; + + return preg_replace('/(:\d{2}.\d{6})\d*/', '$1', $timestamp); + } + /** * Take value and turn it into a string suitable for inclusion in * the path, by url-encoding. @@ -313,10 +327,9 @@ class ObjectSerializer return new \DateTime($data); } catch (\Exception $exception) { // Some API's return a date-time with too high nanosecond - // precision for php's DateTime to handle. This conversion - // (string -> unix timestamp -> DateTime) is a workaround - // for the problem. - return (new \DateTime())->setTimestamp(strtotime($data)); + // precision for php's DateTime to handle. + // With provided regexp 6 digits of microseconds saved + return new \DateTime(self::sanitizeTimestamp($data)); } } else { return null; diff --git a/samples/client/petstore/php/OpenAPIClient-php/lib/ObjectSerializer.php b/samples/client/petstore/php/OpenAPIClient-php/lib/ObjectSerializer.php index 9d9562bb668..093c15794ed 100644 --- a/samples/client/petstore/php/OpenAPIClient-php/lib/ObjectSerializer.php +++ b/samples/client/petstore/php/OpenAPIClient-php/lib/ObjectSerializer.php @@ -129,6 +129,20 @@ class ObjectSerializer } } + /** + * Shorter timestamp microseconds to 6 digits length. + * + * @param string $timestamp Original timestamp + * + * @return string the shorten timestamp + */ + public static function sanitizeTimestamp($timestamp) + { + if (!is_string($timestamp)) return $timestamp; + + return preg_replace('/(:\d{2}.\d{6})\d*/', '$1', $timestamp); + } + /** * Take value and turn it into a string suitable for inclusion in * the path, by url-encoding. @@ -322,10 +336,9 @@ class ObjectSerializer return new \DateTime($data); } catch (\Exception $exception) { // Some API's return a date-time with too high nanosecond - // precision for php's DateTime to handle. This conversion - // (string -> unix timestamp -> DateTime) is a workaround - // for the problem. - return (new \DateTime())->setTimestamp(strtotime($data)); + // precision for php's DateTime to handle. + // With provided regexp 6 digits of microseconds saved + return new \DateTime(self::sanitizeTimestamp($data)); } } else { return null; diff --git a/samples/client/petstore/php/OpenAPIClient-php/tests/ObjectSerializerTest.php b/samples/client/petstore/php/OpenAPIClient-php/tests/ObjectSerializerTest.php index d7cc4a173f1..9c4e86d5bf1 100644 --- a/samples/client/petstore/php/OpenAPIClient-php/tests/ObjectSerializerTest.php +++ b/samples/client/petstore/php/OpenAPIClient-php/tests/ObjectSerializerTest.php @@ -64,4 +64,66 @@ class ObjectSerializerTest extends TestCase ], ]; } + + /** + * @covers ObjectSerializer::sanitizeTimestamp + * @dataProvider provideTimestamps + */ + public function testSanitizeTimestamp(string $timestamp, string $expected): void + { + $this->assertEquals($expected, ObjectSerializer::sanitizeTimestamp($timestamp)); + } + + /** + * Test datetime deserialization. + * + * @covers ObjectSerializer::deserialize + * @dataProvider provideTimestamps + * + * @see https://github.com/OpenAPITools/openapi-generator/issues/7942 + * @see https://github.com/OpenAPITools/openapi-generator/issues/10548 + */ + public function testDateTimeParseSecondAccuracy(string $timestamp, string $expected): void + { + $dateTime = ObjectSerializer::deserialize($timestamp, '\DateTime'); + $this->assertEquals(new \DateTime($expected), $dateTime); + } + + public function provideTimestamps(): array + { + return [ + 'String from #7942' => [ + '2020-11-11T15:17:58.868722633Z', + '2020-11-11T15:17:58.868722Z', + ], + 'String from #10548' => [ + '2021-10-06T20:17:16.076372256Z', + '2021-10-06T20:17:16.076372Z', + ], + 'Without timezone' => [ + '2021-10-06T20:17:16.076372256', + '2021-10-06T20:17:16.076372', + ], + 'Without microseconds' => [ + '2021-10-06T20:17:16', + '2021-10-06T20:17:16', + ], + 'Without microseconds with timezone' => [ + '2021-10-06T20:17:16Z', + '2021-10-06T20:17:16Z', + ], + 'With numeric timezone' => [ + '2021-10-06T20:17:16.076372256+03:00', + '2021-10-06T20:17:16.076372+03:00', + ], + 'With numeric timezone without delimiter' => [ + '2021-10-06T20:17:16.076372256+0300', + '2021-10-06T20:17:16.076372+0300', + ], + 'With numeric short timezone' => [ + '2021-10-06T20:17:16.076372256+03', + '2021-10-06T20:17:16.076372+03', + ], + ]; + } }