jdk/src/java.base/share/classes/java/time/Duration.java
changeset 25991 e48157b42439
parent 25986 12bcf9a5994f
parent 25859 3317bb8137f4
child 26462 d6d34934be12
equal deleted inserted replaced
25876:d06a6d3c66c0 25991:e48157b42439
   386     public static Duration parse(CharSequence text) {
   386     public static Duration parse(CharSequence text) {
   387         Objects.requireNonNull(text, "text");
   387         Objects.requireNonNull(text, "text");
   388         Matcher matcher = PATTERN.matcher(text);
   388         Matcher matcher = PATTERN.matcher(text);
   389         if (matcher.matches()) {
   389         if (matcher.matches()) {
   390             // check for letter T but no time sections
   390             // check for letter T but no time sections
   391             if ("T".equals(matcher.group(3)) == false) {
   391             if (!charMatch(text, matcher.start(3), matcher.end(3), 'T')) {
   392                 boolean negate = "-".equals(matcher.group(1));
   392                 boolean negate = charMatch(text, matcher.start(1), matcher.end(1), '-');
   393                 String dayMatch = matcher.group(2);
   393 
   394                 String hourMatch = matcher.group(4);
   394                 int dayStart = matcher.start(2), dayEnd = matcher.end(2);
   395                 String minuteMatch = matcher.group(5);
   395                 int hourStart = matcher.start(4), hourEnd = matcher.end(4);
   396                 String secondMatch = matcher.group(6);
   396                 int minuteStart = matcher.start(5), minuteEnd = matcher.end(5);
   397                 String fractionMatch = matcher.group(7);
   397                 int secondStart = matcher.start(6), secondEnd = matcher.end(6);
   398                 if (dayMatch != null || hourMatch != null || minuteMatch != null || secondMatch != null) {
   398                 int fractionStart = matcher.start(7), fractionEnd = matcher.end(7);
   399                     long daysAsSecs = parseNumber(text, dayMatch, SECONDS_PER_DAY, "days");
   399 
   400                     long hoursAsSecs = parseNumber(text, hourMatch, SECONDS_PER_HOUR, "hours");
   400                 if (dayStart >= 0 || hourStart >= 0 || minuteStart >= 0 || secondStart >= 0) {
   401                     long minsAsSecs = parseNumber(text, minuteMatch, SECONDS_PER_MINUTE, "minutes");
   401                     long daysAsSecs = parseNumber(text, dayStart, dayEnd, SECONDS_PER_DAY, "days");
   402                     long seconds = parseNumber(text, secondMatch, 1, "seconds");
   402                     long hoursAsSecs = parseNumber(text, hourStart, hourEnd, SECONDS_PER_HOUR, "hours");
   403                     int nanos = parseFraction(text,  fractionMatch, seconds < 0 ? -1 : 1);
   403                     long minsAsSecs = parseNumber(text, minuteStart, minuteEnd, SECONDS_PER_MINUTE, "minutes");
       
   404                     long seconds = parseNumber(text, secondStart, secondEnd, 1, "seconds");
       
   405                     int nanos = parseFraction(text, fractionStart, fractionEnd, seconds < 0 ? -1 : 1);
   404                     try {
   406                     try {
   405                         return create(negate, daysAsSecs, hoursAsSecs, minsAsSecs, seconds, nanos);
   407                         return create(negate, daysAsSecs, hoursAsSecs, minsAsSecs, seconds, nanos);
   406                     } catch (ArithmeticException ex) {
   408                     } catch (ArithmeticException ex) {
   407                         throw (DateTimeParseException) new DateTimeParseException("Text cannot be parsed to a Duration: overflow", text, 0).initCause(ex);
   409                         throw (DateTimeParseException) new DateTimeParseException("Text cannot be parsed to a Duration: overflow", text, 0).initCause(ex);
   408                     }
   410                     }
   410             }
   412             }
   411         }
   413         }
   412         throw new DateTimeParseException("Text cannot be parsed to a Duration", text, 0);
   414         throw new DateTimeParseException("Text cannot be parsed to a Duration", text, 0);
   413     }
   415     }
   414 
   416 
   415     private static long parseNumber(CharSequence text, String parsed, int multiplier, String errorText) {
   417     private static boolean charMatch(CharSequence text, int start, int end, char c) {
       
   418         return (start >= 0 && end == start + 1 && text.charAt(start) == c);
       
   419     }
       
   420 
       
   421     private static long parseNumber(CharSequence text, int start, int end, int multiplier, String errorText) {
   416         // regex limits to [-+]?[0-9]+
   422         // regex limits to [-+]?[0-9]+
   417         if (parsed == null) {
   423         if (start < 0 || end < 0) {
   418             return 0;
   424             return 0;
   419         }
   425         }
   420         try {
   426         try {
   421             long val = Long.parseLong(parsed);
   427             long val = Long.parseLong(text, 10, start, end);
   422             return Math.multiplyExact(val, multiplier);
   428             return Math.multiplyExact(val, multiplier);
   423         } catch (NumberFormatException | ArithmeticException ex) {
   429         } catch (NumberFormatException | ArithmeticException ex) {
   424             throw (DateTimeParseException) new DateTimeParseException("Text cannot be parsed to a Duration: " + errorText, text, 0).initCause(ex);
   430             throw (DateTimeParseException) new DateTimeParseException("Text cannot be parsed to a Duration: " + errorText, text, 0).initCause(ex);
   425         }
   431         }
   426     }
   432     }
   427 
   433 
   428     private static int parseFraction(CharSequence text, String parsed, int negate) {
   434     private static int parseFraction(CharSequence text, int start, int end, int negate) {
   429         // regex limits to [0-9]{0,9}
   435         // regex limits to [0-9]{0,9}
   430         if (parsed == null || parsed.length() == 0) {
   436         if (start < 0 || end < 0 || end - start == 0) {
   431             return 0;
   437             return 0;
   432         }
   438         }
   433         try {
   439         try {
   434             parsed = (parsed + "000000000").substring(0, 9);
   440             int fraction = Integer.parseInt(text, 10, start, end);
   435             return Integer.parseInt(parsed) * negate;
   441 
       
   442             // for number strings smaller than 9 digits, interpret as if there
       
   443             // were trailing zeros
       
   444             for (int i = end - start; i < 9; i++) {
       
   445                 fraction *= 10;
       
   446             }
       
   447             return fraction * negate;
   436         } catch (NumberFormatException | ArithmeticException ex) {
   448         } catch (NumberFormatException | ArithmeticException ex) {
   437             throw (DateTimeParseException) new DateTimeParseException("Text cannot be parsed to a Duration: fraction", text, 0).initCause(ex);
   449             throw (DateTimeParseException) new DateTimeParseException("Text cannot be parsed to a Duration: fraction", text, 0).initCause(ex);
   438         }
   450         }
   439     }
   451     }
   440 
   452