@@ -104,6 +104,31 @@ public static bool TryParse(string text, out DateInfo parsedValue)
104104 return false ;
105105 }
106106
107+ public static bool TryParse ( string text , out TimeInfo parsedValue )
108+ {
109+ const int start = 0 ;
110+
111+ DateAndTimeInfo rawParsedValue ;
112+ string normalizedText = text . Trim ( ) ;
113+
114+ if ( TryParseAsTime ( normalizedText , XsdDateAndTimeFlags . Time , start , out rawParsedValue ) )
115+ {
116+ parsedValue = rawParsedValue . Time ;
117+ return true ;
118+ }
119+ else
120+ {
121+ if ( TryParseAsDateTime ( normalizedText , XsdDateAndTimeFlags . DateTime | XsdDateAndTimeFlags . XdrDateTime , start , out rawParsedValue ) )
122+ {
123+ parsedValue = rawParsedValue . Time ;
124+ return true ;
125+ }
126+ }
127+
128+ parsedValue = default ;
129+ return false ;
130+ }
131+
107132 private static bool TryParseAsDate (
108133 string text ,
109134 XsdDateAndTimeFlags kinds ,
@@ -118,14 +143,14 @@ private static bool TryParseAsDate(
118143 {
119144 if ( TryParseZoneAndWhitespace ( text , start + s_lzyyyy_MM_dd , out kind , out zoneHour , out zoneMinute ) )
120145 {
121- parsedValue = new DateAndTimeInfo ( date , 0 , 0 , kind . Value , 0 , 0 , DateTimeTypeCode . Date , zoneHour . Value , zoneMinute . Value ) ;
146+ parsedValue = new DateAndTimeInfo ( date , kind . Value , default , DateTimeTypeCode . Date , zoneHour . Value , zoneMinute . Value ) ;
122147 return true ;
123148 }
124149
125150 if ( ParseChar ( text , start + s_lzyyyy_MM_dd , 'T' )
126- && TryParseTimeAndZoneAndWhitespace ( text , start + s_lzyyyy_MM_ddT , out _ , out _ , out _ , out _ , out kind , out zoneHour , out zoneMinute ) )
151+ && TryParseTimeAndZoneAndWhitespace ( text , start + s_lzyyyy_MM_ddT , out kind , out _ , out zoneHour , out zoneMinute ) )
127152 {
128- parsedValue = new DateAndTimeInfo ( date , 0 , 0 , kind . Value , 0 , 0 , DateTimeTypeCode . Date , zoneHour . Value , zoneMinute . Value ) ;
153+ parsedValue = new DateAndTimeInfo ( date , kind . Value , default , DateTimeTypeCode . Date , zoneHour . Value , zoneMinute . Value ) ;
129154 return true ;
130155 }
131156 }
@@ -145,32 +170,34 @@ private static bool TryParseAsDateTime(
145170 | XsdDateAndTimeFlags . XdrDateTimeNoTz ;
146171
147172 DateInfo date ;
148- int ? hour , minute , second , fraction , zoneHour , zoneMinute ;
173+ TimeInfo time ;
174+ int ? zoneHour , zoneMinute ;
149175 XsdDateTimeKind ? kind ;
150176
151177 // Choose format starting from the most common and trying not to reparse the same thing too many times
152178 if ( Test ( kinds , dateTimeVariants ) && TryParseDate ( text , start , out date ) )
153179 {
154180 if ( Test ( kinds , XsdDateAndTimeFlags . DateTime ) &&
155181 ParseChar ( text , start + s_lzyyyy_MM_dd , 'T' ) &&
156- TryParseTimeAndZoneAndWhitespace ( text , start + s_lzyyyy_MM_ddT , out hour , out minute , out second , out fraction , out kind , out zoneHour , out zoneMinute ) )
182+ TryParseTimeAndZoneAndWhitespace ( text , start + s_lzyyyy_MM_ddT , out kind , out time , out zoneHour , out zoneMinute ) )
157183 {
158- parsedValue = new DateAndTimeInfo ( date , fraction . Value , hour . Value , kind . Value , minute . Value , second . Value , DateTimeTypeCode . DateTime , zoneHour . Value , zoneMinute . Value ) ;
184+ parsedValue = new DateAndTimeInfo ( date , kind . Value , time , DateTimeTypeCode . DateTime , zoneHour . Value , zoneMinute . Value ) ;
159185 return true ;
160186 }
161187
162188 if ( Test ( kinds , XsdDateAndTimeFlags . XdrDateTime ) )
163189 {
164190 if ( TryParseZoneAndWhitespace ( text , start + s_lzyyyy_MM_dd , out kind , out zoneHour , out zoneMinute ) )
165191 {
166- parsedValue = new DateAndTimeInfo ( date , 0 , 0 , kind . Value , 0 , 0 , DateTimeTypeCode . XdrDateTime , zoneHour . Value , zoneMinute . Value ) ;
192+ time = default ;
193+ parsedValue = new DateAndTimeInfo ( date , kind . Value , time , DateTimeTypeCode . XdrDateTime , zoneHour . Value , zoneMinute . Value ) ;
167194 return true ;
168195 }
169196
170197 if ( ParseChar ( text , start + s_lzyyyy_MM_dd , 'T' )
171- && TryParseTimeAndZoneAndWhitespace ( text , start + s_lzyyyy_MM_ddT , out hour , out minute , out second , out fraction , out kind , out zoneHour , out zoneMinute ) )
198+ && TryParseTimeAndZoneAndWhitespace ( text , start + s_lzyyyy_MM_ddT , out kind , out time , out zoneHour , out zoneMinute ) )
172199 {
173- parsedValue = new DateAndTimeInfo ( date , fraction . Value , hour . Value , kind . Value , minute . Value , second . Value , DateTimeTypeCode . XdrDateTime , zoneHour . Value , zoneMinute . Value ) ;
200+ parsedValue = new DateAndTimeInfo ( date , kind . Value , time , DateTimeTypeCode . XdrDateTime , zoneHour . Value , zoneMinute . Value ) ;
174201 return true ;
175202 }
176203 }
@@ -179,15 +206,16 @@ private static bool TryParseAsDateTime(
179206 {
180207 if ( ParseChar ( text , start + s_lzyyyy_MM_dd , 'T' ) )
181208 {
182- if ( ParseTimeAndWhitespace ( text , start + s_lzyyyy_MM_ddT , out hour , out minute , out second , out fraction ) )
209+ if ( ParseTimeAndWhitespace ( text , start + s_lzyyyy_MM_ddT , out time ) )
183210 {
184- parsedValue = new DateAndTimeInfo ( date , fraction . Value , hour . Value , XsdDateTimeKind . Unspecified , minute . Value , second . Value , DateTimeTypeCode . XdrDateTime , 0 , 0 ) ;
211+ parsedValue = new DateAndTimeInfo ( date , XsdDateTimeKind . Unspecified , time , DateTimeTypeCode . XdrDateTime , 0 , 0 ) ;
185212 return true ;
186213 }
187214 }
188215 else
189216 {
190- parsedValue = new DateAndTimeInfo ( date , 0 , 0 , XsdDateTimeKind . Unspecified , 0 , 0 , DateTimeTypeCode . XdrDateTime , 0 , 0 ) ;
217+ time = default ;
218+ parsedValue = new DateAndTimeInfo ( date , XsdDateTimeKind . Unspecified , time , DateTimeTypeCode . XdrDateTime , 0 , 0 ) ;
191219 return true ;
192220 }
193221 }
@@ -203,9 +231,10 @@ private static bool TryParseAsTime(
203231 int start ,
204232 out DateAndTimeInfo parsedValue )
205233 {
206- if ( Test ( kinds , XsdDateAndTimeFlags . Time ) && TryParseTimeAndZoneAndWhitespace ( text , start , out int ? hour , out int ? minute , out int ? second , out int ? fraction , out XsdDateTimeKind ? kind , out int ? zoneHour , out int ? zoneMinute ) )
234+ if ( Test ( kinds , XsdDateAndTimeFlags . Time )
235+ && TryParseTimeAndZoneAndWhitespace ( text , start , out XsdDateTimeKind ? kind , out TimeInfo time , out int ? zoneHour , out int ? zoneMinute ) )
207236 {
208- parsedValue = new DateAndTimeInfo ( DateInfo . DefaultValue , fraction . Value , hour . Value , kind . Value , minute . Value , second . Value , DateTimeTypeCode . Time , zoneHour . Value , zoneMinute . Value ) ;
237+ parsedValue = new DateAndTimeInfo ( DateInfo . DefaultValue , kind . Value , time , DateTimeTypeCode . Time , zoneHour . Value , zoneMinute . Value ) ;
209238 return true ;
210239 }
211240
@@ -219,9 +248,9 @@ private static bool TryParseAsXdrTimeNoTz(
219248 int start ,
220249 out DateAndTimeInfo parsedValue )
221250 {
222- if ( Test ( kinds , XsdDateAndTimeFlags . XdrTimeNoTz ) && ParseTimeAndWhitespace ( text , start , out int ? hour , out int ? minute , out int ? second , out int ? fraction ) )
251+ if ( Test ( kinds , XsdDateAndTimeFlags . XdrTimeNoTz ) && ParseTimeAndWhitespace ( text , start , out TimeInfo time ) )
223252 {
224- parsedValue = new DateAndTimeInfo ( DateInfo . DefaultValue , fraction . Value , hour . Value , XsdDateTimeKind . Unspecified , minute . Value , second . Value , DateTimeTypeCode . Time , default , default ) ;
253+ parsedValue = new DateAndTimeInfo ( DateInfo . DefaultValue , XsdDateTimeKind . Unspecified , time , DateTimeTypeCode . Time , default , default ) ;
225254 return true ;
226255 }
227256
@@ -249,19 +278,19 @@ private static bool TryParseAsGYearOrGYearMonth(
249278 TryParseZoneAndWhitespace ( text , start + s_lzyyyy_MM , out kind , out zoneHour , out zoneMinute ) )
250279 {
251280 date = new DateInfo ( DateInfo . FirstDay , month . Value , year . Value ) ;
252- parsedValue = new DateAndTimeInfo ( date , default , default , kind . Value , default , default , DateTimeTypeCode . GYearMonth , zoneHour . Value , zoneMinute . Value ) ;
281+ parsedValue = new DateAndTimeInfo ( date , kind . Value , default , DateTimeTypeCode . GYearMonth , zoneHour . Value , zoneMinute . Value ) ;
253282 return true ;
254283 }
255284
256285 if ( Test ( kinds , XsdDateAndTimeFlags . GYear ) && TryParseZoneAndWhitespace ( text , start + s_lzyyyy , out kind , out zoneHour , out zoneMinute ) )
257286 {
258287 date = new DateInfo ( DateInfo . FirstDay , DateInfo . FirstMonth , year . Value ) ;
259- parsedValue = new DateAndTimeInfo ( date , default , default , kind . Value , default , default , DateTimeTypeCode . GYear , zoneHour . Value , zoneMinute . Value ) ;
288+ parsedValue = new DateAndTimeInfo ( date , kind . Value , default , DateTimeTypeCode . GYear , zoneHour . Value , zoneMinute . Value ) ;
260289 return true ;
261290 }
262291 }
263292
264- parsedValue = new DateAndTimeInfo ( default , default , default , XsdDateTimeKind . Unspecified , default , default , default , default , default ) ;
293+ parsedValue = new DateAndTimeInfo ( default , XsdDateTimeKind . Unspecified , default , default , default , default ) ;
265294 return false ;
266295 }
267296
@@ -286,7 +315,7 @@ private static bool TryParseAsGMonthOrGMonthDay(
286315 TryParseZoneAndWhitespace ( text , start + s_lz__mm_dd , out kind , out zoneHour , out zoneMinute ) )
287316 {
288317 date = new DateInfo ( day . Value , month . Value , DateInfo . LeapYear ) ;
289- parsedValue = new DateAndTimeInfo ( date , default , default , kind . Value , default , default , DateTimeTypeCode . GMonthDay , zoneHour . Value , zoneMinute . Value ) ;
318+ parsedValue = new DateAndTimeInfo ( date , kind . Value , default , DateTimeTypeCode . GMonthDay , zoneHour . Value , zoneMinute . Value ) ;
290319 return true ;
291320 }
292321
@@ -297,7 +326,7 @@ private static bool TryParseAsGMonthOrGMonthDay(
297326 TryParseZoneAndWhitespace ( text , start + s_lz__mm__ , out kind , out zoneHour , out zoneMinute ) ) )
298327 {
299328 date = new DateInfo ( DateInfo . FirstDay , month . Value , DateInfo . LeapYear ) ;
300- parsedValue = new DateAndTimeInfo ( date , default , default , kind . Value , default , default , DateTimeTypeCode . GMonth , zoneHour . Value , zoneMinute . Value ) ;
329+ parsedValue = new DateAndTimeInfo ( date , kind . Value , default , DateTimeTypeCode . GMonth , zoneHour . Value , zoneMinute . Value ) ;
301330 return true ;
302331 }
303332 }
@@ -326,7 +355,7 @@ private static bool TryParseAsGDay(
326355 TryParseZoneAndWhitespace ( text , start + s_lz___dd , out kind , out zoneHour , out zoneMinute ) )
327356 {
328357 date = new DateInfo ( day . Value , DateInfo . FirstMonth , DateInfo . LeapYear ) ;
329- parsedValue = new DateAndTimeInfo ( date , default , default , kind . Value , default , default , DateTimeTypeCode . GDay , zoneHour . Value , zoneMinute . Value ) ;
358+ parsedValue = new DateAndTimeInfo ( date , kind . Value , default , DateTimeTypeCode . GDay , zoneHour . Value , zoneMinute . Value ) ;
330359
331360 return true ;
332361 }
@@ -422,11 +451,10 @@ private static bool TryParseDate(
422451 private static bool TryParseTime (
423452 string rawValue ,
424453 ref int start ,
425- [ NotNullWhen ( true ) ] out int ? hour ,
426- [ NotNullWhen ( true ) ] out int ? minute ,
427- [ NotNullWhen ( true ) ] out int ? second ,
428- [ NotNullWhen ( true ) ] out int ? fraction )
454+ out TimeInfo time )
429455 {
456+ int ? fraction , hour , minute , second ;
457+
430458 if (
431459 ParseTwoDigits ( rawValue , start , out hour ) && hour < 24 &&
432460 ParseChar ( rawValue , start + s_lzHH , ':' ) &&
@@ -475,6 +503,7 @@ private static bool TryParseTime(
475503 {
476504 if ( fractionDigits == 0 )
477505 {
506+ time = default ;
478507 return false ; // cannot end with .
479508 }
480509 fraction *= Power10 [ MaxFractionDigits - fractionDigits ] ;
@@ -493,47 +522,40 @@ private static bool TryParseTime(
493522 fraction = 0 ;
494523 }
495524
525+ time = new TimeInfo ( fraction . Value , hour . Value , minute . Value , second . Value ) ;
496526 return true ;
497527 }
498528
499- hour = default ;
500- minute = default ;
501- second = default ;
502- fraction = default ;
529+ time = default ;
503530 return false ;
504531 }
505532
506533 private static bool ParseTimeAndWhitespace (
507534 string rawValue ,
508535 int start ,
509- [ NotNullWhen ( true ) ] out int ? hour ,
510- [ NotNullWhen ( true ) ] out int ? minute ,
511- [ NotNullWhen ( true ) ] out int ? second ,
512- [ NotNullWhen ( true ) ] out int ? fraction )
536+ out TimeInfo time )
513537 {
514- if ( TryParseTime ( rawValue , ref start , out hour , out minute , out second , out fraction ) )
538+ if ( TryParseTime ( rawValue , ref start , out time ) )
515539 {
516540 while ( start < rawValue . Length )
517541 {
518542 start ++ ;
519543 }
520544 return start == rawValue . Length ;
521545 }
546+
522547 return false ;
523548 }
524549
525550 private static bool TryParseTimeAndZoneAndWhitespace (
526551 string rawValue ,
527552 int start ,
528- [ NotNullWhen ( true ) ] out int ? hour ,
529- [ NotNullWhen ( true ) ] out int ? minute ,
530- [ NotNullWhen ( true ) ] out int ? second ,
531- [ NotNullWhen ( true ) ] out int ? fraction ,
532553 [ NotNullWhen ( true ) ] out XsdDateTimeKind ? kind ,
554+ out TimeInfo time ,
533555 [ NotNullWhen ( true ) ] out int ? zoneHour ,
534556 [ NotNullWhen ( true ) ] out int ? zoneMinute )
535557 {
536- if ( TryParseTime ( rawValue , ref start , out hour , out minute , out second , out fraction ) )
558+ if ( TryParseTime ( rawValue , ref start , out time ) )
537559 {
538560 if ( TryParseZoneAndWhitespace ( rawValue , start , out kind , out zoneHour , out zoneMinute ) )
539561 {
0 commit comments