@@ -26,6 +26,8 @@ class Format
2626 const IRI_REFERENCE = 'iri-reference ' ;
2727 const URI_TEMPLATE = 'uri-template ' ;
2828
29+ public static $ strictDateTimeValidation = false ;
30+
2931 private static $ dateRegexPart = '(\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01]) ' ;
3032 private static $ timeRegexPart = '([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9]|60)(\.[0-9]+)?(Z|(\+|-)([01][0-9]|2[0-3]):([0-5][0-9]))? ' ;
3133 private static $ jsonPointerRegex = '_^(?:/|(?:/[^/#]*)*)$_ ' ;
@@ -75,9 +77,26 @@ public static function validationError($format, $data)
7577
7678 public static function dateTimeError ($ data )
7779 {
78- return preg_match ('/^ ' . self ::$ dateRegexPart . 'T ' . self ::$ timeRegexPart . '$/i ' , $ data )
79- ? null
80- : 'Invalid date-time: ' . $ data ;
80+ if (!preg_match ('/^ ' . self ::$ dateRegexPart . 'T ' . self ::$ timeRegexPart . '$/i ' , $ data )) {
81+ return 'Invalid date-time format: ' . $ data ;
82+ }
83+
84+ if (self ::$ strictDateTimeValidation ) {
85+ $ dt = date_create ($ data );
86+ if ($ dt === false ) {
87+ return 'Failed to parse date-time: ' . $ data ;
88+ }
89+ $ isLeapSecond = '6 ' === $ data [17 ] && (
90+ 0 === strpos (substr ($ data , 5 , 5 ), '12-31 ' ) ||
91+ 0 === strpos (substr ($ data , 5 , 5 ), '06-30 ' )
92+ );
93+ if (!$ isLeapSecond &&
94+ 0 !== stripos ($ dt ->format (DATE_RFC3339 ), substr ($ data , 0 , 19 ))) {
95+ return 'Invalid date-time value: ' . $ data ;
96+ }
97+ }
98+
99+ return null ;
81100 }
82101
83102 public static function regexError ($ data )
0 commit comments