1 /*
   2  * Copyright (c) 1996, 2014, 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.time.Instant;
  29 import java.time.LocalDateTime;
  30 import sun.misc.SharedSecrets;
  31 import sun.misc.JavaLangAccess;
  32 
  33 /**
  34  * <P>A thin wrapper around {@code java.util.Date} that allows
  35  * the JDBC API to identify this as an SQL {@code TIMESTAMP} value.
  36  * It adds the ability
  37  * to hold the SQL {@code TIMESTAMP} fractional seconds value, by allowing
  38  * the specification of fractional seconds to a precision of nanoseconds.
  39  * A Timestamp also provides formatting and
  40  * parsing operations to support the JDBC escape syntax for timestamp values.
  41  *
  42  * <p>The precision of a Timestamp object is calculated to be either:
  43  * <ul>
  44  * <li>{@code 19 }, which is the number of characters in yyyy-mm-dd hh:mm:ss
  45  * <li> {@code  20 + s }, which is the number
  46  * of characters in the yyyy-mm-dd hh:mm:ss.[fff...] and {@code s} represents  the scale of the given Timestamp,
  47  * its fractional seconds precision.
  48  *</ul>
  49  *
  50  * <P><B>Note:</B> This type is a composite of a {@code java.util.Date} and a
  51  * separate nanoseconds value. Only integral seconds are stored in the
  52  * {@code java.util.Date} component. The fractional seconds - the nanos - are
  53  * separate.  The {@code Timestamp.equals(Object)} method never returns
  54  * {@code true} when passed an object
  55  * that isn't an instance of {@code java.sql.Timestamp},
  56  * because the nanos component of a date is unknown.
  57  * As a result, the {@code Timestamp.equals(Object)}
  58  * method is not symmetric with respect to the
  59  * {@code java.util.Date.equals(Object)}
  60  * method.  Also, the {@code hashCode} method uses the underlying
  61  * {@code java.util.Date}
  62  * implementation and therefore does not include nanos in its computation.
  63  * <P>
  64  * Due to the differences between the {@code Timestamp} class
  65  * and the {@code java.util.Date}
  66  * class mentioned above, it is recommended that code not view
  67  * {@code Timestamp} values generically as an instance of
  68  * {@code java.util.Date}.  The
  69  * inheritance relationship between {@code Timestamp}
  70  * and {@code java.util.Date} really
  71  * denotes implementation inheritance, and not type inheritance.
  72  */
  73 public class Timestamp extends java.util.Date {
  74 
  75     private static final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
  76 
  77     /**
  78      * Constructs a {@code Timestamp} object initialized
  79      * with the given values.
  80      *
  81      * @param year the year minus 1900
  82      * @param month 0 to 11
  83      * @param date 1 to 31
  84      * @param hour 0 to 23
  85      * @param minute 0 to 59
  86      * @param second 0 to 59
  87      * @param nano 0 to 999,999,999
  88      * @deprecated instead use the constructor {@code Timestamp(long millis)}
  89      * @exception IllegalArgumentException if the nano argument is out of bounds
  90      */
  91     @Deprecated
  92     public Timestamp(int year, int month, int date,
  93                      int hour, int minute, int second, int nano) {
  94         super(year, month, date, hour, minute, second);
  95         if (nano > 999999999 || nano < 0) {
  96             throw new IllegalArgumentException("nanos > 999999999 or < 0");
  97         }
  98         nanos = nano;
  99     }
 100 
 101     /**
 102      * Constructs a {@code Timestamp} object
 103      * using a milliseconds time value. The
 104      * integral seconds are stored in the underlying date value; the
 105      * fractional seconds are stored in the {@code nanos} field of
 106      * the {@code Timestamp} object.
 107      *
 108      * @param time milliseconds since January 1, 1970, 00:00:00 GMT.
 109      *        A negative number is the number of milliseconds before
 110      *         January 1, 1970, 00:00:00 GMT.
 111      * @see java.util.Calendar
 112      */
 113     public Timestamp(long time) {
 114         super((time/1000)*1000);
 115         nanos = (int)((time%1000) * 1000000);
 116         if (nanos < 0) {
 117             nanos = 1000000000 + nanos;
 118             super.setTime(((time/1000)-1)*1000);
 119         }
 120     }
 121 
 122     /**
 123      * Sets this {@code Timestamp} object to represent a point in time that is
 124      * {@code time} milliseconds after January 1, 1970 00:00:00 GMT.
 125      *
 126      * @param time   the number of milliseconds.
 127      * @see #getTime
 128      * @see #Timestamp(long time)
 129      * @see java.util.Calendar
 130      */
 131     public void setTime(long time) {
 132         super.setTime((time/1000)*1000);
 133         nanos = (int)((time%1000) * 1000000);
 134         if (nanos < 0) {
 135             nanos = 1000000000 + nanos;
 136             super.setTime(((time/1000)-1)*1000);
 137         }
 138     }
 139 
 140     /**
 141      * Returns the number of milliseconds since January 1, 1970, 00:00:00 GMT
 142      * represented by this {@code Timestamp} object.
 143      *
 144      * @return  the number of milliseconds since January 1, 1970, 00:00:00 GMT
 145      *          represented by this date.
 146      * @see #setTime
 147      */
 148     public long getTime() {
 149         long time = super.getTime();
 150         return (time + (nanos / 1000000));
 151     }
 152 
 153 
 154     /**
 155      * @serial
 156      */
 157     private int nanos;
 158 
 159     /**
 160      * Converts a {@code String} object in JDBC timestamp escape format to a
 161      * {@code Timestamp} value.
 162      *
 163      * @param s timestamp in format {@code yyyy-[m]m-[d]d hh:mm:ss[.f...]}.  The
 164      * fractional seconds may be omitted. The leading zero for {@code mm}
 165      * and {@code dd} may also be omitted.
 166      *
 167      * @return corresponding {@code Timestamp} value
 168      * @exception java.lang.IllegalArgumentException if the given argument
 169      * does not have the format {@code yyyy-[m]m-[d]d hh:mm:ss[.f...]}
 170      */
 171     public static Timestamp valueOf(String s) {
 172         final int YEAR_LENGTH = 4;
 173         final int MONTH_LENGTH = 2;
 174         final int DAY_LENGTH = 2;
 175         final int MAX_MONTH = 12;
 176         final int MAX_DAY = 31;
 177         int year = 0;
 178         int month = 0;
 179         int day = 0;
 180         int hour;
 181         int minute;
 182         int second;
 183         int a_nanos = 0;
 184         int firstDash;
 185         int secondDash;
 186         int dividingSpace;
 187         int firstColon;
 188         int secondColon;
 189         int period;
 190         String formatError = "Timestamp format must be yyyy-mm-dd hh:mm:ss[.fffffffff]";
 191 
 192         if (s == null) throw new java.lang.IllegalArgumentException("null string");
 193 
 194         // Split the string into date and time components
 195         s = s.trim();
 196         dividingSpace = s.indexOf(' ');
 197         if (dividingSpace < 0) {
 198             throw new java.lang.IllegalArgumentException(formatError);
 199         }
 200 
 201         // Parse the date
 202         firstDash = s.indexOf('-');
 203         secondDash = s.indexOf('-', firstDash+1);
 204 
 205         // Parse the time
 206         firstColon = s.indexOf(':', dividingSpace + 1);
 207         secondColon = s.indexOf(':', firstColon + 1);
 208         period = s.indexOf('.', secondColon + 1);
 209 
 210         // Convert the date
 211         boolean parsedDate = false;
 212         if (firstDash > 0 && secondDash > 0 && secondDash < dividingSpace - 1) {
 213             if (firstDash == YEAR_LENGTH &&
 214                     (secondDash - firstDash > 1 && secondDash - firstDash <= MONTH_LENGTH + 1) &&
 215                     (dividingSpace - secondDash > 1 && dividingSpace - secondDash <= DAY_LENGTH + 1)) {
 216                  year = Integer.parseInt(s, 0, firstDash, 10);
 217                  month = Integer.parseInt(s, firstDash + 1, secondDash, 10);
 218                  day = Integer.parseInt(s, secondDash + 1, dividingSpace, 10);
 219 
 220                 if ((month >= 1 && month <= MAX_MONTH) && (day >= 1 && day <= MAX_DAY)) {
 221                     parsedDate = true;
 222                 }
 223             }
 224         }
 225         if (! parsedDate) {
 226             throw new java.lang.IllegalArgumentException(formatError);
 227         }
 228 
 229         // Convert the time; default missing nanos
 230         int len = s.length();
 231         if (firstColon > 0 && secondColon > 0 && secondColon < len - 1) {
 232             hour = Integer.parseInt(s, dividingSpace + 1, firstColon, 10);
 233             minute = Integer.parseInt(s, firstColon + 1, secondColon, 10);
 234             if (period > 0 && period < len - 1) {
 235                 second = Integer.parseInt(s, secondColon + 1, period, 10);
 236                 int nanoPrecision = len - (period + 1);
 237                 if (nanoPrecision > 9)
 238                     throw new java.lang.IllegalArgumentException(formatError);
 239                 if (!Character.isDigit(s.charAt(period + 1)))
 240                     throw new java.lang.IllegalArgumentException(formatError);
 241                 int tmpNanos = Integer.parseInt(s, period + 1, len, 10);
 242                 while (nanoPrecision < 9) {
 243                     tmpNanos *= 10;
 244                     nanoPrecision++;
 245                 }
 246                 a_nanos = tmpNanos;
 247             } else if (period > 0) {
 248                 throw new java.lang.IllegalArgumentException(formatError);
 249             } else {
 250                 second = Integer.parseInt(s, secondColon + 1, len, 10);
 251             }
 252         } else {
 253             throw new java.lang.IllegalArgumentException(formatError);
 254         }
 255 
 256         return new Timestamp(year - 1900, month - 1, day, hour, minute, second, a_nanos);
 257     }
 258 
 259     /**
 260      * Formats a timestamp in JDBC timestamp escape format.
 261      *         {@code yyyy-mm-dd hh:mm:ss.fffffffff},
 262      * where {@code ffffffffff} indicates nanoseconds.
 263      *
 264      * @return a {@code String} object in
 265      *           {@code yyyy-mm-dd hh:mm:ss.fffffffff} format
 266      */
 267     @SuppressWarnings("deprecation")
 268     public String toString() {
 269         int year = super.getYear() + 1900;
 270         int month = super.getMonth() + 1;
 271         int day = super.getDate();
 272         int hour = super.getHours();
 273         int minute = super.getMinutes();
 274         int second = super.getSeconds();
 275 
 276         int trailingZeros = 0;
 277         int tmpNanos = nanos;
 278         if (tmpNanos == 0) {
 279             trailingZeros = 8;
 280         } else {
 281             while (tmpNanos % 10 == 0) {
 282                 tmpNanos /= 10;
 283                 trailingZeros++;
 284             }
 285         }
 286 
 287         // 8058429: To comply with current JCK tests, we need to deal with year
 288         // being any number between 0 and 292278995
 289         int count = 10000;
 290         int yearSize = 4;
 291         do {
 292             if (year < count) {
 293                 break;
 294             }
 295             yearSize++;
 296             count *= 10;
 297         } while (count < 1000000000);
 298 
 299         char[] buf = new char[25 + yearSize - trailingZeros];
 300         Date.formatDecimalInt(year, buf, 0, yearSize);
 301         buf[yearSize] = '-';
 302         Date.formatDecimalInt(month, buf, yearSize + 1, 2);
 303         buf[yearSize + 3] = '-';
 304         Date.formatDecimalInt(day, buf, yearSize + 4, 2);
 305         buf[yearSize + 6] = ' ';
 306         Date.formatDecimalInt(hour, buf, yearSize + 7, 2);
 307         buf[yearSize + 9] = ':';
 308         Date.formatDecimalInt(minute, buf, yearSize + 10, 2);
 309         buf[yearSize + 12] = ':';
 310         Date.formatDecimalInt(second, buf, yearSize + 13, 2);
 311         buf[yearSize + 15] = '.';
 312         Date.formatDecimalInt(tmpNanos, buf, yearSize + 16, 9 - trailingZeros);
 313 
 314         return jla.newStringUnsafe(buf);
 315     }
 316 
 317     /**
 318      * Gets this {@code Timestamp} object's {@code nanos} value.
 319      *
 320      * @return this {@code Timestamp} object's fractional seconds component
 321      * @see #setNanos
 322      */
 323     public int getNanos() {
 324         return nanos;
 325     }
 326 
 327     /**
 328      * Sets this {@code Timestamp} object's {@code nanos} field
 329      * to the given value.
 330      *
 331      * @param n the new fractional seconds component
 332      * @exception java.lang.IllegalArgumentException if the given argument
 333      *            is greater than 999999999 or less than 0
 334      * @see #getNanos
 335      */
 336     public void setNanos(int n) {
 337         if (n > 999999999 || n < 0) {
 338             throw new IllegalArgumentException("nanos > 999999999 or < 0");
 339         }
 340         nanos = n;
 341     }
 342 
 343     /**
 344      * Tests to see if this {@code Timestamp} object is
 345      * equal to the given {@code Timestamp} object.
 346      *
 347      * @param ts the {@code Timestamp} value to compare with
 348      * @return {@code true} if the given {@code Timestamp}
 349      *         object is equal to this {@code Timestamp} object;
 350      *         {@code false} otherwise
 351      */
 352     public boolean equals(Timestamp ts) {
 353         if (super.equals(ts)) {
 354             if  (nanos == ts.nanos) {
 355                 return true;
 356             } else {
 357                 return false;
 358             }
 359         } else {
 360             return false;
 361         }
 362     }
 363 
 364     /**
 365      * Tests to see if this {@code Timestamp} object is
 366      * equal to the given object.
 367      *
 368      * This version of the method {@code equals} has been added
 369      * to fix the incorrect
 370      * signature of {@code Timestamp.equals(Timestamp)} and to preserve backward
 371      * compatibility with existing class files.
 372      *
 373      * Note: This method is not symmetric with respect to the
 374      * {@code equals(Object)} method in the base class.
 375      *
 376      * @param ts the {@code Object} value to compare with
 377      * @return {@code true} if the given {@code Object} is an instance
 378      *         of a {@code Timestamp} that
 379      *         is equal to this {@code Timestamp} object;
 380      *         {@code false} otherwise
 381      */
 382     public boolean equals(java.lang.Object ts) {
 383       if (ts instanceof Timestamp) {
 384         return this.equals((Timestamp)ts);
 385       } else {
 386         return false;
 387       }
 388     }
 389 
 390     /**
 391      * Indicates whether this {@code Timestamp} object is
 392      * earlier than the given {@code Timestamp} object.
 393      *
 394      * @param ts the {@code Timestamp} value to compare with
 395      * @return {@code true} if this {@code Timestamp} object is earlier;
 396      *        {@code false} otherwise
 397      */
 398     public boolean before(Timestamp ts) {
 399         return compareTo(ts) < 0;
 400     }
 401 
 402     /**
 403      * Indicates whether this {@code Timestamp} object is
 404      * later than the given {@code Timestamp} object.
 405      *
 406      * @param ts the {@code Timestamp} value to compare with
 407      * @return {@code true} if this {@code Timestamp} object is later;
 408      *        {@code false} otherwise
 409      */
 410     public boolean after(Timestamp ts) {
 411         return compareTo(ts) > 0;
 412     }
 413 
 414     /**
 415      * Compares this {@code Timestamp} object to the given
 416      * {@code Timestamp} object.
 417      *
 418      * @param   ts   the {@code Timestamp} object to be compared to
 419      *                this {@code Timestamp} object
 420      * @return  the value {@code 0} if the two {@code Timestamp}
 421      *          objects are equal; a value less than {@code 0} if this
 422      *          {@code Timestamp} object is before the given argument;
 423      *          and a value greater than {@code 0} if this
 424      *          {@code Timestamp} object is after the given argument.
 425      * @since   1.4
 426      */
 427     public int compareTo(Timestamp ts) {
 428         long thisTime = this.getTime();
 429         long anotherTime = ts.getTime();
 430         int i = (thisTime<anotherTime ? -1 :(thisTime==anotherTime?0 :1));
 431         if (i == 0) {
 432             if (nanos > ts.nanos) {
 433                     return 1;
 434             } else if (nanos < ts.nanos) {
 435                 return -1;
 436             }
 437         }
 438         return i;
 439     }
 440 
 441     /**
 442      * Compares this {@code Timestamp} object to the given
 443      * {@code Date} object.
 444      *
 445      * @param o the {@code Date} to be compared to
 446      *          this {@code Timestamp} object
 447      * @return  the value {@code 0} if this {@code Timestamp} object
 448      *          and the given object are equal; a value less than {@code 0}
 449      *          if this  {@code Timestamp} object is before the given argument;
 450      *          and a value greater than {@code 0} if this
 451      *          {@code Timestamp} object is after the given argument.
 452      *
 453      * @since   1.5
 454      */
 455     public int compareTo(java.util.Date o) {
 456        if(o instanceof Timestamp) {
 457             // When Timestamp instance compare it with a Timestamp
 458             // Hence it is basically calling this.compareTo((Timestamp))o);
 459             // Note typecasting is safe because o is instance of Timestamp
 460            return compareTo((Timestamp)o);
 461       } else {
 462             // When Date doing a o.compareTo(this)
 463             // will give wrong results.
 464           Timestamp ts = new Timestamp(o.getTime());
 465           return this.compareTo(ts);
 466       }
 467     }
 468 
 469     /**
 470      * {@inheritDoc}
 471      *
 472      * The {@code hashCode} method uses the underlying {@code java.util.Date}
 473      * implementation and therefore does not include nanos in its computation.
 474      *
 475      */
 476     @Override
 477     public int hashCode() {
 478         return super.hashCode();
 479     }
 480 
 481     static final long serialVersionUID = 2745179027874758501L;
 482 
 483     private static final int MILLIS_PER_SECOND = 1000;
 484 
 485     /**
 486      * Obtains an instance of {@code Timestamp} from a {@code LocalDateTime}
 487      * object, with the same year, month, day of month, hours, minutes,
 488      * seconds and nanos date-time value as the provided {@code LocalDateTime}.
 489      * <p>
 490      * The provided {@code LocalDateTime} is interpreted as the local
 491      * date-time in the local time zone.
 492      *
 493      * @param dateTime a {@code LocalDateTime} to convert
 494      * @return a {@code Timestamp} object
 495      * @exception NullPointerException if {@code dateTime} is null.
 496      * @since 1.8
 497      */
 498     @SuppressWarnings("deprecation")
 499     public static Timestamp valueOf(LocalDateTime dateTime) {
 500         return new Timestamp(dateTime.getYear() - 1900,
 501                              dateTime.getMonthValue() - 1,
 502                              dateTime.getDayOfMonth(),
 503                              dateTime.getHour(),
 504                              dateTime.getMinute(),
 505                              dateTime.getSecond(),
 506                              dateTime.getNano());
 507     }
 508 
 509     /**
 510      * Converts this {@code Timestamp} object to a {@code LocalDateTime}.
 511      * <p>
 512      * The conversion creates a {@code LocalDateTime} that represents the
 513      * same year, month, day of month, hours, minutes, seconds and nanos
 514      * date-time value as this {@code Timestamp} in the local time zone.
 515      *
 516      * @return a {@code LocalDateTime} object representing the same date-time value
 517      * @since 1.8
 518      */
 519     @SuppressWarnings("deprecation")
 520     public LocalDateTime toLocalDateTime() {
 521         return LocalDateTime.of(getYear() + 1900,
 522                                 getMonth() + 1,
 523                                 getDate(),
 524                                 getHours(),
 525                                 getMinutes(),
 526                                 getSeconds(),
 527                                 getNanos());
 528     }
 529 
 530     /**
 531      * Obtains an instance of {@code Timestamp} from an {@link Instant} object.
 532      * <p>
 533      * {@code Instant} can store points on the time-line further in the future
 534      * and further in the past than {@code Date}. In this scenario, this method
 535      * will throw an exception.
 536      *
 537      * @param instant  the instant to convert
 538      * @return an {@code Timestamp} representing the same point on the time-line as
 539      *  the provided instant
 540      * @exception NullPointerException if {@code instant} is null.
 541      * @exception IllegalArgumentException if the instant is too large to
 542      *  represent as a {@code Timestamp}
 543      * @since 1.8
 544      */
 545     public static Timestamp from(Instant instant) {
 546         try {
 547             Timestamp stamp = new Timestamp(instant.getEpochSecond() * MILLIS_PER_SECOND);
 548             stamp.nanos = instant.getNano();
 549             return stamp;
 550         } catch (ArithmeticException ex) {
 551             throw new IllegalArgumentException(ex);
 552         }
 553     }
 554 
 555     /**
 556      * Converts this {@code Timestamp} object to an {@code Instant}.
 557      * <p>
 558      * The conversion creates an {@code Instant} that represents the same
 559      * point on the time-line as this {@code Timestamp}.
 560      *
 561      * @return an instant representing the same point on the time-line
 562      * @since 1.8
 563      */
 564     @Override
 565     public Instant toInstant() {
 566         return Instant.ofEpochSecond(super.getTime() / MILLIS_PER_SECOND, nanos);
 567     }
 568 }