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
Timestamp(int year, int month, int date, int hour, int minute, int second, int nano)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      */
Timestamp(long time)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      */
setTime(long time)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      */
getTime()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      */
valueOf(String s)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      */
toString()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      */
getNanos()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      */
setNanos(int n)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      */
equals(Timestamp ts)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      */
equals(java.lang.Object ts)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      */
before(Timestamp ts)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      */
after(Timestamp ts)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      */
compareTo(Timestamp ts)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      */
compareTo(java.util.Date o)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
hashCode()526     public int hashCode() {
527         return super.hashCode();
528     }
529 
530     static final long serialVersionUID = 2745179027874758501L;
531 
532 }
533