Skip to content

Commit 7442039

Browse files
committed
8337279: Share StringBuilder to format instant
Reviewed-by: naoto, liach
1 parent 22182f7 commit 7442039

File tree

10 files changed

+342
-123
lines changed

10 files changed

+342
-123
lines changed

src/java.base/share/classes/java/time/LocalDate.java

+3-28
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@
103103
import java.util.stream.LongStream;
104104
import java.util.stream.Stream;
105105

106+
import jdk.internal.util.DateTimeHelper;
107+
106108
/**
107109
* A date without a time-zone in the ISO-8601 calendar system,
108110
* such as {@code 2007-12-03}.
@@ -2148,37 +2150,10 @@ public int hashCode() {
21482150
@Override
21492151
public String toString() {
21502152
var buf = new StringBuilder(10);
2151-
formatTo(buf);
2153+
DateTimeHelper.formatTo(buf, this);
21522154
return buf.toString();
21532155
}
21542156

2155-
/**
2156-
* Prints the toString result to the given buf, avoiding extra string allocations.
2157-
* Requires extra capacity of 10 to avoid StringBuilder reallocation.
2158-
*/
2159-
void formatTo(StringBuilder buf) {
2160-
int yearValue = year;
2161-
int monthValue = month;
2162-
int dayValue = day;
2163-
int absYear = Math.abs(yearValue);
2164-
if (absYear < 1000) {
2165-
if (yearValue < 0) {
2166-
buf.append('-');
2167-
}
2168-
buf.repeat('0', absYear < 10 ? 3 : absYear < 100 ? 2 : 1);
2169-
buf.append(absYear);
2170-
} else {
2171-
if (yearValue > 9999) {
2172-
buf.append('+');
2173-
}
2174-
buf.append(yearValue);
2175-
}
2176-
buf.append(monthValue < 10 ? "-0" : "-")
2177-
.append(monthValue)
2178-
.append(dayValue < 10 ? "-0" : "-")
2179-
.append(dayValue);
2180-
}
2181-
21822157
//-----------------------------------------------------------------------
21832158
/**
21842159
* Writes the object using a

src/java.base/share/classes/java/time/LocalDateTime.java

+3-10
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@
9696
import java.time.zone.ZoneRules;
9797
import java.util.Objects;
9898

99+
import jdk.internal.util.DateTimeHelper;
100+
99101
/**
100102
* A date-time without a time-zone in the ISO-8601 calendar system,
101103
* such as {@code 2007-12-03T10:15:30}.
@@ -1966,18 +1968,10 @@ public int hashCode() {
19661968
@Override
19671969
public String toString() {
19681970
var buf = new StringBuilder(29);
1969-
formatTo(buf);
1971+
DateTimeHelper.formatTo(buf, this);
19701972
return buf.toString();
19711973
}
19721974

1973-
/**
1974-
* Prints the toString result to the given buf, avoiding extra string allocations.
1975-
*/
1976-
void formatTo(StringBuilder buf) {
1977-
date.formatTo(buf);
1978-
buf.append('T');
1979-
time.formatTo(buf);
1980-
}
19811975

