diff --git a/src/java.base/share/classes/java/time/LocalDate.java b/src/java.base/share/classes/java/time/LocalDate.java index caf6ccd6641..13478530301 100644 --- a/src/java.base/share/classes/java/time/LocalDate.java +++ b/src/java.base/share/classes/java/time/LocalDate.java @@ -103,6 +103,8 @@ import java.util.Objects; import java.util.stream.LongStream; import java.util.stream.Stream; +import jdk.internal.util.DateTimeHelper; + /** * A date without a time-zone in the ISO-8601 calendar system, * such as {@code 2007-12-03}. @@ -2148,37 +2150,10 @@ public final class LocalDate @Override public String toString() { var buf = new StringBuilder(10); - formatTo(buf); + DateTimeHelper.formatTo(buf, this); return buf.toString(); } - /** - * Prints the toString result to the given buf, avoiding extra string allocations. - * Requires extra capacity of 10 to avoid StringBuilder reallocation. - */ - void formatTo(StringBuilder buf) { - int yearValue = year; - int monthValue = month; - int dayValue = day; - int absYear = Math.abs(yearValue); - if (absYear < 1000) { - if (yearValue < 0) { - buf.append('-'); - } - buf.repeat('0', absYear < 10 ? 3 : absYear < 100 ? 2 : 1); - buf.append(absYear); - } else { - if (yearValue > 9999) { - buf.append('+'); - } - buf.append(yearValue); - } - buf.append(monthValue < 10 ? "-0" : "-") - .append(monthValue) - .append(dayValue < 10 ? "-0" : "-") - .append(dayValue); - } - //----------------------------------------------------------------------- /** * Writes the object using a diff --git a/src/java.base/share/classes/java/time/LocalDateTime.java b/src/java.base/share/classes/java/time/LocalDateTime.java index f8c814957dc..37932fe7a65 100644 --- a/src/java.base/share/classes/java/time/LocalDateTime.java +++ b/src/java.base/share/classes/java/time/LocalDateTime.java @@ -96,6 +96,8 @@ import java.time.temporal.ValueRange; import java.time.zone.ZoneRules; import java.util.Objects; +import jdk.internal.util.DateTimeHelper; + /** * A date-time without a time-zone in the ISO-8601 calendar system, * such as {@code 2007-12-03T10:15:30}. @@ -1966,18 +1968,10 @@ public final class LocalDateTime @Override public String toString() { var buf = new StringBuilder(29); - formatTo(buf); + DateTimeHelper.formatTo(buf, this); return buf.toString(); } - /** - * Prints the toString result to the given buf, avoiding extra string allocations. - */ - void formatTo(StringBuilder buf) { - date.formatTo(buf); - buf.append('T'); - time.formatTo(buf); - } //----------------------------------------------------------------------- /** @@ -2018,5 +2012,4 @@ public final class LocalDateTime LocalTime time = LocalTime.readExternal(in); return LocalDateTime.of(date, time); } - } diff --git a/src/java.base/share/classes/java/time/LocalTime.java b/src/java.base/share/classes/java/time/LocalTime.java index 06f408350ca..de2669752ec 100644 --- a/src/java.base/share/classes/java/time/LocalTime.java +++ b/src/java.base/share/classes/java/time/LocalTime.java @@ -92,7 +92,7 @@ import java.time.temporal.UnsupportedTemporalTypeException; import java.time.temporal.ValueRange; import java.util.Objects; -import jdk.internal.util.DecimalDigits; +import jdk.internal.util.DateTimeHelper; /** * A time without a time-zone in the ISO-8601 calendar system, @@ -1632,42 +1632,10 @@ public final class LocalTime @Override public String toString() { var buf = new StringBuilder(18); - formatTo(buf); + DateTimeHelper.formatTo(buf, this); return buf.toString(); } - /** - * Prints the toString result to the given buf, avoiding extra string allocations. - * Requires extra capacity of 18 to avoid StringBuilder reallocation. - */ - void formatTo(StringBuilder buf) { - int hourValue = hour; - int minuteValue = minute; - int secondValue = second; - int nanoValue = nano; - buf.append(hourValue < 10 ? "0" : "").append(hourValue) - .append(minuteValue < 10 ? ":0" : ":").append(minuteValue); - if (secondValue > 0 || nanoValue > 0) { - buf.append(secondValue < 10 ? ":0" : ":").append(secondValue); - if (nanoValue > 0) { - buf.append('.'); - int zeros = 9 - DecimalDigits.stringSize(nanoValue); - if (zeros > 0) { - buf.repeat('0', zeros); - } - int digits; - if (nanoValue % 1_000_000 == 0) { - digits = nanoValue / 1_000_000; - } else if (nanoValue % 1000 == 0) { - digits = nanoValue / 1000; - } else { - digits = nanoValue; - } - buf.append(digits); - } - } - } - //----------------------------------------------------------------------- /** * Writes the object using a diff --git a/src/java.base/share/classes/java/time/OffsetDateTime.java b/src/java.base/share/classes/java/time/OffsetDateTime.java index 6f7005b9fa4..62ff8f23a15 100644 --- a/src/java.base/share/classes/java/time/OffsetDateTime.java +++ b/src/java.base/share/classes/java/time/OffsetDateTime.java @@ -93,6 +93,8 @@ import java.time.zone.ZoneRules; import java.util.Comparator; import java.util.Objects; +import jdk.internal.util.DateTimeHelper; + /** * A date-time with an offset from UTC/Greenwich in the ISO-8601 calendar system, * such as {@code 2007-12-03T10:15:30+01:00}. @@ -1925,7 +1927,7 @@ public final class OffsetDateTime public String toString() { var offsetStr = offset.toString(); var buf = new StringBuilder(29 + offsetStr.length()); - dateTime.formatTo(buf); + DateTimeHelper.formatTo(buf, dateTime); return buf.append(offsetStr).toString(); } diff --git a/src/java.base/share/classes/java/time/OffsetTime.java b/src/java.base/share/classes/java/time/OffsetTime.java index ad9781e2459..831043c47df 100644 --- a/src/java.base/share/classes/java/time/OffsetTime.java +++ b/src/java.base/share/classes/java/time/OffsetTime.java @@ -92,6 +92,8 @@ import java.time.temporal.ValueRange; import java.time.zone.ZoneRules; import java.util.Objects; +import jdk.internal.util.DateTimeHelper; + /** * A time with an offset from UTC/Greenwich in the ISO-8601 calendar system, * such as {@code 10:15:30+01:00}. @@ -1400,7 +1402,7 @@ public final class OffsetTime public String toString() { var offsetStr = offset.toString(); var buf = new StringBuilder(18 + offsetStr.length()); - time.formatTo(buf); + DateTimeHelper.formatTo(buf, time); return buf.append(offsetStr).toString(); } diff --git a/src/java.base/share/classes/java/time/ZonedDateTime.java b/src/java.base/share/classes/java/time/ZonedDateTime.java index 135d1a16ae7..962469b3225 100644 --- a/src/java.base/share/classes/java/time/ZonedDateTime.java +++ b/src/java.base/share/classes/java/time/ZonedDateTime.java @@ -91,6 +91,8 @@ import java.time.zone.ZoneRules; import java.util.List; import java.util.Objects; +import jdk.internal.util.DateTimeHelper; + /** * A date-time with a time-zone in the ISO-8601 calendar system, * such as {@code 2007-12-03T10:15:30+01:00 Europe/Paris}. @@ -2222,7 +2224,7 @@ public final class ZonedDateTime length += zoneStr.length() + 2; } var buf = new StringBuilder(length); - dateTime.formatTo(buf); + DateTimeHelper.formatTo(buf, dateTime); buf.append(offsetStr); if (zoneStr != null) { buf.append('[').append(zoneStr).append(']'); diff --git a/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java b/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java index 7c83de46c52..f5eeeec563c 100644 --- a/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java +++ b/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, 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 @@ -121,6 +121,7 @@ import java.util.concurrent.ConcurrentMap; import java.util.regex.Matcher; import java.util.regex.Pattern; +import jdk.internal.util.DateTimeHelper; import jdk.internal.util.DecimalDigits; import sun.text.spi.JavaTimeDateTimePatternProvider; @@ -161,7 +162,6 @@ import sun.util.locale.provider.TimeZoneNameUtility; * @since 1.8 */ public final class DateTimeFormatterBuilder { - /** * Query for a time-zone that is region-only. */ @@ -3809,58 +3809,73 @@ public final class DateTimeFormatterBuilder { } long inSec = inSecs; int inNano = NANO_OF_SECOND.checkValidIntValue(inNanos != null ? inNanos : 0); - // format mostly using LocalDateTime.toString + if (fractionalDigits == 0) { + inNano = 0; + } + boolean printNanoInLocalDateTime = fractionalDigits == -2 + || (inNano == 0 && (fractionalDigits == 0 || fractionalDigits == -1)); if (inSec >= -SECONDS_0000_TO_1970) { - // current era - long zeroSecs = inSec - SECONDS_PER_10000_YEARS + SECONDS_0000_TO_1970; - long hi = Math.floorDiv(zeroSecs, SECONDS_PER_10000_YEARS) + 1; - long lo = Math.floorMod(zeroSecs, SECONDS_PER_10000_YEARS); - LocalDateTime ldt = LocalDateTime.ofEpochSecond(lo - SECONDS_0000_TO_1970, 0, ZoneOffset.UTC); - if (hi > 0) { - buf.append('+').append(hi); - } - buf.append(ldt); - if (ldt.getSecond() == 0) { - buf.append(":00"); - } + currentEra(buf, inSec, printNanoInLocalDateTime ? inNano : 0); } else { - // before current era - long zeroSecs = inSec + SECONDS_0000_TO_1970; - long hi = zeroSecs / SECONDS_PER_10000_YEARS; - long lo = zeroSecs % SECONDS_PER_10000_YEARS; - LocalDateTime ldt = LocalDateTime.ofEpochSecond(lo - SECONDS_0000_TO_1970, 0, ZoneOffset.UTC); - int pos = buf.length(); - buf.append(ldt); - if (ldt.getSecond() == 0) { - buf.append(":00"); - } - if (hi < 0) { - if (ldt.getYear() == -10_000) { - buf.replace(pos, pos + 2, Long.toString(hi - 1)); - } else if (lo == 0) { - buf.insert(pos, hi); - } else { - buf.insert(pos + 1, Math.abs(hi)); - } - } + beforeCurrentEra(buf, inSec, printNanoInLocalDateTime ? inNano : 0); } // add fraction - if ((fractionalDigits < 0 && inNano > 0) || fractionalDigits > 0) { - buf.append('.'); - int div = 100_000_000; - for (int i = 0; ((fractionalDigits == -1 && inNano > 0) || - (fractionalDigits == -2 && (inNano > 0 || (i % 3) != 0)) || - i < fractionalDigits); i++) { - int digit = inNano / div; - buf.append((char) (digit + '0')); - inNano = inNano - (digit * div); - div = div / 10; - } + if (!printNanoInLocalDateTime) { + printNano(buf, inSec, inNano); } buf.append('Z'); return true; } + private void printNano(StringBuilder buf, long inSec, int inNano) { + buf.append('.'); + int div = 100_000_000; + int fractionalDigits = this.fractionalDigits; + for (int i = 0; ((fractionalDigits == -1 && inNano > 0) || + (fractionalDigits == -2 && (inNano > 0 || (i % 3) != 0)) || + i < fractionalDigits); i++) { + int digit = inNano / div; + buf.append((char) (digit + '0')); + inNano = inNano - (digit * div); + div = div / 10; + } + } + + private static void currentEra(StringBuilder buf, long inSec, int inNano) { + long zeroSecs = inSec - SECONDS_PER_10000_YEARS + SECONDS_0000_TO_1970; + long hi = Math.floorDiv(zeroSecs, SECONDS_PER_10000_YEARS) + 1; + long lo = Math.floorMod(zeroSecs, SECONDS_PER_10000_YEARS); + LocalDateTime ldt = LocalDateTime.ofEpochSecond(lo - SECONDS_0000_TO_1970, inNano, ZoneOffset.UTC); + if (hi > 0) { + buf.append('+').append(hi); + } + DateTimeHelper.formatTo(buf, ldt); + if (ldt.getSecond() == 0 && inNano == 0) { + buf.append(":00"); + } + } + + private static void beforeCurrentEra(StringBuilder buf, long inSec, int inNano) { + long zeroSecs = inSec + SECONDS_0000_TO_1970; + long hi = zeroSecs / SECONDS_PER_10000_YEARS; + long lo = zeroSecs % SECONDS_PER_10000_YEARS; + LocalDateTime ldt = LocalDateTime.ofEpochSecond(lo - SECONDS_0000_TO_1970, inNano, ZoneOffset.UTC); + int pos = buf.length(); + DateTimeHelper.formatTo(buf, ldt); + if (ldt.getSecond() == 0 && inNano == 0) { + buf.append(":00"); + } + if (hi < 0) { + if (ldt.getYear() == -10_000) { + buf.replace(pos, pos + 2, Long.toString(hi - 1)); + } else if (lo == 0) { + buf.insert(pos, hi); + } else { + buf.insert(pos + 1, Math.abs(hi)); + } + } + } + @Override public int parse(DateTimeParseContext context, CharSequence text, int position) { // new context to avoid overwriting fields like year/month/day diff --git a/src/java.base/share/classes/jdk/internal/util/DateTimeHelper.java b/src/java.base/share/classes/jdk/internal/util/DateTimeHelper.java new file mode 100644 index 00000000000..bbb0b6738d1 --- /dev/null +++ b/src/java.base/share/classes/jdk/internal/util/DateTimeHelper.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Alibaba Group Holding Limited. 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.util; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; + +/** + * Helper for java.time + */ +public final class DateTimeHelper { + private DateTimeHelper() { + } + /** + * Prints the toString result to the given buf, avoiding extra string allocations. + */ + public static void formatTo(StringBuilder buf, LocalDateTime dateTime) { + DateTimeHelper.formatTo(buf, dateTime.toLocalDate()); + buf.append('T'); + DateTimeHelper.formatTo(buf, dateTime.toLocalTime()); + } + + /** + * Prints the toString result to the given buf, avoiding extra string allocations. + * Requires extra capacity of 10 to avoid StringBuilder reallocation. + */ + public static void formatTo(StringBuilder buf, LocalDate date) { + int year = date.getYear(), + month = date.getMonthValue(), + day = date.getDayOfMonth(); + int absYear = Math.abs(year); + if (absYear < 1000) { + if (year < 0) { + buf.append('-'); + } + buf.repeat('0', absYear < 10 ? 3 : absYear < 100 ? 2 : 1); + buf.append(absYear); + } else { + if (year > 9999) { + buf.append('+'); + } + buf.append(year); + } + buf.append(month < 10 ? "-0" : "-").append(month) + .append(day < 10 ? "-0" : "-").append(day); + } + + /** + * Prints the toString result to the given buf, avoiding extra string allocations. + * Requires extra capacity of 18 to avoid StringBuilder reallocation. + */ + public static void formatTo(StringBuilder buf, LocalTime time) { + int hour = time.getHour(), + minute = time.getMinute(), + second = time.getSecond(), + nano = time.getNano(); + buf.append(hour < 10 ? "0" : "").append(hour) + .append(minute < 10 ? ":0" : ":").append(minute); + if ((second | nano) > 0) { + buf.append(second < 10 ? ":0" : ":").append(second); + if (nano > 0) { + buf.append('.'); + int zeros = 9 - DecimalDigits.stringSize(nano); + if (zeros > 0) { + buf.repeat('0', zeros); + } + int digits; + if (nano % 1_000_000 == 0) { + digits = nano / 1_000_000; + } else if (nano % 1000 == 0) { + digits = nano / 1000; + } else { + digits = nano; + } + buf.append(digits); + } + } + } +} diff --git a/test/jdk/java/time/tck/java/time/format/TCKInstantPrinterParser.java b/test/jdk/java/time/tck/java/time/format/TCKInstantPrinterParser.java index 4c8c55f9e0c..49b772bf82b 100644 --- a/test/jdk/java/time/tck/java/time/format/TCKInstantPrinterParser.java +++ b/test/jdk/java/time/tck/java/time/format/TCKInstantPrinterParser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2025, 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 @@ -311,6 +311,158 @@ public class TCKInstantPrinterParser { } } + @Test + public void test_print_instant() { + DateTimeFormatter formatter = new DateTimeFormatterBuilder().appendInstant().toFormatter(); + DateTimeFormatter formatter0 = new DateTimeFormatterBuilder().appendInstant(0).toFormatter(); + DateTimeFormatter formatter1 = new DateTimeFormatterBuilder().appendInstant(1).toFormatter(); + DateTimeFormatter formatter2 = new DateTimeFormatterBuilder().appendInstant(2).toFormatter(); + DateTimeFormatter formatter3 = new DateTimeFormatterBuilder().appendInstant(3).toFormatter(); + DateTimeFormatter formatter4 = new DateTimeFormatterBuilder().appendInstant(4).toFormatter(); + DateTimeFormatter formatter5 = new DateTimeFormatterBuilder().appendInstant(5).toFormatter(); + DateTimeFormatter formatter6 = new DateTimeFormatterBuilder().appendInstant(6).toFormatter(); + DateTimeFormatter formatter7 = new DateTimeFormatterBuilder().appendInstant(7).toFormatter(); + DateTimeFormatter formatter8 = new DateTimeFormatterBuilder().appendInstant(8).toFormatter(); + DateTimeFormatter formatter9 = new DateTimeFormatterBuilder().appendInstant(9).toFormatter(); + DateTimeFormatter formatterN1 = new DateTimeFormatterBuilder().appendInstant(-1).toFormatter(); + + { + Instant instant = Instant.ofEpochSecond(1111721337984L, 1); + assertEquals("+37199-01-18T02:46:24.000000001Z", formatter.format(instant)); + assertEquals("+37199-01-18T02:46:24Z", formatter0.format(instant)); + assertEquals("+37199-01-18T02:46:24.0Z", formatter1.format(instant)); + assertEquals("+37199-01-18T02:46:24.00Z", formatter2.format(instant)); + assertEquals("+37199-01-18T02:46:24.000Z", formatter3.format(instant)); + assertEquals("+37199-01-18T02:46:24.0000Z", formatter4.format(instant)); + assertEquals("+37199-01-18T02:46:24.00000Z", formatter5.format(instant)); + assertEquals("+37199-01-18T02:46:24.000000Z", formatter6.format(instant)); + assertEquals("+37199-01-18T02:46:24.0000000Z", formatter7.format(instant)); + assertEquals("+37199-01-18T02:46:24.00000000Z", formatter8.format(instant)); + assertEquals("+37199-01-18T02:46:24.000000001Z", formatter9.format(instant)); + assertEquals("+37199-01-18T02:46:24.000000001Z", formatterN1.format(instant)); + } + { + Instant instant = Instant.ofEpochSecond(1111721337984L, 10); + assertEquals("+37199-01-18T02:46:24.000000010Z", formatter.format(instant)); + assertEquals("+37199-01-18T02:46:24Z", formatter0.format(instant)); + assertEquals("+37199-01-18T02:46:24.0Z", formatter1.format(instant)); + assertEquals("+37199-01-18T02:46:24.00Z", formatter2.format(instant)); + assertEquals("+37199-01-18T02:46:24.000Z", formatter3.format(instant)); + assertEquals("+37199-01-18T02:46:24.0000Z", formatter4.format(instant)); + assertEquals("+37199-01-18T02:46:24.00000Z", formatter5.format(instant)); + assertEquals("+37199-01-18T02:46:24.000000Z", formatter6.format(instant)); + assertEquals("+37199-01-18T02:46:24.0000000Z", formatter7.format(instant)); + assertEquals("+37199-01-18T02:46:24.00000001Z", formatter8.format(instant)); + assertEquals("+37199-01-18T02:46:24.000000010Z", formatter9.format(instant)); + assertEquals("+37199-01-18T02:46:24.00000001Z", formatterN1.format(instant)); + } + { + Instant instant = Instant.ofEpochSecond(1111721337984L, 100); + assertEquals("+37199-01-18T02:46:24.000000100Z", formatter.format(instant)); + assertEquals("+37199-01-18T02:46:24Z", formatter0.format(instant)); + assertEquals("+37199-01-18T02:46:24.0Z", formatter1.format(instant)); + assertEquals("+37199-01-18T02:46:24.00Z", formatter2.format(instant)); + assertEquals("+37199-01-18T02:46:24.000Z", formatter3.format(instant)); + assertEquals("+37199-01-18T02:46:24.0000Z", formatter4.format(instant)); + assertEquals("+37199-01-18T02:46:24.00000Z", formatter5.format(instant)); + assertEquals("+37199-01-18T02:46:24.000000Z", formatter6.format(instant)); + assertEquals("+37199-01-18T02:46:24.0000001Z", formatter7.format(instant)); + assertEquals("+37199-01-18T02:46:24.00000010Z", formatter8.format(instant)); + assertEquals("+37199-01-18T02:46:24.000000100Z", formatter9.format(instant)); + assertEquals("+37199-01-18T02:46:24.0000001Z", formatterN1.format(instant)); + } + { + Instant instant = Instant.ofEpochSecond(1111721337984L, 1_000); + assertEquals("+37199-01-18T02:46:24.000001Z", formatter.format(instant)); + assertEquals("+37199-01-18T02:46:24Z", formatter0.format(instant)); + assertEquals("+37199-01-18T02:46:24.0Z", formatter1.format(instant)); + assertEquals("+37199-01-18T02:46:24.00Z", formatter2.format(instant)); + assertEquals("+37199-01-18T02:46:24.000Z", formatter3.format(instant)); + assertEquals("+37199-01-18T02:46:24.0000Z", formatter4.format(instant)); + assertEquals("+37199-01-18T02:46:24.00000Z", formatter5.format(instant)); + assertEquals("+37199-01-18T02:46:24.000001Z", formatter6.format(instant)); + assertEquals("+37199-01-18T02:46:24.0000010Z", formatter7.format(instant)); + assertEquals("+37199-01-18T02:46:24.00000100Z", formatter8.format(instant)); + assertEquals("+37199-01-18T02:46:24.000001000Z", formatter9.format(instant)); + assertEquals("+37199-01-18T02:46:24.000001Z", formatterN1.format(instant)); + } + { + Instant instant = Instant.ofEpochSecond(1721337984L, 10_000); + assertEquals("2024-07-18T21:26:24.000010Z", formatter.format(instant)); + assertEquals("2024-07-18T21:26:24Z", formatter0.format(instant)); + assertEquals("2024-07-18T21:26:24.0Z", formatter1.format(instant)); + assertEquals("2024-07-18T21:26:24.00Z", formatter2.format(instant)); + assertEquals("2024-07-18T21:26:24.000Z", formatter3.format(instant)); + assertEquals("2024-07-18T21:26:24.0000Z", formatter4.format(instant)); + assertEquals("2024-07-18T21:26:24.00001Z", formatter5.format(instant)); + assertEquals("2024-07-18T21:26:24.000010Z", formatter6.format(instant)); + assertEquals("2024-07-18T21:26:24.0000100Z", formatter7.format(instant)); + assertEquals("2024-07-18T21:26:24.00001000Z", formatter8.format(instant)); + assertEquals("2024-07-18T21:26:24.000010000Z", formatter9.format(instant)); + assertEquals("2024-07-18T21:26:24.00001Z", formatterN1.format(instant)); + } + { + Instant instant = Instant.ofEpochSecond(-1721337984L, 100_000); + assertEquals("1915-06-16T02:33:36.000100Z", formatter.format(instant)); + assertEquals("1915-06-16T02:33:36Z", formatter0.format(instant)); + assertEquals("1915-06-16T02:33:36.0Z", formatter1.format(instant)); + assertEquals("1915-06-16T02:33:36.00Z", formatter2.format(instant)); + assertEquals("1915-06-16T02:33:36.000Z", formatter3.format(instant)); + assertEquals("1915-06-16T02:33:36.0001Z", formatter4.format(instant)); + assertEquals("1915-06-16T02:33:36.00010Z", formatter5.format(instant)); + assertEquals("1915-06-16T02:33:36.000100Z", formatter6.format(instant)); + assertEquals("1915-06-16T02:33:36.0001000Z", formatter7.format(instant)); + assertEquals("1915-06-16T02:33:36.00010000Z", formatter8.format(instant)); + assertEquals("1915-06-16T02:33:36.000100000Z", formatter9.format(instant)); + assertEquals("1915-06-16T02:33:36.0001Z", formatterN1.format(instant)); + } + { + Instant instant = Instant.ofEpochSecond(-51721337984L, 1_000_000); + assertEquals("0331-01-07T09:40:16.001Z", formatter.format(instant)); + assertEquals("0331-01-07T09:40:16Z", formatter0.format(instant)); + assertEquals("0331-01-07T09:40:16.0Z", formatter1.format(instant)); + assertEquals("0331-01-07T09:40:16.00Z", formatter2.format(instant)); + assertEquals("0331-01-07T09:40:16.001Z", formatter3.format(instant)); + assertEquals("0331-01-07T09:40:16.0010Z", formatter4.format(instant)); + assertEquals("0331-01-07T09:40:16.00100Z", formatter5.format(instant)); + assertEquals("0331-01-07T09:40:16.001000Z", formatter6.format(instant)); + assertEquals("0331-01-07T09:40:16.0010000Z", formatter7.format(instant)); + assertEquals("0331-01-07T09:40:16.00100000Z", formatter8.format(instant)); + assertEquals("0331-01-07T09:40:16.001000000Z", formatter9.format(instant)); + assertEquals("0331-01-07T09:40:16.001Z", formatterN1.format(instant)); + } + { + Instant instant = Instant.ofEpochSecond(11337984L, 100_000_000); + assertEquals("1970-05-12T05:26:24.100Z", formatter.format(instant)); + assertEquals("1970-05-12T05:26:24Z", formatter0.format(instant)); + assertEquals("1970-05-12T05:26:24.1Z", formatter1.format(instant)); + assertEquals("1970-05-12T05:26:24.10Z", formatter2.format(instant)); + assertEquals("1970-05-12T05:26:24.100Z", formatter3.format(instant)); + assertEquals("1970-05-12T05:26:24.1000Z", formatter4.format(instant)); + assertEquals("1970-05-12T05:26:24.10000Z", formatter5.format(instant)); + assertEquals("1970-05-12T05:26:24.100000Z", formatter6.format(instant)); + assertEquals("1970-05-12T05:26:24.1000000Z", formatter7.format(instant)); + assertEquals("1970-05-12T05:26:24.10000000Z", formatter8.format(instant)); + assertEquals("1970-05-12T05:26:24.100000000Z", formatter9.format(instant)); + assertEquals("1970-05-12T05:26:24.1Z", formatterN1.format(instant)); + } + { + Instant instant = Instant.MAX; + assertEquals("+1000000000-12-31T23:59:59.999999999Z", formatter.format(instant)); + assertEquals("+1000000000-12-31T23:59:59Z", formatter0.format(instant)); + assertEquals("+1000000000-12-31T23:59:59.9Z", formatter1.format(instant)); + assertEquals("+1000000000-12-31T23:59:59.99Z", formatter2.format(instant)); + assertEquals("+1000000000-12-31T23:59:59.999Z", formatter3.format(instant)); + assertEquals("+1000000000-12-31T23:59:59.9999Z", formatter4.format(instant)); + assertEquals("+1000000000-12-31T23:59:59.99999Z", formatter5.format(instant)); + assertEquals("+1000000000-12-31T23:59:59.999999Z", formatter6.format(instant)); + assertEquals("+1000000000-12-31T23:59:59.9999999Z", formatter7.format(instant)); + assertEquals("+1000000000-12-31T23:59:59.99999999Z", formatter8.format(instant)); + assertEquals("+1000000000-12-31T23:59:59.999999999Z", formatter9.format(instant)); + assertEquals("+1000000000-12-31T23:59:59.999999999Z", formatterN1.format(instant)); + } + } + //----------------------------------------------------------------------- @Test(expectedExceptions=IllegalArgumentException.class) public void test_appendInstant_tooSmall() { diff --git a/test/micro/org/openjdk/bench/java/time/ToStringBench.java b/test/micro/org/openjdk/bench/java/time/ToStringBench.java index 3d62e21ba8f..13f713b86c8 100644 --- a/test/micro/org/openjdk/bench/java/time/ToStringBench.java +++ b/test/micro/org/openjdk/bench/java/time/ToStringBench.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Alibaba Group Holding Limited. All Rights Reserved. + * Copyright (c) 2025, Alibaba Group Holding Limited. 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 @@ -121,4 +121,11 @@ public class ToStringBench { bh.consume(localTime.toString()); } } -} \ No newline at end of file + + @Benchmark + public void instantToString(Blackhole bh) { + for (Instant instant : INSTANTS) { + bh.consume(instant.toString()); + } + } +}