< prev index next >

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

Print this page




 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 
 844     /**
 845      * Appends an instant using ISO-8601 to the formatter with control over
 846      * the number of fractional digits.
 847      * <p>
 848      * Instants have a fixed output format, although this method provides some
 849      * control over the fractional digits. They are converted to a date-time
 850      * with a zone-offset of UTC and printed using the standard ISO-8601 format.
 851      * The localized decimal style is not used.
 852      * <p>
 853      * The {@code fractionalDigits} parameter allows the output of the fractional


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 {




 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      * When formatting, the instant will always be suffixed by 'Z' to indicate UTC.
 835      * When parsing, the behaviour of {@link DateTimeFormatterBuilder#appendOffsetId()} will be used to parse the offset,
 836      * converting the instant to UTC as necessary.
 837      * <p>
 838      * An alternative to this method is to format/parse the instant as a single
 839      * epoch-seconds value. That is achieved using {@code appendValue(INSTANT_SECONDS)}.
 840      *
 841      * @return this, for chaining, not null
 842      */
 843     public DateTimeFormatterBuilder appendInstant() {
 844         appendInternal(new InstantPrinterParser(-2));
 845         return this;
 846     }
 847 
 848     /**
 849      * Appends an instant using ISO-8601 to the formatter with control over
 850      * the number of fractional digits.
 851      * <p>
 852      * Instants have a fixed output format, although this method provides some
 853      * control over the fractional digits. They are converted to a date-time
 854      * with a zone-offset of UTC and printed using the standard ISO-8601 format.
 855      * The localized decimal style is not used.
 856      * <p>
 857      * The {@code fractionalDigits} parameter allows the output of the fractional


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


< prev index next >