8058230: Improve java.sql toString formatting
authorredestad
Fri, 12 Sep 2014 17:34:13 +0200
changeset 26597 c840e6631327
parent 26596 85ea379d419a
child 26598 c1d885140938
child 26613 5533758d18c9
8058230: Improve java.sql toString formatting Reviewed-by: lancea
jdk/src/java.sql/share/classes/java/sql/Date.java
jdk/src/java.sql/share/classes/java/sql/Time.java
jdk/src/java.sql/share/classes/java/sql/Timestamp.java
--- a/jdk/src/java.sql/share/classes/java/sql/Date.java	Wed Aug 13 18:40:16 2014 +0200
+++ b/jdk/src/java.sql/share/classes/java/sql/Date.java	Fri Sep 12 17:34:13 2014 +0200
@@ -27,6 +27,8 @@
 
 import java.time.Instant;
 import java.time.LocalDate;
+import sun.misc.SharedSecrets;
+import sun.misc.JavaLangAccess;
 
 /**
  * <P>A thin wrapper around a millisecond value that allows
@@ -42,6 +44,8 @@
  */
 public class Date extends java.util.Date {
 
+    private static final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
+
     /**
      * Constructs a <code>Date</code> object initialized with the given
      * year, month, and day.
@@ -155,17 +159,30 @@
         int month = super.getMonth() + 1;
         int day = super.getDate();
 
-        char buf[] = "2000-00-00".toCharArray();
-        buf[0] = Character.forDigit(year/1000,10);
-        buf[1] = Character.forDigit((year/100)%10,10);
-        buf[2] = Character.forDigit((year/10)%10,10);
-        buf[3] = Character.forDigit(year%10,10);
-        buf[5] = Character.forDigit(month/10,10);
-        buf[6] = Character.forDigit(month%10,10);
-        buf[8] = Character.forDigit(day/10,10);
-        buf[9] = Character.forDigit(day%10,10);
+        char buf[] = new char[10];
+        formatDecimalInt(year, buf, 0, 4);
+        buf[4] = '-';
+        Date.formatDecimalInt(month, buf, 5, 2);
+        buf[7] = '-';
+        Date.formatDecimalInt(day, buf, 8, 2);
+
+        return jla.newStringUnsafe(buf);
+    }
 
-        return new String(buf);
+    /*
+     * Formats an unsigned integer into a char array in decimal output format.
+     * Numbers will be zero-padded or truncated if the string representation
+     * of the integer is smaller than or exceeds len, respectively.
+     *
+     * Should consider moving this to Integer and expose it through
+     * JavaLangAccess similar to Integer::formatUnsignedInt
+     */
+    protected static void formatDecimalInt(int val, char[] buf, int offset, int len) {
+        int charPos = offset + len;
+        do {
+            buf[--charPos] = (char)('0' + (val % 10));
+            val /= 10;
+        } while (charPos > offset);
     }
 
     // Override all the time operations inherited from java.util.Date;
--- a/jdk/src/java.sql/share/classes/java/sql/Time.java	Wed Aug 13 18:40:16 2014 +0200
+++ b/jdk/src/java.sql/share/classes/java/sql/Time.java	Fri Sep 12 17:34:13 2014 +0200
@@ -27,6 +27,8 @@
 
 import java.time.Instant;
 import java.time.LocalTime;
+import sun.misc.SharedSecrets;
+import sun.misc.JavaLangAccess;
 
 /**
  * <P>A thin wrapper around the <code>java.util.Date</code> class that allows the JDBC
@@ -39,6 +41,8 @@
  */
 public class Time extends java.util.Date {
 
+    private static final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
+
     /**
      * Constructs a <code>Time</code> object initialized with the
      * given values for the hour, minute, and second.
@@ -120,26 +124,15 @@
         int hour = super.getHours();
         int minute = super.getMinutes();
         int second = super.getSeconds();
-        String hourString;
-        String minuteString;
-        String secondString;
 
-        if (hour < 10) {
-            hourString = "0" + hour;
-        } else {
-            hourString = Integer.toString(hour);
-        }
-        if (minute < 10) {
-            minuteString = "0" + minute;
-        } else {
-            minuteString = Integer.toString(minute);
-        }
-        if (second < 10) {
-            secondString = "0" + second;
-        } else {
-            secondString = Integer.toString(second);
-        }
-        return (hourString + ":" + minuteString + ":" + secondString);
+        char[] buf = new char[8];
+        Date.formatDecimalInt(hour, buf, 0, 2);
+        buf[2] = ':';
+        Date.formatDecimalInt(minute, buf, 3, 2);
+        buf[5] = ':';
+        Date.formatDecimalInt(second, buf, 6, 2);
+
+        return jla.newStringUnsafe(buf);
     }
 
     // Override all the date operations inherited from java.util.Date;
--- a/jdk/src/java.sql/share/classes/java/sql/Timestamp.java	Wed Aug 13 18:40:16 2014 +0200
+++ b/jdk/src/java.sql/share/classes/java/sql/Timestamp.java	Fri Sep 12 17:34:13 2014 +0200
@@ -27,7 +27,8 @@
 
 import java.time.Instant;
 import java.time.LocalDateTime;
-import java.util.StringTokenizer;
+import sun.misc.SharedSecrets;
+import sun.misc.JavaLangAccess;
 
 /**
  * <P>A thin wrapper around <code>java.util.Date</code> that allows
@@ -71,6 +72,8 @@
  */
 public class Timestamp extends java.util.Date {
 
+    private static final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
+
     /**
      * Constructs a <code>Timestamp</code> object initialized
      * with the given values.
@@ -262,95 +265,41 @@
      *           <code>yyyy-mm-dd hh:mm:ss.fffffffff</code> format
      */
     @SuppressWarnings("deprecation")
-    public String toString () {
-
+    public String toString() {
         int year = super.getYear() + 1900;
         int month = super.getMonth() + 1;
         int day = super.getDate();
         int hour = super.getHours();
         int minute = super.getMinutes();
         int second = super.getSeconds();
-        String yearString;
-        String monthString;
-        String dayString;
-        String hourString;
-        String minuteString;
-        String secondString;
-        String nanosString;
-        String zeros = "000000000";
-        String yearZeros = "0000";
-        StringBuffer timestampBuf;
 
-        if (year < 1000) {
-            // Add leading zeros
-            yearString = "" + year;
-            yearString = yearZeros.substring(0, (4-yearString.length())) +
-                yearString;
-        } else {
-            yearString = "" + year;
-        }
-        if (month < 10) {
-            monthString = "0" + month;
-        } else {
-            monthString = Integer.toString(month);
-        }
-        if (day < 10) {
-            dayString = "0" + day;
+        int trailingZeros = 0;
+        int tmpNanos = nanos;
+        if (tmpNanos == 0) {
+            trailingZeros = 8;
         } else {
-            dayString = Integer.toString(day);
-        }
-        if (hour < 10) {
-            hourString = "0" + hour;
-        } else {
-            hourString = Integer.toString(hour);
-        }
-        if (minute < 10) {
-            minuteString = "0" + minute;
-        } else {
-            minuteString = Integer.toString(minute);
-        }
-        if (second < 10) {
-            secondString = "0" + second;
-        } else {
-            secondString = Integer.toString(second);
-        }
-        if (nanos == 0) {
-            nanosString = "0";
-        } else {
-            nanosString = Integer.toString(nanos);
-
-            // Add leading zeros
-            nanosString = zeros.substring(0, (9-nanosString.length())) +
-                nanosString;
-
-            // Truncate trailing zeros
-            char[] nanosChar = new char[nanosString.length()];
-            nanosString.getChars(0, nanosString.length(), nanosChar, 0);
-            int truncIndex = 8;
-            while (nanosChar[truncIndex] == '0') {
-                truncIndex--;
+            while (tmpNanos % 10 == 0) {
+                tmpNanos /= 10;
+                trailingZeros++;
             }
-
-            nanosString = new String(nanosChar, 0, truncIndex + 1);
         }
 
-        // do a string buffer here instead.
-        timestampBuf = new StringBuffer(20+nanosString.length());
-        timestampBuf.append(yearString);
-        timestampBuf.append("-");
-        timestampBuf.append(monthString);
-        timestampBuf.append("-");
-        timestampBuf.append(dayString);
-        timestampBuf.append(" ");
-        timestampBuf.append(hourString);
-        timestampBuf.append(":");
-        timestampBuf.append(minuteString);
-        timestampBuf.append(":");
-        timestampBuf.append(secondString);
-        timestampBuf.append(".");
-        timestampBuf.append(nanosString);
+        char[] buf = new char[29 - trailingZeros];
+        Date.formatDecimalInt(year, buf, 0, 4);
+        buf[4] = '-';
+        Date.formatDecimalInt(month, buf, 5, 2);
+        buf[7] = '-';
+        Date.formatDecimalInt(day, buf, 8, 2);
+        buf[10] = ' ';
+        Date.formatDecimalInt(hour, buf, 11, 2);
+        buf[13] = ':';
+        Date.formatDecimalInt(minute, buf, 14, 2);
+        buf[16] = ':';
+        Date.formatDecimalInt(second, buf, 17, 2);
+        buf[19] = '.';
+        Date.formatDecimalInt(tmpNanos, buf, 20, 9 - trailingZeros);
 
-        return (timestampBuf.toString());
+        return jla.newStringUnsafe(buf);
     }
 
     /**