-
Notifications
You must be signed in to change notification settings - Fork 6.2k
8315999: Improve Date toString performance #15658
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
27174f4
93ed81d
f4190a8
9bb6231
c6ab251
a849b2e
f05fb42
72ea933
c26eb70
342bbd2
b26cb85
70566a7
2a617db
26d7c7c
5d0fa13
8b3f063
6288ee9
9040ea0
e4c5b67
8c76799
8471814
fba3979
d3ad490
b7a3528
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -80,6 +80,8 @@ | |
| import java.io.InvalidObjectException; | ||
| import java.io.ObjectInputStream; | ||
| import java.io.Serializable; | ||
| import java.nio.charset.CharacterCodingException; | ||
| import java.nio.charset.StandardCharsets; | ||
| import java.time.chrono.ChronoLocalDate; | ||
| import java.time.chrono.IsoEra; | ||
| import java.time.chrono.IsoChronology; | ||
|
|
@@ -103,6 +105,11 @@ | |
| import java.util.stream.LongStream; | ||
| import java.util.stream.Stream; | ||
|
|
||
| import jdk.internal.access.JavaLangAccess; | ||
| import jdk.internal.access.SharedSecrets; | ||
| import jdk.internal.util.ByteArrayLittleEndian; | ||
| import jdk.internal.util.DecimalDigits; | ||
|
|
||
| /** | ||
| * A date without a time-zone in the ISO-8601 calendar system, | ||
| * such as {@code 2007-12-03}. | ||
|
|
@@ -140,6 +147,8 @@ | |
| public final class LocalDate | ||
| implements Temporal, TemporalAdjuster, ChronoLocalDate, Serializable { | ||
|
|
||
| private static final JavaLangAccess jla = SharedSecrets.getJavaLangAccess(); | ||
|
|
||
| /** | ||
| * The minimum supported {@code LocalDate}, '-999999999-01-01'. | ||
| * This could be used by an application as a "far past" date. | ||
|
|
@@ -2147,28 +2156,60 @@ public int hashCode() { | |
| */ | ||
| @Override | ||
| public String toString() { | ||
| int yearValue = year; | ||
| int monthValue = month; | ||
| int dayValue = day; | ||
| int absYear = Math.abs(yearValue); | ||
| StringBuilder buf = new StringBuilder(10); | ||
| if (absYear < 1000) { | ||
| if (yearValue < 0) { | ||
| buf.append(yearValue - 10000).deleteCharAt(1); | ||
| } else { | ||
| buf.append(yearValue + 10000).deleteCharAt(0); | ||
| byte[] buf = new byte[yearSize(year) + 6]; | ||
| getChars(buf, 0); | ||
|
|
||
| try { | ||
| return jla.newStringNoRepl(buf, StandardCharsets.ISO_8859_1); | ||
| } catch (CharacterCodingException cce) { | ||
| throw new AssertionError(cce); | ||
| } | ||
| } | ||
|
|
||
| static int yearSize(int year) { | ||
| if (Math.abs(year) < 1000) { | ||
| return year < 0 ? 5 : 4; | ||
| } | ||
| return DecimalDigits.stringSize(year) + (year > 9999 ? 1 : 0); | ||
| } | ||
|
|
||
| int getChars(byte[] buf, int off) { | ||
| int year = this.year; | ||
| int yearSize = yearSize(year); | ||
| int yearAbs = Math.abs(year); | ||
|
|
||
| int yearEnd = off + yearSize; | ||
| if (yearAbs < 1000) { | ||
| if (year < 0) { | ||
| buf[off++] = '-'; | ||
| } | ||
| int y01 = yearAbs / 100; | ||
| int y23 = yearAbs - y01 * 100; | ||
|
|
||
| ByteArrayLittleEndian.setInt( | ||
| buf, | ||
| off, | ||
| (DecimalDigits.digitPair(y23) << 16) | DecimalDigits.digitPair(y01)); | ||
| } else { | ||
| if (yearValue > 9999) { | ||
| buf.append('+'); | ||
| if (year > 9999) { | ||
| buf[off] = '+'; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this place doesn't need off++
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Correct, though it's a bit opaque that |
||
| } | ||
| buf.append(yearValue); | ||
| DecimalDigits.getCharsLatin1(year, yearEnd, buf); | ||
| } | ||
| return buf.append(monthValue < 10 ? "-0" : "-") | ||
| .append(monthValue) | ||
| .append(dayValue < 10 ? "-0" : "-") | ||
| .append(dayValue) | ||
| .toString(); | ||
|
|
||
| off = yearEnd; | ||
| buf[off] = '-'; | ||
| ByteArrayLittleEndian.setShort( | ||
| buf, | ||
| off + 1, | ||
| DecimalDigits.digitPair(month)); // mm | ||
| buf[off + 3] = '-'; | ||
| ByteArrayLittleEndian.setShort( | ||
| buf, | ||
| off + 4, | ||
| DecimalDigits.digitPair(day)); // dd | ||
|
|
||
| return off + 6; | ||
| } | ||
|
|
||
| //----------------------------------------------------------------------- | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have you considered potentially more generalizable optimizations to
DateTimeFormatter.ISO_INSTANT.format(this)here?Hand-rolling a fixed-length buffer, skipping the
StringBuilder.. understandably this can have a performance edge, but perhaps aDateTimeFormatterlikeISO_INSTANTcan be optimized to get closer to whatever speed-up this gets you - with broader implications.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The performance of optimizing DateTimeFormatter cannot be as fast as using ixed-length buffer directly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Of course, the optimization of DateTimeFormatter is more general, and we can spend time doing it later. The format of toString is fixed, we can not use DateTimeFormatter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I submitted an optimization for the commonly used format of DateTimeFormatter::format
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you have a link to that PR? Is there an RFE filed for it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Optimization of DateTimeFormatter::format should be another PR, I created a branche but the work is unfinished.