Skip to content

Commit

Permalink
feat: support microseconds in the Atom / RFC 3339 / ISO 8601 format
Browse files Browse the repository at this point in the history
This commit adds default support for microseconds in the RFC 3339
format.

The references to the “Atom” format have been updated to RFC 3339 which
is identical to the Atom format, but uses a reference that is not
PHP-specific.
  • Loading branch information
TimWolla authored Aug 22, 2023
1 parent 3e7c632 commit c25721f
Show file tree
Hide file tree
Showing 6 changed files with 42 additions and 8 deletions.
2 changes: 1 addition & 1 deletion docs/pages/how-to/deal-with-dates.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Dealing with dates

When the mapper builds a date object, it has to know which format(s) are
supported. By default, any valid timestamp or ATOM-formatted value will be
supported. By default, any valid timestamp or RFC 3339-formatted value will be
accepted.

If other formats are to be supported, they need to be registered using the
Expand Down
6 changes: 5 additions & 1 deletion src/Library/Settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@
final class Settings
{
/** @var non-empty-array<non-empty-string> */
public const DEFAULT_SUPPORTED_DATETIME_FORMATS = [DATE_ATOM, 'U'];
public const DEFAULT_SUPPORTED_DATETIME_FORMATS = [
'Y-m-d\\TH:i:sP', // RFC 3339
'Y-m-d\\TH:i:s.uP', // RFC 3339 with microseconds
'U', // Unix Timestamp
];

/** @var array<class-string|interface-string, callable> */
public array $inferredMapping = [];
Expand Down
2 changes: 1 addition & 1 deletion src/Mapper/Object/DateTimeFormatConstructor.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* date formats should be allowed during mapping.
*
* By default, if this constructor is never registered, the dates will accept
* any valid timestamp or ATOM-formatted value.
* any valid timestamp or RFC 3339-formatted value.
*
* Usage:
*
Expand Down
4 changes: 2 additions & 2 deletions src/MapperBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ public function registerConstructor(callable|string ...$constructors): self
/**
* Describes which date formats will be supported during mapping.
*
* By default, the dates will accept any valid timestamp or ATOM-formatted
* By default, the dates will accept any valid timestamp or RFC 3339-formatted
* value.
*
* ```php
Expand All @@ -244,7 +244,7 @@ public function supportDateFormats(string $format, string ...$formats): self
/**
* Returns the date formats supported during mapping.
*
* By default, any valid timestamp or ATOM-formatted value are accepted.
* By default, any valid timestamp or RFC 3339-formatted value are accepted.
* Custom formats can be set using method `supportDateFormats()`.
*
* @return non-empty-array<non-empty-string>
Expand Down
34 changes: 32 additions & 2 deletions tests/Integration/Mapping/Object/DateTimeMappingTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public function test_default_datetime_constructor_cannot_be_used(): void
}
}

public function test_default_date_constructor_with_valid_atom_format_source_returns_datetime(): void
public function test_default_date_constructor_with_valid_rfc_3339_format_source_returns_datetime(): void
{
try {
$result = (new MapperBuilder())
Expand All @@ -37,6 +37,36 @@ public function test_default_date_constructor_with_valid_atom_format_source_retu
self::assertSame('2022-08-05T08:32:06+00:00', $result->format(DATE_ATOM));
}

public function test_default_date_constructor_with_valid_rfc_3339_and_milliseconds_format_source_returns_datetime(): void
{
try {
$result = (new MapperBuilder())
->mapper()
->map(DateTimeInterface::class, '2022-08-05T08:32:06.123Z');
} catch (MappingError $error) {
$this->mappingFail($error);
}

self::assertSame('1659688326', $result->format('U'));
self::assertSame('123', $result->format('v'));
self::assertSame('123000', $result->format('u'));
}

public function test_default_date_constructor_with_valid_rfc_3339_and_microseconds_format_source_returns_datetime(): void
{
try {
$result = (new MapperBuilder())
->mapper()
->map(DateTimeInterface::class, '2022-08-05T08:32:06.123456Z');
} catch (MappingError $error) {
$this->mappingFail($error);
}

self::assertSame('1659688326', $result->format('U'));
self::assertSame('123', $result->format('v'));
self::assertSame('123456', $result->format('u'));
}

public function test_default_date_constructor_with_valid_timestamp_format_source_returns_datetime(): void
{
try {
Expand Down Expand Up @@ -100,7 +130,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`, `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`.", (string)$error);
}
}

Expand Down
2 changes: 1 addition & 1 deletion tests/Unit/MapperBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,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([DATE_ATOM, 'U'], $this->mapperBuilder->supportedDateFormats());
self::assertSame(['Y-m-d\\TH:i:sP', 'Y-m-d\\TH:i:s.uP', 'U'], $this->mapperBuilder->supportedDateFormats());
}

public function test_get_supported_date_formats_returns_configured_values(): void
Expand Down

0 comments on commit c25721f

Please sign in to comment.