diff --git a/docs/pages/how-to/deal-with-dates.md b/docs/pages/how-to/deal-with-dates.md index fa9470f8..b8d62fe1 100644 --- a/docs/pages/how-to/deal-with-dates.md +++ b/docs/pages/how-to/deal-with-dates.md @@ -2,7 +2,7 @@ When the mapper builds a date object, it has to know which format(s) are supported. By default, any valid timestamp or RFC 3339-formatted value will be -accepted. +accepted with or without microseconds. If other formats are to be supported, they need to be registered using the following method: diff --git a/src/Library/Settings.php b/src/Library/Settings.php index 653f6627..028556c2 100644 --- a/src/Library/Settings.php +++ b/src/Library/Settings.php @@ -23,6 +23,7 @@ final class Settings 'Y-m-d\\TH:i:sP', // RFC 3339 'Y-m-d\\TH:i:s.uP', // RFC 3339 with microseconds 'U', // Unix Timestamp + 'U.u', // Unix Timestamp with microseconds ]; /** @var array */ diff --git a/src/Mapper/Object/DateTimeFormatConstructor.php b/src/Mapper/Object/DateTimeFormatConstructor.php index 98298f22..a9df7758 100644 --- a/src/Mapper/Object/DateTimeFormatConstructor.php +++ b/src/Mapper/Object/DateTimeFormatConstructor.php @@ -44,10 +44,10 @@ public function __construct(string $format, string ...$formats) /** * @param class-string $className - * @param non-empty-string|int $value + * @param non-empty-string|int|float $value */ #[DynamicConstructor] - public function __invoke(string $className, string|int $value): DateTimeInterface + public function __invoke(string $className, string|int|float $value): DateTimeInterface { foreach ($this->formats as $format) { $date = $className::createFromFormat($format, (string)$value) ?: null; diff --git a/tests/Integration/Mapping/Object/DateTimeMappingTest.php b/tests/Integration/Mapping/Object/DateTimeMappingTest.php index 99d7113f..4c454864 100644 --- a/tests/Integration/Mapping/Object/DateTimeMappingTest.php +++ b/tests/Integration/Mapping/Object/DateTimeMappingTest.php @@ -79,6 +79,19 @@ public function test_default_date_constructor_with_valid_timestamp_format_source self::assertSame('1659688380', $result->format('U')); } + public function test_default_date_constructor_with_valid_timestamp_with_microseconds_format_source_returns_datetime(): void + { + try { + $result = $this->mapperBuilder() + ->mapper() + ->map(DateTimeInterface::class, 1659688380.654000); + } catch (MappingError $error) { + $this->mappingFail($error); + } + + self::assertSame('1659688380.654000', $result->format('U.u')); + } + public function test_default_date_constructor_with_timestamp_at_0_source_returns_datetime(): void { try { @@ -129,7 +142,7 @@ public function test_default_date_constructor_with_invalid_source_throws_excepti $error = $exception->node()->messages()[0]; self::assertSame('1630686564', $error->code()); - self::assertSame("Value 'invalid datetime' does not match any of the following formats: `Y-m-d\TH:i:sP`, `Y-m-d\TH:i:s.uP`, `U`.", (string)$error); + self::assertSame("Value 'invalid datetime' does not match any of the following formats: `Y-m-d\TH:i:sP`, `Y-m-d\TH:i:s.uP`, `U`, `U.u`.", (string)$error); } } diff --git a/tests/Unit/MapperBuilderTest.php b/tests/Unit/MapperBuilderTest.php index a47e4a5b..0f97a690 100644 --- a/tests/Unit/MapperBuilderTest.php +++ b/tests/Unit/MapperBuilderTest.php @@ -56,7 +56,7 @@ public function test_mapper_instance_is_the_same(): void public function test_get_supported_date_formats_returns_defaults_formats_when_not_overridden(): void { - self::assertSame(['Y-m-d\\TH:i:sP', 'Y-m-d\\TH:i:s.uP', 'U'], $this->mapperBuilder->supportedDateFormats()); + self::assertSame(['Y-m-d\\TH:i:sP', 'Y-m-d\\TH:i:s.uP', 'U', 'U.u'], $this->mapperBuilder->supportedDateFormats()); } public function test_get_supported_date_formats_returns_configured_values(): void