Skip to content

Commit 3c902ae

Browse files
committed
Merge branch 'review-date-formatter'
2 parents 902ccd8 + de29aae commit 3c902ae

27 files changed

+305
-276
lines changed

src/Concept/Provider.php

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
namespace Lkrms\Concept;
44

55
use Lkrms\Contract\IContainer;
6-
use Lkrms\Contract\IDateFormatter;
76
use Lkrms\Contract\IProvider;
87
use Lkrms\Exception\MethodNotImplementedException;
8+
use Lkrms\Support\Date\DateFormatterInterface;
99
use Lkrms\Support\ProviderContext;
1010

1111
/**
@@ -17,7 +17,7 @@ abstract class Provider implements IProvider
1717
{
1818
protected IContainer $App;
1919

20-
private IDateFormatter $DateFormatter;
20+
private DateFormatterInterface $DateFormatter;
2121

2222
/**
2323
* Creates a new provider object
@@ -31,10 +31,10 @@ public function __construct(IContainer $app)
3131
* Get a date formatter to work with the backend's date and time format
3232
* and/or timezone
3333
*
34-
* The {@see IDateFormatter} returned will be cached for the lifetime of the
35-
* {@see Provider} instance.
34+
* The {@see DateFormatterInterface} returned will be cached for the
35+
* lifetime of the {@see Provider} instance.
3636
*/
37-
abstract protected function getDateFormatter(): IDateFormatter;
37+
abstract protected function getDateFormatter(): DateFormatterInterface;
3838

