--- old/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java 2018-09-19 14:14:07.477585800 +0530 +++ new/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java 2018-09-19 14:14:05.802592800 +0530 @@ -647,12 +647,12 @@ appendInternal(pp.withFixedWidth()); // Retain the previous active parser active.valueParserIndex = activeValueParser; - } else { + } else { // Modify the active parser to be fixed width basePP = basePP.withFixedWidth(); // The new parser becomes the mew active parser active.valueParserIndex = appendInternal(pp); - } + } // Replace the modified parser with the updated one active.printerParsers.set(activeValueParser, basePP); } else { @@ -3456,14 +3456,27 @@ // new context to avoid overwriting fields like year/month/day int minDigits = (fractionalDigits < 0 ? 0 : fractionalDigits); int maxDigits = (fractionalDigits < 0 ? 9 : fractionalDigits); - CompositePrinterParser parser = new DateTimeFormatterBuilder() + boolean offsetPresent = false; + int length = text.length(); + String pattern = "+HH:mm"; + String noOffsetText = "0"; + if((text.charAt(length - 3) == '+' && text.subSequence(length - 3, length).toString().equals("+00")) + || (text.charAt(length - 5) == '+' && text.subSequence(length - 5, length).toString().equals("+0000")) + || (text.charAt(length - 6) == '+' && text.subSequence(length - 6, length).toString().equals("+00:00"))) { + offsetPresent = true; + if(text.charAt(length - 5) == '+') { + pattern = "+HHmm"; + } + } + DateTimeFormatterBuilder builder = new DateTimeFormatterBuilder() .append(DateTimeFormatter.ISO_LOCAL_DATE).appendLiteral('T') .appendValue(HOUR_OF_DAY, 2).appendLiteral(':') .appendValue(MINUTE_OF_HOUR, 2).appendLiteral(':') .appendValue(SECOND_OF_MINUTE, 2) - .appendFraction(NANO_OF_SECOND, minDigits, maxDigits, true) - .appendLiteral('Z') - .toFormatter().toPrinterParser(false); + .appendFraction(NANO_OF_SECOND, minDigits, maxDigits, true); + + builder = (offsetPresent) ? builder.appendOffset(pattern, noOffsetText) : builder.appendLiteral('Z'); + CompositePrinterParser parser = builder.toFormatter().toPrinterParser(false); DateTimeParseContext newContext = context.copy(); int pos = parser.parse(newContext, text, position); if (pos < 0) { --- old/test/jdk/java/time/tck/java/time/format/TCKInstantPrinterParser.java 2018-09-19 14:14:18.449334500 +0530 +++ new/test/jdk/java/time/tck/java/time/format/TCKInstantPrinterParser.java 2018-09-19 14:14:16.879742100 +0530 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -75,6 +75,11 @@ import org.testng.annotations.DataProvider; import org.testng.annotations.Test; +/* + * @test + * @bug 8166138 + */ + /** * Test DateTimeFormatterBuilder.appendInstant(). */ @@ -202,18 +207,34 @@ {0, 0, "1970-01-01T00:00:00.000Z"}, {0, 0, "1970-01-01T00:00:00.000000000Z"}, + {0, 0, "1970-01-01T00:00:00+00:00"}, + {0, 0, "1970-01-01T00:00:00+00:00"}, + {0, 0, "1970-01-01T00:00:00.0+00:00"}, + {0, 0, "1970-01-01T00:00:00.000+00:00"}, + {-1, 0, "1969-12-31T23:59:59Z"}, {1, 0, "1970-01-01T00:00:01Z"}, {60, 0, "1970-01-01T00:01:00Z"}, {3600, 0, "1970-01-01T01:00:00Z"}, {86400, 0, "1970-01-02T00:00:00Z"}, + {-1, 0, "1969-12-31T23:59:59+0000"}, + {1, 0, "1970-01-01T00:00:01+0000"}, + {60, 0, "1970-01-01T00:01:00+0000"}, + {3600, 0, "1970-01-01T01:00:00+0000"}, + {86400, 0, "1970-01-02T00:00:00+0000"}, + {182, 234000000, "1970-01-01T00:03:02.234Z"}, {182, 234000000, "1970-01-01T00:03:02.2340Z"}, {182, 234000000, "1970-01-01T00:03:02.23400Z"}, {182, 234000000, "1970-01-01T00:03:02.234000Z"}, {182, 234000000, "1970-01-01T00:03:02.234000000Z"}, + {182, 234000000, "1970-01-01T00:03:02.234+00"}, + {182, 234000000, "1970-01-01T00:03:02.2340+00"}, + {182, 234000000, "1970-01-01T00:03:02.23400+00"}, + {182, 234000000, "1970-01-01T00:03:02.234000+00"}, + {((23 * 60) + 59) * 60 + 59, 123456789, "1970-01-01T23:59:59.123456789Z"}, {Instant.MAX.getEpochSecond(), 999999999, "+1000000000-12-31T23:59:59.999999999Z"}, @@ -248,6 +269,40 @@ } } + @DataProvider(name="parseDigitsWithOffsets") + Object[][] data_parse_ninedigits() { + return new Object[][] { + {0, 0, "1970-01-01T00:00:00.000000000+00:00"}, + {0, 0, "1970-01-01T00:00:00.000000000+0000"}, + {0, 0, "1970-01-01T00:00:00.000000000+00"}, + + {182, 234000000, "1970-01-01T00:03:02.234000000+00:00"}, + {182, 234000000, "1970-01-01T00:03:02.234000000+0000"}, + {182, 234000000, "1970-01-01T00:03:02.234000000+00"}, + + {((23 * 60) + 59) * 60 + 59, 123456789, "1970-01-01T23:59:59.123456789+00:00"}, + {((23 * 60) + 59) * 60 + 59, 123456789, "1970-01-01T23:59:59.123456789+0000"}, + {((23 * 60) + 59) * 60 + 59, 123456789, "1970-01-01T23:59:59.123456789+00"}, + + {Instant.MAX.getEpochSecond(), 999999999, "+1000000000-12-31T23:59:59.999999999+00:00"}, + {Instant.MAX.getEpochSecond(), 999999999, "+1000000000-12-31T23:59:59.999999999+0000"}, + {Instant.MAX.getEpochSecond(), 999999999, "+1000000000-12-31T23:59:59.999999999+00"}, + + {Instant.MIN.getEpochSecond(), 0, "-1000000000-01-01T00:00:00.000000000+00:00"}, + {Instant.MIN.getEpochSecond(), 0, "-1000000000-01-01T00:00:00.000000000+0000"}, + {Instant.MIN.getEpochSecond(), 0, "-1000000000-01-01T00:00:00.000000000+00"}, + }; + } + + @Test(dataProvider="parseDigitsWithOffsets") + public void test_parse_digitsNine_withOffset(long instantSecs, int nano, String input) { + DateTimeFormatter f = new DateTimeFormatterBuilder().appendInstant(9).toFormatter(); + Instant expected = Instant.ofEpochSecond(instantSecs, nano); + assertEquals(f.parse(input, Instant::from), expected); + assertEquals(f.parse(input).query(DateTimeFormatter.parsedExcessDays()), Period.ZERO); + assertEquals(f.parse(input).query(DateTimeFormatter.parsedLeapSecond()), Boolean.FALSE); + } + @Test public void test_parse_endOfDay() { Instant expected = OffsetDateTime.of(1970, 2, 4, 0, 0, 0, 0, ZoneOffset.UTC).toInstant(); @@ -283,4 +338,12 @@ new DateTimeFormatterBuilder().appendInstant(10); } + //------------------------------------------------------------------------ + @Test + public void test_equality_withAndWithoutOffset() { + Instant instant1 = Instant.parse("2018-09-12T16:45:51+00:00"); + Instant instant2 = Instant.parse("2018-09-12T16:45:51Z"); + assertEquals(instant2, instant1); + } + }