1515
1616use DateTimeImmutable ;
1717use DateTimeInterface ;
18+ use DateTimeZone ;
1819use Exception ;
1920use ValueError ;
2021
2425final class DateField extends AbstractField
2526{
2627 public readonly string $ format ;
28+ public readonly ?DateTimeZone $ timeZone ;
2729
28- public function __construct (string $ format , float $ confidenceThreshold = 0.8 )
30+ public function __construct (string $ format , DateTimeZone | string | null $ timeZone = null , float $ confidenceThreshold = 0.8 )
2931 {
3032 $ format = trim ($ format );
31- '' !== $ format || throw new ValueError ('The date field strategy format can not be empty. ' );
33+ '' !== $ format || throw new ValueError ('The date field format can not be empty. ' );
34+ $ timeZone = self ::filterTimezone ($ timeZone );
3235
3336 parent ::__construct ($ confidenceThreshold );
3437 $ this ->format = $ format ;
38+ $ this ->timeZone = $ timeZone ;
39+ }
40+
41+ private static function filterTimezone (DateTimeZone |string |null $ timeZone ): ?DateTimeZone
42+ {
43+ if (null === $ timeZone ) {
44+ return null ;
45+ }
46+
47+ if ($ timeZone instanceof DateTimeZone) {
48+ return $ timeZone ;
49+ }
50+
51+ try {
52+ return new DateTimeZone ($ timeZone );
53+ } catch (Exception $ exception ) {
54+ throw new ValueError ('The date field timezone value ` ' .$ timeZone .'` is invalid. ' , previous: $ exception );
55+ }
3556 }
3657
3758 public function type (): FieldType
@@ -44,11 +65,6 @@ public function name(): string
4465 return FieldType::Date->value ;
4566 }
4667
47- public function format (): string
48- {
49- return $ this ->format ;
50- }
51-
5268 public function parse (mixed $ value ): ?DateTimeImmutable
5369 {
5470 if ($ value instanceof DateTimeInterface) {
@@ -65,10 +81,18 @@ public function parse(mixed $value): ?DateTimeImmutable
6581 }
6682
6783 try {
68- $ value = DateTimeImmutable::createFromFormat ($ this ->format , $ value );
69-
70- return false === $ value ? null : $ value ;
71- } catch (Exception ) {
84+ $ value = DateTimeImmutable::createFromFormat ($ this ->format , $ value , $ this ->timeZone );
85+ if (false === $ value ) {
86+ return null ;
87+ }
88+
89+ $ errors = DateTimeImmutable::getLastErrors ();
90+ if (0 < $ errors ['warning_count ' ] || 0 < $ errors ['error_count ' ]) {
91+ return null ;
92+ }
93+
94+ return $ value ;
95+ } catch (ValueError ) {
7296 return null ;
7397 }
7498 }
@@ -77,6 +101,7 @@ public function metadata(): Metadata
77101 {
78102 return new Metadata ([
79103 'format ' => $ this ->format ,
104+ 'timezone ' => $ this ->timeZone ?->getName(),
80105 ]);
81106 }
82107}
0 commit comments