1. /*
  2. * @(#)Timestamp.java 1.58 04/05/18
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package java.sql;
  8. /**
  9. * <P>A thin wrapper around <code>java.util.Date</code> that allows
  10. * the JDBC API to identify this as an SQL <code>TIMESTAMP</code> value.
  11. * It adds the ability
  12. * to hold the SQL <code>TIMESTAMP</code> nanos value and provides formatting and
  13. * parsing operations to support the JDBC escape syntax for timestamp values.
  14. *
  15. * <P><B>Note:</B> This type is a composite of a <code>java.util.Date</code> and a
  16. * separate nanoseconds value. Only integral seconds are stored in the
  17. * <code>java.util.Date</code> component. The fractional seconds - the nanos - are
  18. * separate. The <code>Timestamp.equals(Object)</code> method never returns
  19. * <code>true</code> when passed a value of type <code>java.util.Date</code>
  20. * because the nanos component of a date is unknown.
  21. * As a result, the <code>Timestamp.equals(Object)</code>
  22. * method is not symmetric with respect to the
  23. * <code>java.util.Date.equals(Object)</code>
  24. * method. Also, the <code>hashcode</code> method uses the underlying
  25. * <code>java.util.Date</code>
  26. * implementation and therefore does not include nanos in its computation.
  27. * <P>
  28. * Due to the differences between the <code>Timestamp</code> class
  29. * and the <code>java.util.Date</code>
  30. * class mentioned above, it is recommended that code not view
  31. * <code>Timestamp</code> values generically as an instance of
  32. * <code>java.util.Date</code>. The
  33. * inheritance relationship between <code>Timestamp</code>
  34. * and <code>java.util.Date</code> really
  35. * denotes implementation inheritance, and not type inheritance.
  36. */
  37. public class Timestamp extends java.util.Date {
  38. /**
  39. * Constructs a <code>Timestamp</code> object initialized
  40. * with the given values.
  41. *
  42. * @param year the year minus 1900
  43. * @param month 0 to 11
  44. * @param date 1 to 31
  45. * @param hour 0 to 23
  46. * @param minute 0 to 59
  47. * @param second 0 to 59
  48. * @param nano 0 to 999,999,999
  49. * @deprecated instead use the constructor <code>Timestamp(long millis)</code>
  50. * @exception IllegalArgumentException if the nano argument is out of bounds
  51. */
  52. @Deprecated
  53. public Timestamp(int year, int month, int date,
  54. int hour, int minute, int second, int nano) {
  55. super(year, month, date, hour, minute, second);
  56. if (nano > 999999999 || nano < 0) {
  57. throw new IllegalArgumentException("nanos > 999999999 or < 0");
  58. }
  59. nanos = nano;
  60. }
  61. /**
  62. * Constructs a <code>Timestamp</code> object
  63. * using a milliseconds time value. The
  64. * integral seconds are stored in the underlying date value; the
  65. * fractional seconds are stored in the <code>nanos</code> field of
  66. * the <code>Timestamp</code> object.
  67. *
  68. * @param time milliseconds since January 1, 1970, 00:00:00 GMT.
  69. * A negative number is the number of milliseconds before
  70. * January 1, 1970, 00:00:00 GMT.
  71. * @see java.util.Calendar for more information
  72. */
  73. public Timestamp(long time) {
  74. super((time1000)*1000);
  75. nanos = (int)((time%1000) * 1000000);
  76. if (nanos < 0) {
  77. nanos = 1000000000 + nanos;
  78. super.setTime(((time1000)-1)*1000);
  79. }
  80. }
  81. /**
  82. * Sets this <code>Timestamp</code> object to represent a point in time that is
  83. * <tt>time</tt> milliseconds after January 1, 1970 00:00:00 GMT.
  84. *
  85. * @param time the number of milliseconds.
  86. * @see #getTime
  87. * @see #Timestamp(long time)
  88. * @see java.util.Calendar for more information
  89. */
  90. public void setTime(long time) {
  91. super.setTime((time1000)*1000);
  92. nanos = (int)((time%1000) * 1000000);
  93. if (nanos < 0) {
  94. nanos = 1000000000 + nanos;
  95. super.setTime(((time1000)-1)*1000);
  96. }
  97. }
  98. /**
  99. * Returns the number of milliseconds since January 1, 1970, 00:00:00 GMT
  100. * represented by this <code>Timestamp</code> object.
  101. *
  102. * @return the number of milliseconds since January 1, 1970, 00:00:00 GMT
  103. * represented by this date.
  104. * @see #setTime
  105. */
  106. public long getTime() {
  107. long time = super.getTime();
  108. return (time + (nanos / 1000000));
  109. }
  110. /**
  111. * @serial
  112. */
  113. private int nanos;
  114. /**
  115. * Converts a <code>String</code> object in JDBC timestamp escape format to a
  116. * <code>Timestamp</code> value.
  117. *
  118. * @param s timestamp in format <code>yyyy-mm-dd hh:mm:ss.fffffffff</code>
  119. * @return corresponding <code>Timestamp</code> value
  120. * @exception java.lang.IllegalArgumentException if the given argument
  121. * does not have the format <code>yyyy-mm-dd hh:mm:ss.fffffffff</code>
  122. */
  123. public static Timestamp valueOf(String s) {
  124. String date_s;
  125. String time_s;
  126. String nanos_s;
  127. int year;
  128. int month;
  129. int day;
  130. int hour;
  131. int minute;
  132. int second;
  133. int a_nanos = 0;
  134. int firstDash;
  135. int secondDash;
  136. int dividingSpace;
  137. int firstColon = 0;
  138. int secondColon = 0;
  139. int period = 0;
  140. String formatError = "Timestamp format must be yyyy-mm-dd hh:mm:ss.fffffffff";
  141. String zeros = "000000000";
  142. if (s == null) throw new java.lang.IllegalArgumentException("null string");
  143. // Split the string into date and time components
  144. s = s.trim();
  145. dividingSpace = s.indexOf(' ');
  146. if (dividingSpace > 0) {
  147. date_s = s.substring(0,dividingSpace);
  148. time_s = s.substring(dividingSpace+1);
  149. } else {
  150. throw new java.lang.IllegalArgumentException(formatError);
  151. }
  152. // Parse the date
  153. firstDash = date_s.indexOf('-');
  154. secondDash = date_s.indexOf('-', firstDash+1);
  155. // Parse the time
  156. if (time_s == null)
  157. throw new java.lang.IllegalArgumentException(formatError);
  158. firstColon = time_s.indexOf(':');
  159. secondColon = time_s.indexOf(':', firstColon+1);
  160. period = time_s.indexOf('.', secondColon+1);
  161. // Convert the date
  162. if ((firstDash > 0) & (secondDash > 0) &
  163. (secondDash < date_s.length()-1)) {
  164. year = Integer.parseInt(date_s.substring(0, firstDash)) - 1900;
  165. month =
  166. Integer.parseInt(date_s.substring
  167. (firstDash+1, secondDash)) - 1;
  168. day = Integer.parseInt(date_s.substring(secondDash+1));
  169. } else {
  170. throw new java.lang.IllegalArgumentException(formatError);
  171. }
  172. // Convert the time; default missing nanos
  173. if ((firstColon > 0) & (secondColon > 0) &
  174. (secondColon < time_s.length()-1)) {
  175. hour = Integer.parseInt(time_s.substring(0, firstColon));
  176. minute =
  177. Integer.parseInt(time_s.substring(firstColon+1, secondColon));
  178. if ((period > 0) & (period < time_s.length()-1)) {
  179. second =
  180. Integer.parseInt(time_s.substring(secondColon+1, period));
  181. nanos_s = time_s.substring(period+1);
  182. if (nanos_s.length() > 9)
  183. throw new java.lang.IllegalArgumentException(formatError);
  184. if (!Character.isDigit(nanos_s.charAt(0)))
  185. throw new java.lang.IllegalArgumentException(formatError);
  186. nanos_s = nanos_s + zeros.substring(0,9-nanos_s.length());
  187. a_nanos = Integer.parseInt(nanos_s);
  188. } else if (period > 0) {
  189. throw new java.lang.IllegalArgumentException(formatError);
  190. } else {
  191. second = Integer.parseInt(time_s.substring(secondColon+1));
  192. }
  193. } else {
  194. throw new java.lang.IllegalArgumentException();
  195. }
  196. return new Timestamp(year, month, day, hour, minute, second, a_nanos);
  197. }
  198. /**
  199. * Formats a timestamp in JDBC timestamp escape format.
  200. * <code>yyyy-mm-dd hh:mm:ss.fffffffff</code>,
  201. * where <code>ffffffffff</code> indicates nanoseconds.
  202. * <P>
  203. * NOTE: To specify a timestamp for the class
  204. * <code>java.text.SimpleDateFormat</code>, use "yyyy.MM.dd" rather than
  205. * "yyyy-mm-dd". In the context of <code>java.text.SimpleDateFormat</code>,
  206. * "mm" indicates minutes rather than the month. Note that
  207. * <code>java.text.SimpleDateFormat</code> does not allow for the
  208. * nanoseconds component of a <code>Timestamp</code> object.
  209. * For Example:
  210. * <PRE>
  211. *
  212. * Format Pattern Result
  213. * -------------- ------
  214. * "yyyy.MM.dd G 'at' hh:mm:ss z" --> 2002.07.10 AD at 15:08:56 PDT
  215. *
  216. * </PRE>
  217. * @return a <code>String</code> object in
  218. * <code>yyyy-mm-dd hh:mm:ss.fffffffff</code> format
  219. */
  220. public String toString () {
  221. int year = super.getYear() + 1900;
  222. int month = super.getMonth() + 1;
  223. int day = super.getDate();
  224. int hour = super.getHours();
  225. int minute = super.getMinutes();
  226. int second = super.getSeconds();
  227. String yearString;
  228. String monthString;
  229. String dayString;
  230. String hourString;
  231. String minuteString;
  232. String secondString;
  233. String nanosString;
  234. String zeros = "000000000";
  235. String yearZeros = "0000";
  236. StringBuffer timestampBuf;
  237. if (year < 1000) {
  238. // Add leading zeros
  239. yearString = "" + year;
  240. yearString = yearZeros.substring(0, (4-yearString.length())) +
  241. yearString;
  242. } else {
  243. yearString = "" + year;
  244. }
  245. if (month < 10) {
  246. monthString = "0" + month;
  247. } else {
  248. monthString = Integer.toString(month);
  249. }
  250. if (day < 10) {
  251. dayString = "0" + day;
  252. } else {
  253. dayString = Integer.toString(day);
  254. }
  255. if (hour < 10) {
  256. hourString = "0" + hour;
  257. } else {
  258. hourString = Integer.toString(hour);
  259. }
  260. if (minute < 10) {
  261. minuteString = "0" + minute;
  262. } else {
  263. minuteString = Integer.toString(minute);
  264. }
  265. if (second < 10) {
  266. secondString = "0" + second;
  267. } else {
  268. secondString = Integer.toString(second);
  269. }
  270. if (nanos == 0) {
  271. nanosString = "0";
  272. } else {
  273. nanosString = Integer.toString(nanos);
  274. // Add leading zeros
  275. nanosString = zeros.substring(0, (9-nanosString.length())) +
  276. nanosString;
  277. // Truncate trailing zeros
  278. char[] nanosChar = new char[nanosString.length()];
  279. nanosString.getChars(0, nanosString.length(), nanosChar, 0);
  280. int truncIndex = 8;
  281. while (nanosChar[truncIndex] == '0') {
  282. truncIndex--;
  283. }
  284. nanosString = new String(nanosChar, 0, truncIndex + 1);
  285. }
  286. // do a string buffer here instead.
  287. timestampBuf = new StringBuffer();
  288. timestampBuf.append(yearString);
  289. timestampBuf.append("-");
  290. timestampBuf.append(monthString);
  291. timestampBuf.append("-");
  292. timestampBuf.append(dayString);
  293. timestampBuf.append(" ");
  294. timestampBuf.append(hourString);
  295. timestampBuf.append(":");
  296. timestampBuf.append(minuteString);
  297. timestampBuf.append(":");
  298. timestampBuf.append(secondString);
  299. timestampBuf.append(".");
  300. timestampBuf.append(nanosString);
  301. return (timestampBuf.toString());
  302. }
  303. /**
  304. * Gets this <code>Timestamp</code> object's <code>nanos</code> value.
  305. *
  306. * @return this <code>Timestamp</code> object's fractional seconds component
  307. * @see #setNanos
  308. */
  309. public int getNanos() {
  310. return nanos;
  311. }
  312. /**
  313. * Sets this <code>Timestamp</code> object's <code>nanos</code> field
  314. * to the given value.
  315. *
  316. * @param n the new fractional seconds component
  317. * @exception java.lang.IllegalArgumentException if the given argument
  318. * is greater than 999999999 or less than 0
  319. * @see #getNanos
  320. */
  321. public void setNanos(int n) {
  322. if (n > 999999999 || n < 0) {
  323. throw new IllegalArgumentException("nanos > 999999999 or < 0");
  324. }
  325. nanos = n;
  326. }
  327. /**
  328. * Tests to see if this <code>Timestamp</code> object is
  329. * equal to the given <code>Timestamp</code> object.
  330. *
  331. * @param ts the <code>Timestamp</code> value to compare with
  332. * @return <code>true</code> if the given <code>Timestamp</code>
  333. * object is equal to this <code>Timestamp</code> object;
  334. * <code>false</code> otherwise
  335. */
  336. public boolean equals(Timestamp ts) {
  337. if (super.equals(ts)) {
  338. if (nanos == ts.nanos) {
  339. return true;
  340. } else {
  341. return false;
  342. }
  343. } else {
  344. return false;
  345. }
  346. }
  347. /**
  348. * Tests to see if this <code>Timestamp</code> object is
  349. * equal to the given object.
  350. *
  351. * This version of the method <code>equals</code> has been added
  352. * to fix the incorrect
  353. * signature of <code>Timestamp.equals(Timestamp)</code> and to preserve backward
  354. * compatibility with existing class files.
  355. *
  356. * Note: This method is not symmetric with respect to the
  357. * <code>equals(Object)</code> method in the base class.
  358. *
  359. * @param ts the <code>Object</code> value to compare with
  360. * @return <code>true</code> if the given <code>Object</code>
  361. * instance is equal to this <code>Timestamp</code> object;
  362. * <code>false</code> otherwise
  363. */
  364. public boolean equals(java.lang.Object ts) {
  365. if (ts instanceof Timestamp) {
  366. return this.equals((Timestamp)ts);
  367. } else {
  368. return false;
  369. }
  370. }
  371. /**
  372. * Indicates whether this <code>Timestamp</code> object is
  373. * earlier than the given <code>Timestamp</code> object.
  374. *
  375. * @param ts the <code>Timestamp</code> value to compare with
  376. * @return <code>true</code> if this <code>Timestamp</code> object is earlier;
  377. * <code>false</code> otherwise
  378. */
  379. public boolean before(Timestamp ts) {
  380. return compareTo(ts) < 0;
  381. }
  382. /**
  383. * Indicates whether this <code>Timestamp</code> object is
  384. * later than the given <code>Timestamp</code> object.
  385. *
  386. * @param ts the <code>Timestamp</code> value to compare with
  387. * @return <code>true</code> if this <code>Timestamp</code> object is later;
  388. * <code>false</code> otherwise
  389. */
  390. public boolean after(Timestamp ts) {
  391. return compareTo(ts) > 0;
  392. }
  393. /**
  394. * Compares this <code>Timestamp</code> object to the given
  395. * <code>Timestamp</code> object.
  396. *
  397. * @param ts the <code>Timestamp</code> object to be compared to
  398. * this <code>Timestamp</code> object
  399. * @return the value <code>0</code> if the two <code>Timestamp</code>
  400. * objects are equal; a value less than <code>0</code> if this
  401. * <code>Timestamp</code> object is before the given argument;
  402. * and a value greater than <code>0</code> if this
  403. * <code>Timestamp</code> object is after the given argument.
  404. * @since 1.2
  405. */
  406. public int compareTo(Timestamp ts) {
  407. int i = super.compareTo(ts);
  408. if (i == 0) {
  409. if (nanos > ts.nanos) {
  410. return 1;
  411. } else if (nanos < ts.nanos) {
  412. return -1;
  413. }
  414. }
  415. return i;
  416. }
  417. /**
  418. * Compares this <code>Timestamp</code> object to the given
  419. * <code>Date</code>, which must be a <code>Timestamp</code>
  420. * object. If the argument is not a <code>Timestamp</code> object,
  421. * this method throws a <code>ClassCastException</code> object.
  422. * (<code>Timestamp</code> objects are
  423. * comparable only to other <code>Timestamp</code> objects.)
  424. *
  425. * @param o the <code>Date</code> to be compared, which must be a
  426. * <code>Timestamp</code> object
  427. * @return the value <code>0</code> if this <code>Timestamp</code> object
  428. * and the given object are equal; a value less than <code>0</code>
  429. * if this <code>Timestamp</code> object is before the given argument;
  430. * and a value greater than <code>0</code> if this
  431. * <code>Timestamp</code> object is after the given argument.
  432. *
  433. * @exception ClassCastException if the argument is not a
  434. * <code>Timestamp</code> object
  435. * @since 1.5
  436. */
  437. // This forwarding method ensures that the compareTo(Date) method defined
  438. // in java.util.Date is not invoked on a Timestamp
  439. public int compareTo(java.util.Date o) {
  440. return compareTo((Timestamp)o);
  441. }
  442. static final long serialVersionUID = 2745179027874758501L;
  443. }