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,21 @@ 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 (
91+ (isset ($ errors ['warning_count ' ]) && 0 < $ errors ['warning_count ' ]) ||
92+ (isset ($ errors ['error_count ' ]) && 0 < $ errors ['error_count ' ])
93+ ) {
94+ return null ;
95+ }
96+
97+ return $ value ;
98+ } catch (ValueError ) {
7299 return null ;
73100 }
74101 }
@@ -77,6 +104,7 @@ public function metadata(): Metadata
77104 {
78105 return new Metadata ([
79106 'format ' => $ this ->format ,
107+ 'timezone ' => $ this ->timeZone ?->getName(),
80108 ]);
81109 }
82110}
0 commit comments