3939
/**
4040
* @inheritDoc
@@ -79,7 +79,7 @@ final public function container(): IContainer
7979
/**
8080
* @inheritDoc
8181
*/
82-
final public function dateFormatter(): IDateFormatter
82+
final public function dateFormatter(): DateFormatterInterface
8383
{
8484
return $this->DateFormatter
8585
?? ($this->DateFormatter = $this->getDateFormatter());
@@ -89,7 +89,7 @@ final public function dateFormatter(): IDateFormatter
8989
* Get the date formatter cached by dateFormatter(), or null if it hasn't
9090
* been cached
9191
*/
92-
final protected function getCachedDateFormatter(): ?IDateFormatter
92+
final protected function getCachedDateFormatter(): ?DateFormatterInterface
9393
{
9494
return $this->DateFormatter ?? null;
9595
}
@@ -99,7 +99,7 @@ final protected function getCachedDateFormatter(): ?IDateFormatter
9999
*
100100
* @return $this
101101
*/
102-
final protected function setDateFormatter(?IDateFormatter $formatter)
102+
final protected function setDateFormatter(?DateFormatterInterface $formatter)
103103
{
104104
if ($formatter === null) {
105105
unset($this->DateFormatter);

src/Contract/IDateParser.php

Lines changed: 0 additions & 20 deletions
This file was deleted.

src/Contract/IProvider.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace Lkrms\Contract;
44

55
use Lkrms\Exception\MethodNotImplementedException;
6+
use Lkrms\Support\Date\DateFormatterInterface;
67
use Stringable;
78

89
/**
@@ -64,7 +65,7 @@ public function getBackendIdentifier(): array;
6465
* Get a date formatter to work with the backend's date and time format
6566
* and/or timezone
6667
*/
67-
public function dateFormatter(): IDateFormatter;
68+
public function dateFormatter(): DateFormatterInterface;
6869

6970
/**
7071
* Throw an exception if the backend isn't reachable

src/Contract/ISerializeRules.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
namespace Lkrms\Contract;
44

5-
use Lkrms\Support\DateFormatter;
5+
use Lkrms\Support\Date\DateFormatter;
66

77
/**
88
* Instructions for serializing nested entities

src/Curler/Curler.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
use Lkrms\Concern\TWritable;
99
use Lkrms\Contract\Buildable;
1010
use Lkrms\Contract\ICollection;
11-
use Lkrms\Contract\IDateFormatter;
1211
use Lkrms\Contract\IReadable;
1312
use Lkrms\Contract\IWritable;
1413
use Lkrms\Curler\Catalog\CurlerProperty;
@@ -28,7 +27,8 @@
2827
use Lkrms\Iterator\RecursiveMutableGraphIterator;
2928
use Lkrms\Store\CacheStore;
3029
use Lkrms\Support\Catalog\MimeType;
31-
use Lkrms\Support\DateFormatter;
30+
use Lkrms\Support\Date\DateFormatter;
31+
use Lkrms\Support\Date\DateFormatterInterface;
3232
use Lkrms\Utility\Arr;
3333
use Lkrms\Utility\Compute;
3434
use Lkrms\Utility\Convert;
@@ -78,7 +78,7 @@
7878
* @property bool $ExpectJson Request JSON from upstream?
7979
* @property bool $PostJson Use JSON to serialize POST/PUT/PATCH/DELETE data?
8080
* @property bool $PreserveKeys Suppress removal of numeric indices from serialized lists?
81-
* @property IDateFormatter|null $DateFormatter Specify the date format and timezone used upstream
81+
* @property DateFormatterInterface|null $DateFormatter Specify the date format and timezone used upstream
8282
* @property string|null $UserAgent Override the default User-Agent header
8383
* @property bool $AlwaysPaginate Pass every response to the pager?
8484
* @property bool $ObjectAsArray Return deserialized objects as associative arrays?
@@ -359,7 +359,7 @@ final class Curler implements IReadable, IWritable, Buildable
359359
/**
360360
* Specify the date format and timezone used upstream
361361
*
362-
* @var IDateFormatter|null
362+
* @var DateFormatterInterface|null
363363
*/
364364
protected $DateFormatter;
365365

@@ -465,7 +465,7 @@ public function __construct(
465465
bool $expectJson = true,
466466
bool $postJson = true,
467467
bool $preserveKeys = false,
468-
?IDateFormatter $dateFormatter = null,
468+
?DateFormatterInterface $dateFormatter = null,
469469
?string $userAgent = null,
470470
bool $alwaysPaginate = false,
471471
bool $objectAsArray = true
@@ -924,7 +924,7 @@ private function getCookieKey(): ?string
924924
: null;
925925
}
926926

927-
private function getDateFormatter(): IDateFormatter
927+
private function getDateFormatter(): DateFormatterInterface
928928
{
929929
return $this->DateFormatter
930930
?: ($this->DateFormatter = new DateFormatter());

src/Curler/CurlerBuilder.php

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace Lkrms\Support\Date;
4+
5+
use DateTimeImmutable;
6+
use DateTimeZone;
7+
8+
/**
9+
* Parses date and time strings with a given format
10+
*
11+
* @api
12+
*/
13+
final class DateFormatParser implements DateParserInterface
14+
{
15+
private string $Format;
16+
17+
/**
18+
* Creates a new CreateFromFormatDateParser object
19+
*
20+
* @see DateTimeImmutable::createFromFormat()
21+
*/
22+
public function __construct(string $format)
23+
{
24+
// Reset fields that don't appear in the format string to zero-like
25+
// values, otherwise they will be set to the current date and time
26+
if (strpos($format, '!') === false && strpos($format, '|') === false) {
27+
$format .= '|';
28+
}
29+
30+
$this->Format = $format;
31+
}
32+
33+
/**
34+
* @inheritDoc
35+
*/
36+
public function parse(string $value, ?DateTimeZone $timezone = null): ?DateTimeImmutable
37+
{
38+
$date = DateTimeImmutable::createFromFormat($this->Format, $value, $timezone);
39+
if ($date === false) {
40+
return null;
41+
}
42+
return $date;
43+
}
44+
}

src/Support/Date/DateFormatter.php

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace Lkrms\Support\Date;
4+
5+
use Lkrms\Utility\Date;
6+
use DateTimeImmutable;
7+
use DateTimeInterface;
8+
use DateTimeZone;
9+
10+
/**
11+
* Formats and parses dates, optionally applying a preferred timezone to both
12+
* operations
13+
*
14+
* @api
15+
*/
16+
final class DateFormatter implements DateFormatterInterface
17+
{
18+
private string $Format;
19+
20+
private ?DateTimeZone $Timezone;
21+
22+
/**
23+
* @var DateParserInterface[]
24+
*/
25+
private array $Parsers;
26+
27+
/**
28+
* @param DateTimeZone|string|null $timezone
29+
*/
30+
public function __construct(string $format = DateTimeInterface::ATOM, $timezone = null, DateParserInterface ...$parsers)
31+
{
32+
$this->Format = $format;
33+
$this->Timezone = is_string($timezone) ? new DateTimeZone($timezone) : $timezone;
34+
$this->Parsers = $parsers ?: [new DateFormatParser($format)];
35+
}
36+
37+
/**
38+
* @inheritDoc
39+
*/
40+
public function format(DateTimeInterface $date): string
41+
{
42+
if (
43+
$this->Timezone &&
44+
$this->Timezone->getName() !== $date->getTimezone()->getName()
45+
) {
46+
$date = Date::immutable($date)->setTimezone($this->Timezone);
47+
}
48+
49+
return $date->format($this->Format);
50+
}
51+
52+
/**
53+
* @inheritDoc
54+
*/
55+
public function parse(string $value): ?DateTimeImmutable
56+
{
57+
foreach ($this->Parsers as $parser) {
58+
$date = $parser->parse($value, $this->Timezone);
59+
if ($date) {
60+
return $date;
61+
}
62+
}
63+
64+
return null;
65+
}
66+
}
Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
<?php declare(strict_types=1);
22

3-
namespace Lkrms\Contract;
3+
namespace Lkrms\Support\Date;
44

55
use DateTimeImmutable;
66
use DateTimeInterface;
77

88
/**
9-
* Formats and parses date and time values
9+
* @api
1010
*/
11-
interface IDateFormatter
11+
interface DateFormatterInterface
1212
{
1313
/**
1414
* Format a date and time
@@ -17,6 +17,8 @@ public function format(DateTimeInterface $date): string;
1717

1818
/**
1919
* Convert a string to a date and time, if possible
20+
*
21+
* Returns `null` if `$value` cannot be parsed.
2022
*/
2123
public function parse(string $value): ?DateTimeImmutable;
2224
}

src/Support/Date/DateParser.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace Lkrms\Support\Date;
4+
5+
use DateTimeImmutable;
6+
use DateTimeZone;
7+
8+
/**
9+
* Parses date and time strings understood by strtotime()
10+
*
11+
* @api
12+
*/
13+
final class DateParser implements DateParserInterface
14+
{
15+
/**
16+
* @inheritDoc
17+
*/
18+
public function parse(string $value, ?DateTimeZone $timezone = null): ?DateTimeImmutable
19+
{
20+
$date = date_create_immutable($value, $timezone);
21+
if ($date === false) {
22+
return null;
23+
}
24+
return $date;
25+
}
26+
}

0 commit comments

Comments
 (0)