2121 */
2222
2323import static com .ethlo .time .internal .fixed .ITUParser .DIGITS_IN_NANO ;
24- import static com .ethlo .time .internal .fixed .ITUParser .RADIX ;
2524import static com .ethlo .time .internal .fixed .ITUParser .sanityCheckInputParams ;
26- import static com .ethlo .time .internal .util .LimitedCharArrayIntegerUtil .DIGIT_9 ;
2725import static com .ethlo .time .internal .util .LimitedCharArrayIntegerUtil .ZERO ;
2826
2927import java .time .format .DateTimeParseException ;
@@ -90,7 +88,8 @@ private static int readUntilNonDigit(final String chars, final int offset, final
9088 while (idx < len )
9189 {
9290 final char c = chars .charAt (idx );
93- if (c < ZERO || c > DIGIT_9 )
91+ int isDigit = (c - '0' ) >>> 31 | ('9' - c ) >>> 31 ;
92+ if (isDigit != 0 )
9493 {
9594 unit = c ;
9695 break ;
@@ -105,7 +104,8 @@ private static int readUntilNonDigit(final String chars, final int offset, final
105104 throw new DateTimeParseException ("Numeric overflow while parsing value" , chars , idx );
106105 }
107106
108- value = value * RADIX + digit ;
107+ value = (value << 3 ) + (value << 1 ) + (c - '0' );
108+ //value = value * RADIX + digit;
109109 idx ++;
110110 }
111111 }
@@ -135,11 +135,11 @@ private static class DurationPartsConsumer
135135 private boolean readingFractionalPart ;
136136 private boolean afterT ;
137137 private boolean pFound ;
138- private boolean wFound ;
139- private boolean dFound ;
140- private boolean hFound ;
141- private boolean mFound ;
142- private boolean sFound ;
138+ private int wFound ;
139+ private int dFound ;
140+ private int hFound ;
141+ private int mFound ;
142+ private int sFound ;
143143 private boolean dotFound ;
144144 private boolean fractionsFound ;
145145
@@ -149,6 +149,11 @@ private DurationPartsConsumer(final int startOffset, boolean negative)
149149 this .negative = negative ;
150150 }
151151
152+ private static DateTimeParseException error (String chars , int index )
153+ {
154+ return new DateTimeParseException ("Units must be in order from largest to smallest" , chars , index );
155+ }
156+
152157 public final void accept (final String chars , final int index , final int length , final char unit , final int value )
153158 {
154159 final int relIndex = index - startOffset ;
@@ -195,7 +200,7 @@ public final void accept(final String chars, final int index, final int length,
195200
196201 case 'W' :
197202 assertNonFractional ('W' , chars , index );
198- if (wFound )
203+ if (wFound > 0 )
199204 {
200205 throw new DateTimeParseException ("'W' (week) can only appear once" , chars , index );
201206 }
@@ -205,12 +210,12 @@ public final void accept(final String chars, final int index, final int length,
205210 throw new DateTimeParseException ("'W' (week) must appear before 'T' in the duration" , chars , index );
206211 }
207212 seconds += value * 604800L ; // 7 * 86400
208- wFound = true ;
213+ wFound = index ;
209214 break ;
210215
211216 case 'D' :
212217 assertNonFractional ('D' , chars , index );
213- if (dFound )
218+ if (dFound > 0 )
214219 {
215220 throw new DateTimeParseException ("'D' (days) can only appear once" , chars , index );
216221 }
@@ -219,12 +224,12 @@ public final void accept(final String chars, final int index, final int length,
219224 throw new DateTimeParseException ("'D' (days) must appear before 'T' in the duration" , chars , index );
220225 }
221226 seconds += value * 86400L ;
222- dFound = true ;
227+ dFound = index ;
223228 break ;
224229
225230 case 'H' :
226231 assertNonFractional ('H' , chars , index );
227- if (hFound )
232+ if (hFound > 0 )
228233 {
229234 throw new DateTimeParseException ("'H' (hours) can only appear once" , chars , index );
230235 }
@@ -233,12 +238,12 @@ public final void accept(final String chars, final int index, final int length,
233238 throw new DateTimeParseException ("'H' (hours) must appear after 'T' in the duration" , chars , index );
234239 }
235240 seconds += value * 3600L ;
236- hFound = true ;
241+ hFound = index ;
237242 break ;
238243
239244 case 'M' :
240245 assertNonFractional ('M' , chars , index );
241- if (mFound )
246+ if (mFound > 0 )
242247 {
243248 throw new DateTimeParseException ("'M' (minutes) can only appear once" , chars , index );
244249 }
@@ -247,19 +252,19 @@ public final void accept(final String chars, final int index, final int length,
247252 throw new DateTimeParseException ("'M' (minutes) must appear after 'T' in the duration" , chars , index );
248253 }
249254 seconds += value * 60L ;
250- mFound = true ;
255+ mFound = index ;
251256 break ;
252257
253258 case 'S' :
254- if (sFound )
259+ if (sFound > 0 )
255260 {
256261 throw new DateTimeParseException ("'S' (seconds) can only appear once" , chars , index );
257262 }
258263 if (!afterT )
259264 {
260265 throw new DateTimeParseException ("'S' (seconds) must appear after 'T' in the duration" , chars , index );
261266 }
262- sFound = true ;
267+ sFound = index ;
263268
264269 if (readingFractionalPart )
265270 {
@@ -323,7 +328,7 @@ private void assertNonFractional(final char unit, final String chars, final int
323328
324329 public void validate (String chars , int index )
325330 {
326- if (afterT && ! hFound && ! mFound && ! sFound )
331+ if (afterT && hFound == 0 && mFound == 0 && sFound == 0 )
327332 {
328333 throw new DateTimeParseException ("Expected at least value and unit after the 'T'" , chars , index );
329334 }
@@ -333,15 +338,52 @@ public void validate(String chars, int index)
333338 throw new DateTimeParseException ("Expected at least one fractional digit after the dot" , chars , index );
334339 }
335340
336- if (fractionsFound && ! sFound )
341+ if (fractionsFound && sFound == 0 )
337342 {
338343 throw new DateTimeParseException ("Expected 'S' after fractional number" , chars , index );
339344 }
340345
341- if (! wFound && ! dFound && ! hFound && ! mFound && ! sFound )
346+ if (wFound == 0 && dFound == 0 && hFound == 0 && mFound == 0 && sFound == 0 )
342347 {
343348 throw new DateTimeParseException ("Expected at least one value and unit" , chars , index );
344349 }
350+
351+ valdateUnitOrder (chars );
352+ }
353+
354+ private void valdateUnitOrder (String chars )
355+ {
356+ int lastIndex = -1 ;
357+
358+ if (wFound > 0 )
359+ {
360+ if (wFound < lastIndex ) throw error (chars , wFound );
361+ lastIndex = wFound ;
362+ }
363+
364+ if (dFound > 0 )
365+ {
366+ if (dFound < lastIndex ) throw error (chars , dFound );
367+ lastIndex = dFound ;
368+ }
369+
370+ if (hFound > 0 )
371+ {
372+ if (hFound < lastIndex ) throw error (chars , hFound );
373+ lastIndex = hFound ;
374+ }
375+
376+ if (mFound > 0 )
377+ {
378+ if (mFound < lastIndex ) throw error (chars , mFound );
379+ lastIndex = mFound ;
380+ }
381+
382+ if (sFound > 0 )
383+ {
384+ if (sFound < lastIndex ) throw error (chars , sFound );
385+ lastIndex = sFound ;
386+ }
345387 }
346388
347389 public Duration getResult ()
0 commit comments