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