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