1. /*
  2. * @(#)Timestamp.java 1.53 03/01/27
  3. *
  4. * Copyright 2003 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.Data</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. public Timestamp(int year, int month, int date,
  53. int hour, int minute, int second, int nano) {
  54. super(year, month, date, hour, minute, second);
  55. if (nano > 999999999 || nano < 0) {
  56. throw new IllegalArgumentException("nanos > 999999999 or < 0");
  57. }
  58. nanos = nano;
  59. }
  60. /**
  61. * Constructs a <code>Timestamp</code> object
  62. * using a milliseconds time value. The
  63. * integral seconds are stored in the underlying date value; the
  64. * fractional seconds are stored in the <code>nanos</code> field of
  65. * the <code>Timestamp</code> object.
  66. *
  67. * @param time milliseconds since January 1, 1970, 00:00:00 GMT.
  68. * A negative number is the number of milliseconds before
  69. * January 1, 1970, 00:00:00 GMT.
  70. * @see java.util.Calendar for more information
  71. */
  72. public Timestamp(long time) {
  73. super((time1000)*1000);
  74. nanos = (int)((time%1000) * 1000000);
  75. if (nanos < 0) {
  76. nanos = 1000000000 + nanos;
  77. super.setTime(((time1000)-1)*1000);
  78. }
  79. }
  80. /**
  81. * Sets this <code>Timestamp</code> object to represent a point in time that is
  82. * <tt>time</tt> milliseconds after January 1, 1970 00:00:00 GMT.
  83. *
  84. * @param time the number of milliseconds.
  85. * @see #getTime
  86. * @see #Timestamp(long time)
  87. * @see java.util.Calendar for more information
  88. */
  89. public void setTime(long time) {
  90. super.setTime((time1000)*1000);
  91. nanos = (int)((time%1000) * 1000000);
  92. if (nanos < 0) {
  93. nanos = 1000000000 + nanos;
  94. super.setTime(((time1000)-1)*1000);
  95. }
  96. }
  97. /**
  98. * Returns the number of milliseconds since January 1, 1970, 00:00:00 GMT
  99. * represented by this <code>Timestamp</code> object.
  100. *
  101. * @return the number of milliseconds since January 1, 1970, 00:00:00 GMT
  102. * represented by this date.
  103. * @see #setTime
  104. */
  105. public long getTime() {
  106. long time = super.getTime();
  107. return (time + (nanos / 1000000));
  108. }
  109. /**
  110. * @serial
  111. */
  112. private int nanos;
  113. /**
  114. * Converts a <code>String</code> object in JDBC timestamp escape format to a
  115. * <code>Timestamp</code> value.
  116. *
  117. * @param s timestamp in format <code>yyyy-mm-dd hh:mm:ss.fffffffff</code>
  118. * @return corresponding <code>Timestamp</code> value
  119. * @exception java.lang.IllegalArgumentException if the given argument
  120. * does not have the format <code>yyyy-mm-dd hh:mm:ss.fffffffff</code>
  121. */
  122. public static Timestamp valueOf(String s) {
  123. String date_s;
  124. String time_s;
  125. String nanos_s;
  126. int year;
  127. int month;
  128. int day;
  129. int hour;
  130. int minute;
  131. int second;
  132. int a_nanos = 0;
  133. int firstDash;
  134. int secondDash;
  135. int dividingSpace;
  136. int firstColon = 0;
  137. int secondColon = 0;
  138. int period = 0;
  139. String formatError = "Timestamp format must be yyyy-mm-dd hh:mm:ss.fffffffff";
  140. String zeros = "000000000";
  141. if (s == null) throw new java.lang.IllegalArgumentException("null string");
  142. // Split the string into date and time components
  143. s = s.trim();
  144. dividingSpace = s.indexOf(' ');
  145. if (dividingSpace > 0) {
  146. date_s = s.substring(0,dividingSpace);
  147. time_s = s.substring(dividingSpace+1);
  148. } else {
  149. throw new java.lang.IllegalArgumentException(formatError);
  150. }
  151. // Parse the date
  152. firstDash = date_s.indexOf('-');
  153. secondDash = date_s.indexOf('-', firstDash+1);
  154. // Parse the time
  155. if (time_s == null)
  156. throw new java.lang.IllegalArgumentException(formatError);
  157. firstColon = time_s.indexOf(':');
  158. secondColon = time_s.indexOf(':', firstColon+1);
  159. period = time_s.indexOf('.', secondColon+1);
  160. // Convert the date
  161. if ((firstDash > 0) & (secondDash > 0) &
  162. (secondDash < date_s.length()-1)) {
  163. year = Integer.parseInt(date_s.substring(0, firstDash)) - 1900;
  164. month =
  165. Integer.parseInt(date_s.substring
  166. (firstDash+1, secondDash)) - 1;
  167. day = Integer.parseInt(date_s.substring(secondDash+1));
  168. } else {
  169. throw new java.lang.IllegalArgumentException(formatError);
  170. }
  171. // Convert the time; default missing nanos
  172. if ((firstColon > 0) & (secondColon > 0) &
  173. (secondColon < time_s.length()-1)) {
  174. hour = Integer.parseInt(time_s.substring(0, firstColon));
  175. minute =
  176. Integer.parseInt(time_s.substring(firstColon+1, secondColon));
  177. if ((period > 0) & (period < time_s.length()-1)) {
  178. second =
  179. Integer.parseInt(time_s.substring(secondColon+1, period));
  180. nanos_s = time_s.substring(period+1);
  181. if (nanos_s.length() > 9)
  182. throw new java.lang.IllegalArgumentException(formatError);
  183. if (!Character.isDigit(nanos_s.charAt(0)))
  184. throw new java.lang.IllegalArgumentException(formatError);
  185. nanos_s = nanos_s + zeros.substring(0,9-nanos_s.length());
  186. a_nanos = Integer.parseInt(nanos_s);
  187. } else if (period > 0) {
  188. throw new java.lang.IllegalArgumentException(formatError);
  189. } else {
  190. second = Integer.parseInt(time_s.substring(secondColon+1));
  191. }
  192. } else {
  193. throw new java.lang.IllegalArgumentException();
  194. }
  195. return new Timestamp(year, month, day, hour, minute, second, a_nanos);
  196. }
  197. /**
  198. * Formats a timestamp in JDBC timestamp escape format.
  199. * <code>yyyy-mm-dd hh:mm:ss.fffffffff</code>,
  200. * where <code>ffffffffff</code> indicates nanoseconds.
  201. * <P>
  202. * NOTE: To specify a timestamp for the class
  203. * <code>java.text.SimpleDateFormat</code>, use "yyyy.MM.dd" rather than
  204. * "yyyy-mm-dd". In the context of <code>java.text.SimpleDateFormat</code>,
  205. * "mm" indicates minutes rather than the month. Note that
  206. * <code>java.text.SimpleDateFormat</code> does not allow for the
  207. * nanoseconds component of a <code>Timestamp</code> object.
  208. * For Example:
  209. * <PRE>
  210. *
  211. * Format Pattern Result
  212. * -------------- ------
  213. * "yyyy.MM.dd G 'at' hh:mm:ss z" --> 2002.07.10 AD at 15:08:56 PDT
  214. *
  215. * </PRE>
  216. * @return a <code>String</code> object in
  217. * <code>yyyy-mm-dd hh:mm:ss.fffffffff</code> format
  218. */
  219. public String toString () {
  220. int year = super.getYear() + 1900;
  221. int month = super.getMonth() + 1;
  222. int day = super.getDate();
  223. int hour = super.getHours();
  224. int minute = super.getMinutes();
  225. int second = super.getSeconds();
  226. String yearString;
  227. String monthString;
  228. String dayString;
  229. String hourString;
  230. String minuteString;
  231. String secondString;
  232. String nanosString;
  233. String zeros = "000000000";
  234. String yearZeros = "0000";
  235. StringBuffer timestampBuf;
  236. if (year < 1000) {
  237. // Add leading zeros
  238. yearString = "" + year;
  239. yearString = yearZeros.substring(0, (4-yearString.length())) +
  240. yearString;
  241. } else {
  242. yearString = "" + year;
  243. }
  244. if (month < 10) {
  245. monthString = "0" + month;
  246. } else {
  247. monthString = Integer.toString(month);
  248. }
  249. if (day < 10) {
  250. dayString = "0" + day;
  251. } else {
  252. dayString = Integer.toString(day);
  253. }
  254. if (hour < 10) {
  255. hourString = "0" + hour;
  256. } else {
  257. hourString = Integer.toString(hour);
  258. }
  259. if (minute < 10) {
  260. minuteString = "0" + minute;
  261. } else {
  262. minuteString = Integer.toString(minute);
  263. }
  264. if (second < 10) {
  265. secondString = "0" + second;
  266. } else {
  267. secondString = Integer.toString(second);
  268. }
  269. if (nanos == 0) {
  270. nanosString = "0";
  271. } else {
  272. nanosString = Integer.toString(nanos);
  273. // Add leading zeros
  274. nanosString = zeros.substring(0, (9-nanosString.length())) +
  275. nanosString;
  276. // Truncate trailing zeros
  277. char[] nanosChar = new char[nanosString.length()];
  278. nanosString.getChars(0, nanosString.length(), nanosChar, 0);
  279. int truncIndex = 8;
  280. while (nanosChar[truncIndex] == '0') {
  281. truncIndex--;
  282. }
  283. nanosString = new String(nanosChar, 0, truncIndex + 1);
  284. }
  285. // do a string buffer here instead.
  286. timestampBuf = new StringBuffer();
  287. timestampBuf.append(yearString);
  288. timestampBuf.append("-");
  289. timestampBuf.append(monthString);
  290. timestampBuf.append("-");
  291. timestampBuf.append(dayString);
  292. timestampBuf.append(" ");
  293. timestampBuf.append(hourString);
  294. timestampBuf.append(":");
  295. timestampBuf.append(minuteString);
  296. timestampBuf.append(":");
  297. timestampBuf.append(secondString);
  298. timestampBuf.append(".");
  299. timestampBuf.append(nanosString);
  300. return (timestampBuf.toString());
  301. }
  302. /**
  303. * Gets this <code>Timestamp</code> object's <code>nanos</code> value.
  304. *
  305. * @return this <code>Timestamp</code> object's fractional seconds component
  306. * @see #setNanos
  307. */
  308. public int getNanos() {
  309. return nanos;
  310. }
  311. /**
  312. * Sets this <code>Timestamp</code> object's <code>nanos</code> field
  313. * to the given value.
  314. *
  315. * @param n the new fractional seconds component
  316. * @exception java.lang.IllegalArgumentException if the given argument
  317. * is greater than 999999999 or less than 0
  318. * @see #getNanos
  319. */
  320. public void setNanos(int n) {
  321. if (n > 999999999 || n < 0) {
  322. throw new IllegalArgumentException("nanos > 999999999 or < 0");
  323. }
  324. nanos = n;
  325. }
  326. /**
  327. * Tests to see if this <code>Timestamp</code> object is
  328. * equal to the given <code>Timestamp</code> object.
  329. *
  330. * @param ts the <code>Timestamp</code> value to compare with
  331. * @return <code>true</code> if the given <code>Timestamp</code>
  332. * object is equal to this <code>Timestamp</code> object;
  333. * <code>false</code> otherwise
  334. */
  335. public boolean equals(Timestamp ts) {
  336. if (super.equals(ts)) {
  337. if (nanos == ts.nanos) {
  338. return true;
  339. } else {
  340. return false;
  341. }
  342. } else {
  343. return false;
  344. }
  345. }
  346. /**
  347. * Tests to see if this <code>Timestamp</code> object is
  348. * equal to the given object.
  349. *
  350. * This version of the method <code>equals</code> has been added
  351. * to fix the incorrect
  352. * signature of <code>Timestamp.equals(Timestamp)</code> and to preserve backward
  353. * compatibility with existing class files.
  354. *
  355. * Note: This method is not symmetric with respect to the
  356. * <code>equals(Object)</code> method in the base class.
  357. *
  358. * @param ts the <code>Object</code> value to compare with
  359. * @return <code>true</code> if the given <code>Object</code>
  360. * instance is equal to this <code>Timestamp</code> object;
  361. * <code>false</code> otherwise
  362. */
  363. public boolean equals(java.lang.Object ts) {
  364. if (ts instanceof Timestamp) {
  365. return this.equals((Timestamp)ts);
  366. } else {
  367. return false;
  368. }
  369. }
  370. /**
  371. * Indicates whether this <code>Timestamp</code> object is
  372. * earlier than the given <code>Timestamp</code> object.
  373. *
  374. * @param ts the <code>Timestamp</code> value to compare with
  375. * @return <code>true</code> if this <code>Timestamp</code> object is earlier;
  376. * <code>false</code> otherwise
  377. */
  378. public boolean before(Timestamp ts) {
  379. if (super.before(ts)) {
  380. return true;
  381. } else {
  382. if (super.equals(ts)) {
  383. if (nanos < ts.nanos) {
  384. return true;
  385. } else {
  386. return false;
  387. }
  388. } else {
  389. return false;
  390. }
  391. }
  392. }
  393. /**
  394. * Indicates whether this <code>Timestamp</code> object is
  395. * later than the given <code>Timestamp</code> object.
  396. *
  397. * @param ts the <code>Timestamp</code> value to compare with
  398. * @return <code>true</code> if this <code>Timestamp</code> object is later;
  399. * <code>false</code> otherwise
  400. */
  401. public boolean after(Timestamp ts) {
  402. if (super.after(ts)) {
  403. return true;
  404. } else {
  405. if (super.equals(ts)) {
  406. if (nanos > ts.nanos) {
  407. return true;
  408. } else {
  409. return false;
  410. }
  411. } else {
  412. return false;
  413. }
  414. }
  415. }
  416. /**
  417. * Compares this <code>Timestamp</code> object to the given
  418. * <code>Timestamp</code> object.
  419. *
  420. * @param ts the <code>Timestamp</code> object to be compared to
  421. * this <code>Timestamp</code> object
  422. * @return the value <code>0</code> if the two <code>Timestamp</code>
  423. * objects are equal; a value less than <code>0</code> if this
  424. * <code>Timestamp</code> object is before the given argument;
  425. * and a value greater than <code>0</code> if this
  426. * <code>Timestamp</code> object is after the given argument.
  427. * @since 1.2
  428. */
  429. public int compareTo(Timestamp ts) {
  430. int i = super.compareTo(ts);
  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. * Compares this <code>Timestamp</code> object to the given
  442. * <code>Object</code>, which must be a <code>Timestamp</code>
  443. * object. If the argument is not a <code>Timestamp</code> object,
  444. * this method throws a <code>ClassCastException</code> object.
  445. * (<code>Timestamp</code> objects are
  446. * comparable only to other <code>Timestamp</code> objects.)
  447. *
  448. * @param o the <code>Object</code> to be compared, which must be a
  449. * <code>Timestamp</code> object
  450. * @return the value <code>0</code> if this <code>Timestamp</code> object
  451. * and the given object are equal; a value less than <code>0</code>
  452. * if this <code>Timestamp</code> object is before the given argument;
  453. * and a value greater than <code>0</code> if this
  454. * <code>Timestamp</code> object is after the given argument.
  455. *
  456. * @exception ClassCastException if the argument is not a
  457. * <code>Timestamp</code> object
  458. */
  459. public int compareTo(Object o) {
  460. return compareTo((Timestamp)o);
  461. }
  462. static final long serialVersionUID = 2745179027874758501L;
  463. }