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 }