Home | History | Annotate | Download | only in sql
      1 /*
      2  * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
      3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      4  *
      5  * This code is free software; you can redistribute it and/or modify it
      6  * under the terms of the GNU General Public License version 2 only, as
      7  * published by the Free Software Foundation.  Oracle designates this
      8  * particular file as subject to the "Classpath" exception as provided
      9  * by Oracle in the LICENSE file that accompanied this code.
     10  *
     11  * This code is distributed in the hope that it will be useful, but WITHOUT
     12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     14  * version 2 for more details (a copy is included in the LICENSE file that
     15  * accompanied this code).
     16  *
     17  * You should have received a copy of the GNU General Public License version
     18  * 2 along with this work; if not, write to the Free Software Foundation,
     19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
     20  *
     21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
     22  * or visit www.oracle.com if you need additional information or have any
     23  * questions.
     24  */
     25 
     26 package java.sql;
     27 
     28 import java.util.StringTokenizer;
     29 
     30 /**
     31  * <P>A thin wrapper around <code>java.util.Date</code> that allows
     32  * the JDBC API to identify this as an SQL <code>TIMESTAMP</code> value.
     33  * It adds the ability
     34  * to hold the SQL <code>TIMESTAMP</code> fractional seconds value, by allowing
     35  * the specification of fractional seconds to a precision of nanoseconds.
     36  * A Timestamp also provides formatting and
     37  * parsing operations to support the JDBC escape syntax for timestamp values.
     38  *
     39  * <p>The precision of a Timestamp object is calculated to be either:
     40  * <ul>
     41  * <li><code>19 </code>, which is the number of characters in yyyy-mm-dd hh:mm:ss
     42  * <li> <code> 20 + s </code>, which is the number
     43  * of characters in the yyyy-mm-dd hh:mm:ss.[fff...] and <code>s</code> represents  the scale of the given Timestamp,
     44  * its fractional seconds precision.
     45  *</ul>
     46  *
     47  * <P><B>Note:</B> This type is a composite of a <code>java.util.Date</code> and a
     48  * separate nanoseconds value. Only integral seconds are stored in the
     49  * <code>java.util.Date</code> component. The fractional seconds - the nanos - are
     50  * separate.  The <code>Timestamp.equals(Object)</code> method never returns
     51  * <code>true</code> when passed an object
     52  * that isn't an instance of <code>java.sql.Timestamp</code>,
     53  * because the nanos component of a date is unknown.
     54  * As a result, the <code>Timestamp.equals(Object)</code>
     55  * method is not symmetric with respect to the
     56  * <code>java.util.Date.equals(Object)</code>
     57  * method.  Also, the <code>hashCode</code> method uses the underlying
     58  * <code>java.util.Date</code>
     59  * implementation and therefore does not include nanos in its computation.
     60  * <P>
     61  * Due to the differences between the <code>Timestamp</code> class
     62  * and the <code>java.util.Date</code>
     63  * class mentioned above, it is recommended that code not view
     64  * <code>Timestamp</code> values generically as an instance of
     65  * <code>java.util.Date</code>.  The
     66  * inheritance relationship between <code>Timestamp</code>
     67  * and <code>java.util.Date</code> really
     68  * denotes implementation inheritance, and not type inheritance.
     69  */
     70 public class Timestamp extends java.util.Date {
     71 
     72     /**
     73      * Constructs a <code>Timestamp</code> object initialized
     74      * with the given values.
     75      *
     76      * @param year the year minus 1900
     77      * @param month 0 to 11
     78      * @param date 1 to 31
     79      * @param hour 0 to 23
     80      * @param minute 0 to 59
     81      * @param second 0 to 59
     82      * @param nano 0 to 999,999,999
     83      * @deprecated instead use the constructor <code>Timestamp(long millis)</code>
     84      * @exception IllegalArgumentException if the nano argument is out of bounds
     85      */
     86     @Deprecated
     87     public Timestamp(int year, int month, int date,
     88                      int hour, int minute, int second, int nano) {
     89         super(year, month, date, hour, minute, second);
     90         if (nano > 999999999 || nano < 0) {
     91             throw new IllegalArgumentException("nanos > 999999999 or < 0");
     92         }
     93         nanos = nano;
     94     }
     95 
     96     /**
     97      * Constructs a <code>Timestamp</code> object
     98      * using a milliseconds time value. The
     99      * integral seconds are stored in the underlying date value; the
    100      * fractional seconds are stored in the <code>nanos</code> field of
    101      * the <code>Timestamp</code> object.
    102      *
    103      * @param time milliseconds since January 1, 1970, 00:00:00 GMT.
    104      *        A negative number is the number of milliseconds before
    105      *         January 1, 1970, 00:00:00 GMT.
    106      * @see java.util.Calendar
    107      */
    108     public Timestamp(long time) {
    109         super((time/1000)*1000);
    110         nanos = (int)((time%1000) * 1000000);
    111         if (nanos < 0) {
    112             nanos = 1000000000 + nanos;
    113             super.setTime(((time/1000)-1)*1000);
    114         }
    115     }
    116 
    117     /**
    118      * Sets this <code>Timestamp</code> object to represent a point in time that is
    119      * <tt>time</tt> milliseconds after January 1, 1970 00:00:00 GMT.
    120      *
    121      * @param time   the number of milliseconds.
    122      * @see #getTime
    123      * @see #Timestamp(long time)
    124      * @see java.util.Calendar
    125      */
    126     public void setTime(long time) {
    127         super.setTime((time/1000)*1000);
    128         nanos = (int)((time%1000) * 1000000);
    129         if (nanos < 0) {
    130             nanos = 1000000000 + nanos;
    131             super.setTime(((time/1000)-1)*1000);
    132         }
    133     }
    134 
    135     /**
    136      * Returns the number of milliseconds since January 1, 1970, 00:00:00 GMT
    137      * represented by this <code>Timestamp</code> object.
    138      *
    139      * @return  the number of milliseconds since January 1, 1970, 00:00:00 GMT
    140      *          represented by this date.
    141      * @see #setTime
    142      */
    143     public long getTime() {
    144         long time = super.getTime();
    145         return (time + (nanos / 1000000));
    146     }
    147 
    148 
    149     /**
    150      * @serial
    151      */
    152     private int nanos;
    153 
    154     /**
    155      * Converts a <code>String</code> object in JDBC timestamp escape format to a
    156      * <code>Timestamp</code> value.
    157      *
    158      * @param s timestamp in format <code>yyyy-[m]m-[d]d hh:mm:ss[.f...]</code>.  The
    159      * fractional seconds may be omitted. The leading zero for <code>mm</code>
    160      * and <code>dd</code> may also be omitted.
    161      *
    162      * @return corresponding <code>Timestamp</code> value
    163      * @exception java.lang.IllegalArgumentException if the given argument
    164      * does not have the format <code>yyyy-[m]m-[d]d hh:mm:ss[.f...]</code>
    165      */
    166     public static Timestamp valueOf(String s) {
    167         final int YEAR_LENGTH = 4;
    168         final int MONTH_LENGTH = 2;
    169         final int DAY_LENGTH = 2;
    170         final int MAX_MONTH = 12;
    171         final int MAX_DAY = 31;
    172         String date_s;
    173         String time_s;
    174         String nanos_s;
    175         int year = 0;
    176         int month = 0;
    177         int day = 0;
    178         int hour;
    179         int minute;
    180         int second;
    181         int a_nanos = 0;
    182         int firstDash;
    183         int secondDash;
    184         int dividingSpace;
    185         int firstColon = 0;
    186         int secondColon = 0;
    187         int period = 0;
    188         String formatError = "Timestamp format must be yyyy-mm-dd hh:mm:ss[.fffffffff]";
    189         String zeros = "000000000";
    190         String delimiterDate = "-";
    191         String delimiterTime = ":";
    192 
    193         if (s == null) throw new java.lang.IllegalArgumentException("null string");
    194 
    195         // Split the string into date and time components
    196         s = s.trim();
    197         dividingSpace = s.indexOf(' ');
    198         if (dividingSpace > 0) {
    199             date_s = s.substring(0,dividingSpace);
    200             time_s = s.substring(dividingSpace+1);
    201         } else {
    202             throw new java.lang.IllegalArgumentException(formatError);
    203         }
    204 
    205         // Parse the date
    206         firstDash = date_s.indexOf('-');
    207         secondDash = date_s.indexOf('-', firstDash+1);
    208 
    209         // Parse the time
    210         if (time_s == null)
    211             throw new java.lang.IllegalArgumentException(formatError);
    212         firstColon = time_s.indexOf(':');
    213         secondColon = time_s.indexOf(':', firstColon+1);
    214         period = time_s.indexOf('.', secondColon+1);
    215 
    216         // Convert the date
    217         boolean parsedDate = false;
    218         if ((firstDash > 0) && (secondDash > 0) && (secondDash < date_s.length() - 1)) {
    219             String yyyy = date_s.substring(0, firstDash);
    220             String mm = date_s.substring(firstDash + 1, secondDash);
    221             String dd = date_s.substring(secondDash + 1);
    222             if (yyyy.length() == YEAR_LENGTH &&
    223                     (mm.length() >= 1 && mm.length() <= MONTH_LENGTH) &&
    224                     (dd.length() >= 1 && dd.length() <= DAY_LENGTH)) {
    225                  year = Integer.parseInt(yyyy);
    226                  month = Integer.parseInt(mm);
    227                  day = Integer.parseInt(dd);
    228 
    229                 if ((month >= 1 && month <= MAX_MONTH) && (day >= 1 && day <= MAX_DAY)) {
    230                     parsedDate = true;
    231                 }
    232             }
    233         }
    234         if (! parsedDate) {
    235             throw new java.lang.IllegalArgumentException(formatError);
    236         }
    237 
    238         // Convert the time; default missing nanos
    239         if ((firstColon > 0) & (secondColon > 0) &
    240             (secondColon < time_s.length()-1)) {
    241             hour = Integer.parseInt(time_s.substring(0, firstColon));
    242             minute =
    243                 Integer.parseInt(time_s.substring(firstColon+1, secondColon));
    244             if ((period > 0) & (period < time_s.length()-1)) {
    245                 second =
    246                     Integer.parseInt(time_s.substring(secondColon+1, period));
    247                 nanos_s = time_s.substring(period+1);
    248                 if (nanos_s.length() > 9)
    249                     throw new java.lang.IllegalArgumentException(formatError);
    250                 if (!Character.isDigit(nanos_s.charAt(0)))
    251                     throw new java.lang.IllegalArgumentException(formatError);
    252                 nanos_s = nanos_s + zeros.substring(0,9-nanos_s.length());
    253                 a_nanos = Integer.parseInt(nanos_s);
    254             } else if (period > 0) {
    255                 throw new java.lang.IllegalArgumentException(formatError);
    256             } else {
    257                 second = Integer.parseInt(time_s.substring(secondColon+1));
    258             }
    259         } else {
    260             throw new java.lang.IllegalArgumentException(formatError);
    261         }
    262 
    263         return new Timestamp(year - 1900, month - 1, day, hour, minute, second, a_nanos);
    264     }
    265 
    266     /**
    267      * Formats a timestamp in JDBC timestamp escape format.
    268      *         <code>yyyy-mm-dd hh:mm:ss.fffffffff</code>,
    269      * where <code>ffffffffff</code> indicates nanoseconds.
    270      * <P>
    271      * @return a <code>String</code> object in
    272      *           <code>yyyy-mm-dd hh:mm:ss.fffffffff</code> format
    273      */
    274     public String toString () {
    275 
    276         int year = super.getYear() + 1900;
    277         int month = super.getMonth() + 1;
    278         int day = super.getDate();
    279         int hour = super.getHours();
    280         int minute = super.getMinutes();
    281         int second = super.getSeconds();
    282         String yearString;
    283         String monthString;
    284         String dayString;
    285         String hourString;
    286         String minuteString;
    287         String secondString;
    288         String nanosString;
    289         String zeros = "000000000";
    290         String yearZeros = "0000";
    291         StringBuffer timestampBuf;
    292 
    293         if (year < 1000) {
    294             // Add leading zeros
    295             yearString = "" + year;
    296             yearString = yearZeros.substring(0, (4-yearString.length())) +
    297                 yearString;
    298         } else {
    299             yearString = "" + year;
    300         }
    301         if (month < 10) {
    302             monthString = "0" + month;
    303         } else {
    304             monthString = Integer.toString(month);
    305         }
    306         if (day < 10) {
    307             dayString = "0" + day;
    308         } else {
    309             dayString = Integer.toString(day);
    310         }
    311         if (hour < 10) {
    312             hourString = "0" + hour;
    313         } else {
    314             hourString = Integer.toString(hour);
    315         }
    316         if (minute < 10) {
    317             minuteString = "0" + minute;
    318         } else {
    319             minuteString = Integer.toString(minute);
    320         }
    321         if (second < 10) {
    322             secondString = "0" + second;
    323         } else {
    324             secondString = Integer.toString(second);
    325         }
    326         if (nanos == 0) {
    327             nanosString = "0";
    328         } else {
    329             nanosString = Integer.toString(nanos);
    330 
    331             // Add leading zeros
    332             nanosString = zeros.substring(0, (9-nanosString.length())) +
    333                 nanosString;
    334 
    335             // Truncate trailing zeros
    336             char[] nanosChar = new char[nanosString.length()];
    337             nanosString.getChars(0, nanosString.length(), nanosChar, 0);
    338             int truncIndex = 8;
    339             while (nanosChar[truncIndex] == '0') {
    340                 truncIndex--;
    341             }
    342 
    343             nanosString = new String(nanosChar, 0, truncIndex + 1);
    344         }
    345 
    346         // do a string buffer here instead.
    347         timestampBuf = new StringBuffer(20+nanosString.length());
    348         timestampBuf.append(yearString);
    349         timestampBuf.append("-");
    350         timestampBuf.append(monthString);
    351         timestampBuf.append("-");
    352         timestampBuf.append(dayString);
    353         timestampBuf.append(" ");
    354         timestampBuf.append(hourString);
    355         timestampBuf.append(":");
    356         timestampBuf.append(minuteString);
    357         timestampBuf.append(":");
    358         timestampBuf.append(secondString);
    359         timestampBuf.append(".");
    360         timestampBuf.append(nanosString);
    361 
    362         return (timestampBuf.toString());
    363     }
    364 
    365     /**
    366      * Gets this <code>Timestamp</code> object's <code>nanos</code> value.
    367      *
    368      * @return this <code>Timestamp</code> object's fractional seconds component
    369      * @see #setNanos
    370      */
    371     public int getNanos() {
    372         return nanos;
    373     }
    374 
    375     /**
    376      * Sets this <code>Timestamp</code> object's <code>nanos</code> field
    377      * to the given value.
    378      *
    379      * @param n the new fractional seconds component
    380      * @exception java.lang.IllegalArgumentException if the given argument
    381      *            is greater than 999999999 or less than 0
    382      * @see #getNanos
    383      */
    384     public void setNanos(int n) {
    385         if (n > 999999999 || n < 0) {
    386             throw new IllegalArgumentException("nanos > 999999999 or < 0");
    387         }
    388         nanos = n;
    389     }
    390 
    391     /**
    392      * Tests to see if this <code>Timestamp</code> object is
    393      * equal to the given <code>Timestamp</code> object.
    394      *
    395      * @param ts the <code>Timestamp</code> value to compare with
    396      * @return <code>true</code> if the given <code>Timestamp</code>
    397      *         object is equal to this <code>Timestamp</code> object;
    398      *         <code>false</code> otherwise
    399      */
    400     public boolean equals(Timestamp ts) {
    401         if (super.equals(ts)) {
    402             if  (nanos == ts.nanos) {
    403                 return true;
    404             } else {
    405                 return false;
    406             }
    407         } else {
    408             return false;
    409         }
    410     }
    411 
    412     /**
    413      * Tests to see if this <code>Timestamp</code> object is
    414      * equal to the given object.
    415      *
    416      * This version of the method <code>equals</code> has been added
    417      * to fix the incorrect
    418      * signature of <code>Timestamp.equals(Timestamp)</code> and to preserve backward
    419      * compatibility with existing class files.
    420      *
    421      * Note: This method is not symmetric with respect to the
    422      * <code>equals(Object)</code> method in the base class.
    423      *
    424      * @param ts the <code>Object</code> value to compare with
    425      * @return <code>true</code> if the given <code>Object</code> is an instance
    426      *         of a <code>Timestamp</code> that
    427      *         is equal to this <code>Timestamp</code> object;
    428      *         <code>false</code> otherwise
    429      */
    430     public boolean equals(java.lang.Object ts) {
    431       if (ts instanceof Timestamp) {
    432         return this.equals((Timestamp)ts);
    433       } else {
    434         return false;
    435       }
    436     }
    437 
    438     /**
    439      * Indicates whether this <code>Timestamp</code> object is
    440      * earlier than the given <code>Timestamp</code> object.
    441      *
    442      * @param ts the <code>Timestamp</code> value to compare with
    443      * @return <code>true</code> if this <code>Timestamp</code> object is earlier;
    444      *        <code>false</code> otherwise
    445      */
    446     public boolean before(Timestamp ts) {
    447         return compareTo(ts) < 0;
    448     }
    449 
    450     /**
    451      * Indicates whether this <code>Timestamp</code> object is
    452      * later than the given <code>Timestamp</code> object.
    453      *
    454      * @param ts the <code>Timestamp</code> value to compare with
    455      * @return <code>true</code> if this <code>Timestamp</code> object is later;
    456      *        <code>false</code> otherwise
    457      */
    458     public boolean after(Timestamp ts) {
    459         return compareTo(ts) > 0;
    460     }
    461 
    462     /**
    463      * Compares this <code>Timestamp</code> object to the given
    464      * <code>Timestamp</code> object.
    465      *
    466      * @param   ts   the <code>Timestamp</code> object to be compared to
    467      *                this <code>Timestamp</code> object
    468      * @return  the value <code>0</code> if the two <code>Timestamp</code>
    469      *          objects are equal; a value less than <code>0</code> if this
    470      *          <code>Timestamp</code> object is before the given argument;
    471      *          and a value greater than <code>0</code> if this
    472      *          <code>Timestamp</code> object is after the given argument.
    473      * @since   1.4
    474      */
    475     public int compareTo(Timestamp ts) {
    476         long thisTime = this.getTime();
    477         long anotherTime = ts.getTime();
    478         int i = (thisTime<anotherTime ? -1 :(thisTime==anotherTime?0 :1));
    479         if (i == 0) {
    480             if (nanos > ts.nanos) {
    481                     return 1;
    482             } else if (nanos < ts.nanos) {
    483                 return -1;
    484             }
    485         }
    486         return i;
    487 
    488     }
    489 
    490     /**
    491      * Compares this <code>Timestamp</code> object to the given
    492      * <code>Date</code> object.
    493      *
    494      * @param o the <code>Date</code> to be compared to
    495      *          this <code>Timestamp</code> object
    496      * @return  the value <code>0</code> if this <code>Timestamp</code> object
    497      *          and the given object are equal; a value less than <code>0</code>
    498      *          if this  <code>Timestamp</code> object is before the given argument;
    499      *          and a value greater than <code>0</code> if this
    500      *          <code>Timestamp</code> object is after the given argument.
    501      *
    502      * @since   1.5
    503      */
    504     public int compareTo(java.util.Date o) {
    505        if(o instanceof Timestamp) {
    506             // When Timestamp instance compare it with a Timestamp
    507             // Hence it is basically calling this.compareTo((Timestamp))o);
    508             // Note typecasting is safe because o is instance of Timestamp
    509            return compareTo((Timestamp)o);
    510       } else {
    511             // When Date doing a o.compareTo(this)
    512             // will give wrong results.
    513           Timestamp ts = new Timestamp(o.getTime());
    514           return this.compareTo(ts);
    515       }
    516     }
    517 
    518     /**
    519      * {@inheritDoc}
    520      *
    521      * The {@code hashCode} method uses the underlying {@code java.util.Date}
    522      * implementation and therefore does not include nanos in its computation.
    523      *
    524      */
    525     @Override
    526     public int hashCode() {
    527         return super.hashCode();
    528     }
    529 
    530     static final long serialVersionUID = 2745179027874758501L;
    531 
    532 }
    533