19821976
//-----------------------------------------------------------------------
19831977
/**
@@ -2018,5 +2012,4 @@ static LocalDateTime readExternal(DataInput in) throws IOException {
20182012
LocalTime time = LocalTime.readExternal(in);
20192013
return LocalDateTime.of(date, time);
20202014
}
2021-
20222015
}

src/java.base/share/classes/java/time/LocalTime.java

+2-34
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@
9292
import java.time.temporal.ValueRange;
9393
import java.util.Objects;
9494

95-
import jdk.internal.util.DecimalDigits;
95+
import jdk.internal.util.DateTimeHelper;
9696

9797
/**
9898
* A time without a time-zone in the ISO-8601 calendar system,
@@ -1632,42 +1632,10 @@ public int hashCode() {
16321632
@Override
16331633
public String toString() {
16341634
var buf = new StringBuilder(18);
1635-
formatTo(buf);
1635+
DateTimeHelper.formatTo(buf, this);
16361636
return buf.toString();
16371637
}
16381638

1639-
/**
1640-
* Prints the toString result to the given buf, avoiding extra string allocations.
1641-
* Requires extra capacity of 18 to avoid StringBuilder reallocation.
1642-
*/
1643-
void formatTo(StringBuilder buf) {
1644-
int hourValue = hour;
1645-
int minuteValue = minute;
1646-
int secondValue = second;
1647-
int nanoValue = nano;
1648-
buf.append(hourValue < 10 ? "0" : "").append(hourValue)
1649-
.append(minuteValue < 10 ? ":0" : ":").append(minuteValue);
1650-
if (secondValue > 0 || nanoValue > 0) {
1651-
buf.append(secondValue < 10 ? ":0" : ":").append(secondValue);
1652-
if (nanoValue > 0) {
1653-
buf.append('.');
1654-
int zeros = 9 - DecimalDigits.stringSize(nanoValue);
1655-
if (zeros > 0) {
1656-
buf.repeat('0', zeros);
1657-
}
1658-
int digits;
1659-
if (nanoValue % 1_000_000 == 0) {
1660-
digits = nanoValue / 1_000_000;
1661-
} else if (nanoValue % 1000 == 0) {
1662-
digits = nanoValue / 1000;
1663-
} else {
1664-
digits = nanoValue;
1665-
}
1666-
buf.append(digits);
1667-
}
1668-
}
1669-
}
1670-
16711639
//-----------------------------------------------------------------------
16721640
/**
16731641
* Writes the object using a

src/java.base/share/classes/java/time/OffsetDateTime.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@
9393
import java.util.Comparator;
9494
import java.util.Objects;
9595

96+
import jdk.internal.util.DateTimeHelper;
97+
9698
/**
9799
* A date-time with an offset from UTC/Greenwich in the ISO-8601 calendar system,
98100
* such as {@code 2007-12-03T10:15:30+01:00}.
@@ -1925,7 +1927,7 @@ public int hashCode() {
19251927
public String toString() {
19261928
var offsetStr = offset.toString();
19271929
var buf = new StringBuilder(29 + offsetStr.length());
1928-
dateTime.formatTo(buf);
1930+
DateTimeHelper.formatTo(buf, dateTime);
19291931
return buf.append(offsetStr).toString();
19301932
}
19311933

src/java.base/share/classes/java/time/OffsetTime.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@
9292
import java.time.zone.ZoneRules;
9393
import java.util.Objects;
9494

95+
import jdk.internal.util.DateTimeHelper;
96+
9597
/**
9698
* A time with an offset from UTC/Greenwich in the ISO-8601 calendar system,
9799
* such as {@code 10:15:30+01:00}.
@@ -1400,7 +1402,7 @@ public int hashCode() {
14001402
public String toString() {
14011403
var offsetStr = offset.toString();
14021404
var buf = new StringBuilder(18 + offsetStr.length());
1403-
time.formatTo(buf);
1405+
DateTimeHelper.formatTo(buf, time);
14041406
return buf.append(offsetStr).toString();
14051407
}
14061408

src/java.base/share/classes/java/time/ZonedDateTime.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@
9191
import java.util.List;
9292
import java.util.Objects;
9393

94+
import jdk.internal.util.DateTimeHelper;
95+
9496
/**
9597
* A date-time with a time-zone in the ISO-8601 calendar system,
9698
* such as {@code 2007-12-03T10:15:30+01:00 Europe/Paris}.
@@ -2222,7 +2224,7 @@ public String toString() {
22222224
length += zoneStr.length() + 2;
22232225
}
22242226
var buf = new StringBuilder(length);
2225-
dateTime.formatTo(buf);
2227+
DateTimeHelper.formatTo(buf, dateTime);
22262228
buf.append(offsetStr);
22272229
if (zoneStr != null) {
22282230
buf.append('[').append(zoneStr).append(']');

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

+60-45
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -121,6 +121,7 @@
121121
import java.util.regex.Matcher;
122122
import java.util.regex.Pattern;
123123

124+
import jdk.internal.util.DateTimeHelper;
124125
import jdk.internal.util.DecimalDigits;
125126

126127
import sun.text.spi.JavaTimeDateTimePatternProvider;
@@ -161,7 +162,6 @@
161162
* @since 1.8
162163
*/
163164
public final class DateTimeFormatterBuilder {
164-
165165
/**
166166
* Query for a time-zone that is region-only.
167167
*/
@@ -3809,58 +3809,73 @@ public boolean format(DateTimePrintContext context, StringBuilder buf) {
38093809
}
38103810
long inSec = inSecs;
38113811
int inNano = NANO_OF_SECOND.checkValidIntValue(inNanos != null ? inNanos : 0);
3812-
// format mostly using LocalDateTime.toString
3812+
if (fractionalDigits == 0) {
3813+
inNano = 0;
3814+
}
3815+
boolean printNanoInLocalDateTime = fractionalDigits == -2
3816+
|| (inNano == 0 && (fractionalDigits == 0 || fractionalDigits == -1));
38133817
if (inSec >= -SECONDS_0000_TO_1970) {
3814-
// current era
3815-
long zeroSecs = inSec - SECONDS_PER_10000_YEARS + SECONDS_0000_TO_1970;
3816-
long hi = Math.floorDiv(zeroSecs, SECONDS_PER_10000_YEARS) + 1;
3817-
long lo = Math.floorMod(zeroSecs, SECONDS_PER_10000_YEARS);
3818-
LocalDateTime ldt = LocalDateTime.ofEpochSecond(lo - SECONDS_0000_TO_1970, 0, ZoneOffset.UTC);
3819-
if (hi > 0) {
3820-
buf.append('+').append(hi);
3821-
}
3822-
buf.append(ldt);
3823-
if (ldt.getSecond() == 0) {
3824-
buf.append(":00");
3825-
}
3818+
currentEra(buf, inSec, printNanoInLocalDateTime ? inNano : 0);
38263819
} else {
3827-
// before current era
3828-
long zeroSecs = inSec + SECONDS_0000_TO_1970;
3829-
long hi = zeroSecs / SECONDS_PER_10000_YEARS;
3830-
long lo = zeroSecs % SECONDS_PER_10000_YEARS;
3831-
LocalDateTime ldt = LocalDateTime.ofEpochSecond(lo - SECONDS_0000_TO_1970, 0, ZoneOffset.UTC);
3832-
int pos = buf.length();
3833-
buf.append(ldt);
3834-
if (ldt.getSecond() == 0) {
3835-
buf.append(":00");
3836-
}
3837-
if (hi < 0) {
3838-
if (ldt.getYear() == -10_000) {
3839-
buf.replace(pos, pos + 2, Long.toString(hi - 1));
3840-
} else if (lo == 0) {
3841-
buf.insert(pos, hi);
3842-
} else {
3843-
buf.insert(pos + 1, Math.abs(hi));
3844-
}
3845-
}
3820+
beforeCurrentEra(buf, inSec, printNanoInLocalDateTime ? inNano : 0);
38463821
}
38473822
// add fraction
3848-
if ((fractionalDigits < 0 && inNano > 0) || fractionalDigits > 0) {
3849-
buf.append('.');
3850-
int div = 100_000_000;
3851-
for (int i = 0; ((fractionalDigits == -1 && inNano > 0) ||
3852-
(fractionalDigits == -2 && (inNano > 0 || (i % 3) != 0)) ||
3853-
i < fractionalDigits); i++) {
3854-
int digit = inNano / div;
3855-
buf.append((char) (digit + '0'));
3856-
inNano = inNano - (digit * div);
3857-
div = div / 10;
3858-
}
3823+
if (!printNanoInLocalDateTime) {
3824+
printNano(buf, inSec, inNano);
38593825
}
38603826
buf.append('Z');
38613827
return true;
38623828
}
38633829

3830+
private void printNano(StringBuilder buf, long inSec, int inNano) {
3831+
buf.append('.');
3832+
int div = 100_000_000;
3833+
int fractionalDigits = this.fractionalDigits;
3834+
for (int i = 0; ((fractionalDigits == -1 && inNano > 0) ||
3835+
(fractionalDigits == -2 && (inNano > 0 || (i % 3) != 0)) ||
3836+
i < fractionalDigits); i++) {
3837+
int digit = inNano / div;
3838+
buf.append((char) (digit + '0'));
3839+
inNano = inNano - (digit * div);
3840+
div = div / 10;
3841+
}
3842+
}
3843+
3844+
private static void currentEra(StringBuilder buf, long inSec, int inNano) {
3845+
long zeroSecs = inSec - SECONDS_PER_10000_YEARS + SECONDS_0000_TO_1970;
3846+
long hi = Math.floorDiv(zeroSecs, SECONDS_PER_10000_YEARS) + 1;
3847+
long lo = Math.floorMod(zeroSecs, SECONDS_PER_10000_YEARS);
3848+
LocalDateTime ldt = LocalDateTime.ofEpochSecond(lo - SECONDS_0000_TO_1970, inNano, ZoneOffset.UTC);
3849+
if (hi > 0) {
3850+
buf.append('+').append(hi);
3851+
}
3852+
DateTimeHelper.formatTo(buf, ldt);
3853+
if (ldt.getSecond() == 0 && inNano == 0) {
3854+
buf.append(":00");
3855+
}
3856+
}
3857+
3858+
private static void beforeCurrentEra(StringBuilder buf, long inSec, int inNano) {
3859+
long zeroSecs = inSec + SECONDS_0000_TO_1970;
3860+
long hi = zeroSecs / SECONDS_PER_10000_YEARS;
3861+
long lo = zeroSecs % SECONDS_PER_10000_YEARS;
3862+
LocalDateTime ldt = LocalDateTime.ofEpochSecond(lo - SECONDS_0000_TO_1970, inNano, ZoneOffset.UTC);
3863+
int pos = buf.length();
3864+
DateTimeHelper.formatTo(buf, ldt);
3865+
if (ldt.getSecond() == 0 && inNano == 0) {
3866+
buf.append(":00");
3867+
}
3868+
if (hi < 0) {
3869+
if (ldt.getYear() == -10_000) {
3870+
buf.replace(pos, pos + 2, Long.toString(hi - 1));
3871+
} else if (lo == 0) {
3872+
buf.insert(pos, hi);
3873+
} else {
3874+
buf.insert(pos + 1, Math.abs(hi));
3875+
}
3876+
}
3877+
}
3878+
38643879
@Override
38653880
public int parse(DateTimeParseContext context, CharSequence text, int position) {
38663881
// new context to avoid overwriting fields like year/month/day

0 commit comments

Comments
 (0)