1515
1616use DateTimeImmutable ;
1717use DateTimeInterface ;
18+ use DateTimeZone ;
1819use Exception ;
1920use ValueError ;
2021
2324
2425final class DateField extends AbstractField
2526{
26- public function __construct (public readonly string $ format = '' , float $ confidenceThreshold = 0.8 )
27+ public readonly string $ format ;
28+ public readonly ?DateTimeZone $ timeZone ;
29+
30+ public function __construct (string $ format , DateTimeZone |string |null $ timeZone = null , float $ confidenceThreshold = 0.8 )
2731 {
32+ $ format = trim ($ format );
33+ '' !== $ format || throw new ValueError ('The date field format can not be empty. ' );
34+ $ timeZone = self ::filterTimezone ($ timeZone );
35+
2836 parent ::__construct ($ confidenceThreshold );
37+ $ this ->format = $ format ;
38+ $ this ->timeZone = $ timeZone ;
2939 }
3040
31- public static function native ( float $ confidenceThreshold = 0.8 ): self
41+ private static function filterTimezone ( DateTimeZone | string | null $ timeZone ): ? DateTimeZone
3242 {
33- return new self (format: '' , confidenceThreshold: $ confidenceThreshold );
34- }
43+ if (null === $ timeZone ) {
44+ return null ;
45+ }
3546
36- public static function withFormat (string $ format , float $ confidenceThreshold = 0.8 ): self
37- {
38- $ format = trim ($ format );
39- '' !== $ format || throw new ValueError ('The date field strategy format can not be empty. ' );
47+ if ($ timeZone instanceof DateTimeZone) {
48+ return $ timeZone ;
49+ }
4050
41- return new self (format: $ format , confidenceThreshold: $ confidenceThreshold );
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+ }
4256 }
4357
4458 public function type (): FieldType
@@ -51,11 +65,6 @@ public function name(): string
5165 return FieldType::Date->value ;
5266 }
5367
54- public function format (): string
55- {
56- return $ this ->format ;
57- }
58-
5968 public function parse (mixed $ value ): ?DateTimeImmutable
6069 {
6170 if ($ value instanceof DateTimeInterface) {
@@ -72,22 +81,30 @@ public function parse(mixed $value): ?DateTimeImmutable
7281 }
7382
7483 try {
75- if ('' !== $ this ->format ) {
76- $ value = DateTimeImmutable::createFromFormat ($ this ->format , $ value );
84+ $ value = DateTimeImmutable::createFromFormat ($ this ->format , $ value , $ this ->timeZone );
85+ if (false === $ value ) {
86+ return null ;
87+ }
7788
78- return false === $ value ? null : $ value ;
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 ;
7995 }
8096
81- return new DateTimeImmutable ( $ value) ;
82- } catch (Exception ) {
97+ return $ value ;
98+ } catch (ValueError ) {
8399 return null ;
84100 }
85101 }
86102
87- public function metadata (): Metadata
103+ public function metadata (): FieldMetadata
88104 {
89- return new Metadata ([
105+ return new FieldMetadata ([
90106 'format ' => $ this ->format ,
107+ 'timezone ' => $ this ->timeZone ?->getName(),
91108 ]);
92109 }
93110}
0 commit comments