< prev index next >

src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java

Print this page




 804             @Override
 805             public Iterator<Entry<String, Long>> getTextIterator(TemporalField field, TextStyle style, Locale locale) {
 806                 return store.getTextIterator(style);
 807             }
 808         };
 809         appendInternal(new TextPrinterParser(field, TextStyle.FULL, provider));
 810         return this;
 811     }
 812 
 813     //-----------------------------------------------------------------------
 814     /**
 815      * Appends an instant using ISO-8601 to the formatter, formatting fractional
 816      * digits in groups of three.
 817      * <p>
 818      * Instants have a fixed output format.
 819      * They are converted to a date-time with a zone-offset of UTC and formatted
 820      * using the standard ISO-8601 format.
 821      * With this method, formatting nano-of-second outputs zero, three, six
 822      * or nine digits as necessary.
 823      * The localized decimal style is not used.

 824      * <p>
 825      * The instant is obtained using {@link ChronoField#INSTANT_SECONDS INSTANT_SECONDS}
 826      * and optionally {@code NANO_OF_SECOND}. The value of {@code INSTANT_SECONDS}
 827      * may be outside the maximum range of {@code LocalDateTime}.
 828      * <p>
 829      * The {@linkplain ResolverStyle resolver style} has no effect on instant parsing.
 830      * The end-of-day time of '24:00' is handled as midnight at the start of the following day.
 831      * The leap-second time of '23:59:59' is handled to some degree, see
 832      * {@link DateTimeFormatter#parsedLeapSecond()} for full details.
 833      * <p>
 834      * An alternative to this method is to format/parse the instant as a single
 835      * epoch-seconds value. That is achieved using {@code appendValue(INSTANT_SECONDS)}.
 836      *
 837      * @return this, for chaining, not null
 838      */
 839     public DateTimeFormatterBuilder appendInstant() {
 840         appendInternal(new InstantPrinterParser(-2));
 841         return this;
 842     }
 843 


3445                     buf.append((char) (digit + '0'));
3446                     inNano = inNano - (digit * div);
3447                     div = div / 10;
3448                 }
3449             }
3450             buf.append('Z');
3451             return true;
3452         }
3453 
3454         @Override
3455         public int parse(DateTimeParseContext context, CharSequence text, int position) {
3456             // new context to avoid overwriting fields like year/month/day
3457             int minDigits = (fractionalDigits < 0 ? 0 : fractionalDigits);
3458             int maxDigits = (fractionalDigits < 0 ? 9 : fractionalDigits);
3459             CompositePrinterParser parser = new DateTimeFormatterBuilder()
3460                     .append(DateTimeFormatter.ISO_LOCAL_DATE).appendLiteral('T')
3461                     .appendValue(HOUR_OF_DAY, 2).appendLiteral(':')
3462                     .appendValue(MINUTE_OF_HOUR, 2).appendLiteral(':')
3463                     .appendValue(SECOND_OF_MINUTE, 2)
3464                     .appendFraction(NANO_OF_SECOND, minDigits, maxDigits, true)
3465                     .appendLiteral('Z')
3466                     .toFormatter().toPrinterParser(false);
3467             DateTimeParseContext newContext = context.copy();
3468             int pos = parser.parse(newContext, text, position);
3469             if (pos < 0) {
3470                 return pos;
3471             }
3472             // parser restricts most fields to 2 digits, so definitely int
3473             // correctly parsed nano is also guaranteed to be valid
3474             long yearParsed = newContext.getParsed(YEAR);
3475             int month = newContext.getParsed(MONTH_OF_YEAR).intValue();
3476             int day = newContext.getParsed(DAY_OF_MONTH).intValue();
3477             int hour = newContext.getParsed(HOUR_OF_DAY).intValue();
3478             int min = newContext.getParsed(MINUTE_OF_HOUR).intValue();
3479             Long secVal = newContext.getParsed(SECOND_OF_MINUTE);
3480             Long nanoVal = newContext.getParsed(NANO_OF_SECOND);
3481             int sec = (secVal != null ? secVal.intValue() : 0);
3482             int nano = (nanoVal != null ? nanoVal.intValue() : 0);

3483             int days = 0;
3484             if (hour == 24 && min == 0 && sec == 0 && nano == 0) {
3485                 hour = 0;
3486                 days = 1;
3487             } else if (hour == 23 && min == 59 && sec == 60) {
3488                 context.setParsedLeapSecond();
3489                 sec = 59;
3490             }
3491             int year = (int) yearParsed % 10_000;
3492             long instantSecs;
3493             try {
3494                 LocalDateTime ldt = LocalDateTime.of(year, month, day, hour, min, sec, 0).plusDays(days);
3495                 instantSecs = ldt.toEpochSecond(ZoneOffset.UTC);
3496                 instantSecs += Math.multiplyExact(yearParsed / 10_000L, SECONDS_PER_10000_YEARS);
3497             } catch (RuntimeException ex) {
3498                 return ~position;
3499             }
3500             int successPos = pos;
3501             successPos = context.setParsedField(INSTANT_SECONDS, instantSecs, position, successPos);
3502             return context.setParsedField(NANO_OF_SECOND, nano, position, successPos);
3503         }
3504 
3505         @Override
3506         public String toString() {
3507             return "Instant()";
3508         }
3509     }
3510 
3511     //-----------------------------------------------------------------------
3512     /**
3513      * Prints or parses an offset ID.
3514      */
3515     static final class OffsetIdPrinterParser implements DateTimePrinterParser {




 804             @Override
 805             public Iterator<Entry<String, Long>> getTextIterator(TemporalField field, TextStyle style, Locale locale) {
 806                 return store.getTextIterator(style);
 807             }
 808         };
 809         appendInternal(new TextPrinterParser(field, TextStyle.FULL, provider));
 810         return this;
 811     }
 812 
 813     //-----------------------------------------------------------------------
 814     /**
 815      * Appends an instant using ISO-8601 to the formatter, formatting fractional
 816      * digits in groups of three.
 817      * <p>
 818      * Instants have a fixed output format.
 819      * They are converted to a date-time with a zone-offset of UTC and formatted
 820      * using the standard ISO-8601 format.
 821      * With this method, formatting nano-of-second outputs zero, three, six
 822      * or nine digits as necessary.
 823      * The localized decimal style is not used.
 824      * During parsing, any offset if available is accepted.
 825      * <p>
 826      * The instant is obtained using {@link ChronoField#INSTANT_SECONDS INSTANT_SECONDS}
 827      * and optionally {@code NANO_OF_SECOND}. The value of {@code INSTANT_SECONDS}
 828      * may be outside the maximum range of {@code LocalDateTime}.
 829      * <p>
 830      * The {@linkplain ResolverStyle resolver style} has no effect on instant parsing.
 831      * The end-of-day time of '24:00' is handled as midnight at the start of the following day.
 832      * The leap-second time of '23:59:59' is handled to some degree, see
 833      * {@link DateTimeFormatter#parsedLeapSecond()} for full details.
 834      * <p>
 835      * An alternative to this method is to format/parse the instant as a single
 836      * epoch-seconds value. That is achieved using {@code appendValue(INSTANT_SECONDS)}.
 837      *
 838      * @return this, for chaining, not null
 839      */
 840     public DateTimeFormatterBuilder appendInstant() {
 841         appendInternal(new InstantPrinterParser(-2));
 842         return this;
 843     }
 844 


