@@ -132,22 +132,40 @@ public XsdDateTime(string text, XsdDateTimeFlags kinds) : this()
132132 {
133133 throw new FormatException ( SR . Format ( SR . XmlConvert_BadFormat , text , kinds ) ) ;
134134 }
135- InitiateXsdDateTime ( parser ) ;
135+ if ( ! TryInitiateXsdDateTime ( parser ) )
136+ {
137+ throw new FormatException ( SR . Format ( SR . XmlConvert_BadFormat , text , kinds ) ) ;
138+ }
136139 }
137140
138- private XsdDateTime ( Parser parser ) : this ( )
141+ private bool TryInitiateXsdDateTime ( Parser parser )
139142 {
140- InitiateXsdDateTime ( parser ) ;
141- }
143+ // Per ISO 8601, 24:00:00 represents end of a calendar day
144+ // (same instant as next day's 00:00:00). Set hour to 0 and add one day.
145+ int hour = parser . hour ;
146+ bool isEndOfDay = hour == 24 ;
147+ if ( isEndOfDay )
148+ {
149+ hour = 0 ;
150+ }
142151
143- private void InitiateXsdDateTime ( Parser parser )
144- {
145- _dt = new DateTime ( parser . year , parser . month , parser . day , parser . hour , parser . minute , parser . second ) ;
152+ _dt = new DateTime ( parser . year , parser . month , parser . day , hour , parser . minute , parser . second ) ;
146153 if ( parser . fraction != 0 )
147154 {
148155 _dt = _dt . AddTicks ( parser . fraction ) ;
149156 }
157+
158+ if ( isEndOfDay )
159+ {
160+ if ( _dt . Ticks > DateTime . MaxValue . Ticks - TimeSpan . TicksPerDay )
161+ {
162+ return false ;
163+ }
164+ _dt = _dt . AddDays ( 1 ) ;
165+ }
166+
150167 _extra = ( uint ) ( ( ( int ) parser . typeCode << TypeShift ) | ( ( int ) parser . kind << KindShift ) | ( parser . zoneHour << ZoneHourShift ) | parser . zoneMinute ) ;
168+ return true ;
151169 }
152170
153171 internal static bool TryParse ( string text , XsdDateTimeFlags kinds , out XsdDateTime result )
@@ -158,7 +176,11 @@ internal static bool TryParse(string text, XsdDateTimeFlags kinds, out XsdDateTi
158176 result = default ;
159177 return false ;
160178 }
161- result = new XsdDateTime ( parser ) ;
179+ result = default ;
180+ if ( ! result . TryInitiateXsdDateTime ( parser ) )
181+ {
182+ return false ;
183+ }
162184 return true ;
163185 }
164186
@@ -917,7 +939,7 @@ private bool ParseTimeAndWhitespace(int start)
917939 private bool ParseTime ( ref int start )
918940 {
919941 if (
920- Parse2Dig ( start , ref hour ) && hour < 24 &&
942+ Parse2Dig ( start , ref hour ) && hour <= 24 &&
921943 ParseChar ( start + s_lzHH , ':' ) &&
922944 Parse2Dig ( start + s_lzHH_ , ref minute ) && minute < 60 &&
923945 ParseChar ( start + s_lzHH_mm , ':' ) &&
@@ -977,6 +999,14 @@ private bool ParseTime(ref int start)
977999 fraction += round ;
9781000 }
9791001 }
1002+
1003+ // Per ISO 8601, 24:00:00 represents end of a calendar day
1004+ // (same instant as next day's 00:00:00), but only when minute, second, and fraction are all zero.
1005+ if ( hour == 24 && ( minute != 0 || second != 0 || fraction != 0 ) )
1006+ {
1007+ return false ;
1008+ }
1009+
9801010 return true ;
9811011 }
9821012 // cleanup - conflict with gYear
0 commit comments