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