3446                     buf.append((char) (digit + '0'));
3447                     inNano = inNano - (digit * div);
3448                     div = div / 10;
3449                 }
3450             }
3451             buf.append('Z');
3452             return true;
3453         }
3454 
3455         @Override
3456         public int parse(DateTimeParseContext context, CharSequence text, int position) {
3457             // new context to avoid overwriting fields like year/month/day
3458             int minDigits = (fractionalDigits < 0 ? 0 : fractionalDigits);
3459             int maxDigits = (fractionalDigits < 0 ? 9 : fractionalDigits);
3460             CompositePrinterParser parser = new DateTimeFormatterBuilder()
3461                     .append(DateTimeFormatter.ISO_LOCAL_DATE).appendLiteral('T')
3462                     .appendValue(HOUR_OF_DAY, 2).appendLiteral(':')
3463                     .appendValue(MINUTE_OF_HOUR, 2).appendLiteral(':')
3464                     .appendValue(SECOND_OF_MINUTE, 2)
3465                     .appendFraction(NANO_OF_SECOND, minDigits, maxDigits, true)
3466                     .appendOffsetId()
3467                     .toFormatter().toPrinterParser(false);
3468             DateTimeParseContext newContext = context.copy();
3469             int pos = parser.parse(newContext, text, position);
3470             if (pos < 0) {
3471                 return pos;
3472             }
3473             // parser restricts most fields to 2 digits, so definitely int
3474             // correctly parsed nano is also guaranteed to be valid
3475             long yearParsed = newContext.getParsed(YEAR);
3476             int month = newContext.getParsed(MONTH_OF_YEAR).intValue();
3477             int day = newContext.getParsed(DAY_OF_MONTH).intValue();
3478             int hour = newContext.getParsed(HOUR_OF_DAY).intValue();
3479             int min = newContext.getParsed(MINUTE_OF_HOUR).intValue();
3480             Long secVal = newContext.getParsed(SECOND_OF_MINUTE);
3481             Long nanoVal = newContext.getParsed(NANO_OF_SECOND);
3482             int sec = (secVal != null ? secVal.intValue() : 0);
3483             int nano = (nanoVal != null ? nanoVal.intValue() : 0);
3484             int offset = newContext.getParsed(OFFSET_SECONDS).intValue();
3485             int days = 0;
3486             if (hour == 24 && min == 0 && sec == 0 && nano == 0) {
3487                 hour = 0;
3488                 days = 1;
3489             } else if (hour == 23 && min == 59 && sec == 60) {
3490                 context.setParsedLeapSecond();
3491                 sec = 59;
3492             }
3493             int year = (int) yearParsed % 10_000;
3494             long instantSecs;
3495             try {
3496                 LocalDateTime ldt = LocalDateTime.of(year, month, day, hour, min, sec, 0).plusDays(days);
3497                 instantSecs = ldt.toEpochSecond(ZoneOffset.ofTotalSeconds(offset));
3498                 instantSecs += Math.multiplyExact(yearParsed / 10_000L, SECONDS_PER_10000_YEARS);
3499             } catch (RuntimeException ex) {
3500                 return ~position;
3501             }
3502             int successPos = pos;
3503             successPos = context.setParsedField(INSTANT_SECONDS, instantSecs, position, successPos);
3504             return context.setParsedField(NANO_OF_SECOND, nano, position, successPos);
3505         }
3506 
3507         @Override
3508         public String toString() {
3509             return "Instant()";
3510         }
3511     }
3512 
3513     //-----------------------------------------------------------------------
3514     /**
3515      * Prints or parses an offset ID.
3516      */
3517     static final class OffsetIdPrinterParser implements DateTimePrinterParser {


< prev index next >