1. /*
  2. * @(#)Timestamp.java 1.34 00/02/02
  3. *
  4. * Copyright 1996-2000 Sun Microsystems, Inc. All Rights Reserved.
  5. *
  6. * This software is the proprietary information of Sun Microsystems, Inc.
  7. * Use is subject to license terms.
  8. *
  9. */
  10. package java.sql;
  11. /**
  12. * <P>A thin wrapper around <code>java.util.Date</code> that allows
  13. * the JDBC API to identify this as an SQL <code>TIMESTAMP</code> value.
  14. * It adds the ability
  15. * to hold the SQL <code>TIMESTAMP</code> nanos value and provides formatting and
  16. * parsing operations to support the JDBC escape syntax for timestamp values.
  17. *
  18. * <P><B>Note:</B> This type is a composite of a <code>java.util.Date</code> and a
  19. * separate nanoseconds value. Only integral seconds are stored in the
  20. * <code>java.util.Date</code> component. The fractional seconds - the nanos - are
  21. * separate. The <code>getTime</code> method will return only integral seconds. If
  22. * a time value that includes the fractional seconds is desired, you
  23. * must convert nanos to milliseconds (nanos/1000000) and add this to
  24. * the <code>getTime</code> value. The
  25. * <code>Timestamp.equals(Object)</code> method never returns
  26. * <code>true</code> when passed a value of type <code>java.util.Date</code>
  27. * because the nanos component of a date is unknown.
  28. * As a result, the <code>Timestamp.equals(Object)</code>
  29. * method is not symmetric with respect to the
  30. * <code>java.util.Date.equals(Object)</code>
  31. * method. Also, the <code>hashcode</code> method uses the underlying
  32. * <code>java.util.Data</code>
  33. * implementation and therefore does not include nanos in its computation.
  34. *
  35. * Due to the differences between the <code>Timestamp</code> class
  36. * and the <code>java.util.Date</code>
  37. * class mentioned above, it is recommended that code not view
  38. * <code>Timestamp</code> values generically as an instance of
  39. * <code>java.util.Date</code>. The
  40. * inheritance relationship between <code>Timestamp</code>
  41. * and <code>java.util.Date</code> really
  42. * denotes implementation inheritance, and not type inheritance.
  43. */
  44. public class Timestamp extends java.util.Date {
  45. /**
  46. * Constructs a <code>Timestamp</code> object initialized
  47. * with the given values.
  48. *
  49. * @param year year-1900
  50. * @param month 0 to 11
  51. * @param date 1 to 31
  52. * @param hour 0 to 23
  53. * @param minute 0 to 59
  54. * @param second 0 to 59
  55. * @param nano 0 to 999,999,999
  56. * @deprecated instead use the constructor <code>Timestamp(long millis)</code>
  57. */
  58. public Timestamp(int year, int month, int date,
  59. int hour, int minute, int second, int nano) {
  60. super(year, month, date, hour, minute, second);
  61. if (nano > 999999999 || nano < 0) {
  62. throw new IllegalArgumentException("nanos > 999999999 or < 0");
  63. }
  64. nanos = nano;
  65. }
  66. /**
  67. * Constructs a <code>Timestamp</code> object
  68. * using a milliseconds time value. The
  69. * integral seconds are stored in the underlying date value; the
  70. * fractional seconds are stored in the <code>nanos</code> field of
  71. * the <code>Timestamp</code> object.
  72. *
  73. * @param time milliseconds since January 1, 1970, 00:00:00 GMT.
  74. * A negative number is the number of milliseconds before
  75. * January 1, 1970, 00:00:00 GMT.
  76. */
  77. public Timestamp(long time) {
  78. super((time1000)*1000);
  79. nanos = (int)((time%1000) * 1000000);
  80. if (nanos < 0) {
  81. nanos = 1000000000 + nanos;
  82. setTime(((time1000)-1)*1000);
  83. }
  84. }
  85. /**
  86. * @serial
  87. */
  88. private int nanos;
  89. /**
  90. * Converts a <code>String</code> object in JDBC timestamp escape format to a
  91. * <code>Timestamp</code> value.
  92. *
  93. * @param s timestamp in format <code>yyyy-mm-dd hh:mm:ss.fffffffff</code>
  94. * @return corresponding <code>Timestamp</code> value
  95. * @exception java.lang.IllegalArgumentException if the given argument
  96. * does not have the format <code>yyyy-mm-dd hh:mm:ss.fffffffff</code>
  97. */
  98. public static Timestamp valueOf(String s) {
  99. String date_s;
  100. String time_s;
  101. String nanos_s;
  102. int year;
  103. int month;
  104. int day;
  105. int hour;
  106. int minute;
  107. int second;
  108. int a_nanos = 0;
  109. int firstDash;
  110. int secondDash;
  111. int dividingSpace;
  112. int firstColon = 0;
  113. int secondColon = 0;
  114. int period = 0;
  115. String formatError = "Timestamp format must be yyyy-mm-dd hh:mm:ss.fffffffff";
  116. String zeros = "000000000";
  117. if (s == null) throw new java.lang.IllegalArgumentException("null string");
  118. // Split the string into date and time components
  119. s = s.trim();
  120. dividingSpace = s.indexOf(' ');
  121. if (dividingSpace > 0) {
  122. date_s = s.substring(0,dividingSpace);
  123. time_s = s.substring(dividingSpace+1);
  124. } else {
  125. throw new java.lang.IllegalArgumentException(formatError);
  126. }
  127. // Parse the date
  128. firstDash = date_s.indexOf('-');
  129. secondDash = date_s.indexOf('-', firstDash+1);
  130. // Parse the time
  131. if (time_s == null)
  132. throw new java.lang.IllegalArgumentException(formatError);
  133. firstColon = time_s.indexOf(':');
  134. secondColon = time_s.indexOf(':', firstColon+1);
  135. period = time_s.indexOf('.', secondColon+1);
  136. // Convert the date
  137. if ((firstDash > 0) & (secondDash > 0) &
  138. (secondDash < date_s.length()-1)) {
  139. year = Integer.parseInt(date_s.substring(0, firstDash)) - 1900;
  140. month =
  141. Integer.parseInt(date_s.substring
  142. (firstDash+1, secondDash)) - 1;
  143. day = Integer.parseInt(date_s.substring(secondDash+1));
  144. } else {
  145. throw new java.lang.IllegalArgumentException(formatError);
  146. }
  147. // Convert the time; default missing nanos
  148. if ((firstColon > 0) & (secondColon > 0) &
  149. (secondColon < time_s.length()-1)) {
  150. hour = Integer.parseInt(time_s.substring(0, firstColon));
  151. minute =
  152. Integer.parseInt(time_s.substring(firstColon+1, secondColon));
  153. if ((period > 0) & (period < time_s.length()-1)) {
  154. second =
  155. Integer.parseInt(time_s.substring(secondColon+1, period));
  156. nanos_s = time_s.substring(period+1);
  157. if (nanos_s.length() > 9)
  158. throw new java.lang.IllegalArgumentException(formatError);
  159. if (!Character.isDigit(nanos_s.charAt(0)))
  160. throw new java.lang.IllegalArgumentException(formatError);
  161. nanos_s = nanos_s + zeros.substring(0,9-nanos_s.length());
  162. a_nanos = Integer.parseInt(nanos_s);
  163. } else if (period > 0) {
  164. throw new java.lang.IllegalArgumentException(formatError);
  165. } else {
  166. second = Integer.parseInt(time_s.substring(secondColon+1));
  167. }
  168. } else {
  169. throw new java.lang.IllegalArgumentException();
  170. }
  171. return new Timestamp(year, month, day, hour, minute, second, a_nanos);
  172. }
  173. /**
  174. * Formats a timestamp in JDBC timestamp escape format.
  175. *
  176. * @return a <code>String</code> object in
  177. * <code>yyyy-mm-dd hh:mm:ss.fffffffff</code> format
  178. * @overrides <code>toString</code> in class <code>java.util.Date</code>
  179. */
  180. public String toString () {
  181. int year = super.getYear() + 1900;
  182. int month = super.getMonth() + 1;
  183. int day = super.getDate();
  184. int hour = super.getHours();
  185. int minute = super.getMinutes();
  186. int second = super.getSeconds();
  187. String yearString;
  188. String monthString;
  189. String dayString;
  190. String hourString;
  191. String minuteString;
  192. String secondString;
  193. String nanosString;
  194. String zeros = "000000000";
  195. yearString = "" + year;
  196. if (month < 10) {
  197. monthString = "0" + month;
  198. } else {
  199. monthString = Integer.toString(month);
  200. }
  201. if (day < 10) {
  202. dayString = "0" + day;
  203. } else {
  204. dayString = Integer.toString(day);
  205. }
  206. if (hour < 10) {
  207. hourString = "0" + hour;
  208. } else {
  209. hourString = Integer.toString(hour);
  210. }
  211. if (minute < 10) {
  212. minuteString = "0" + minute;
  213. } else {
  214. minuteString = Integer.toString(minute);
  215. }
  216. if (second < 10) {
  217. secondString = "0" + second;
  218. } else {
  219. secondString = Integer.toString(second);
  220. }
  221. if (nanos == 0) {
  222. nanosString = "0";
  223. } else {
  224. nanosString = Integer.toString(nanos);
  225. // Add leading zeros
  226. nanosString = zeros.substring(0,(9-nanosString.length())) +
  227. nanosString;
  228. // Truncate trailing zeros
  229. char[] nanosChar = new char[nanosString.length()];
  230. nanosString.getChars(0, nanosString.length(), nanosChar, 0);
  231. int truncIndex = 8;
  232. while (nanosChar[truncIndex] == '0') {
  233. truncIndex--;
  234. }
  235. nanosString = new String(nanosChar,0,truncIndex+1);
  236. }
  237. return (yearString + "-" + monthString + "-" + dayString + " " +
  238. hourString + ":" + minuteString + ":" + secondString + "."
  239. + nanosString);
  240. }
  241. /**
  242. * Gets this <code>Timestamp</code> object's <code>nanos</code> value.
  243. *
  244. * @return this <code>Timestamp</code> object's fractional seconds component
  245. */
  246. public int getNanos() {
  247. return nanos;
  248. }
  249. /**
  250. * Sets this <code>Timestamp</code> object's <code>nanos</code> field
  251. * to the given value.
  252. *
  253. * @param n the new fractional seconds component
  254. * @exception java.lang.IllegalArgumentException if the given argument
  255. * is greater than 999999999 or less than 0
  256. */
  257. public void setNanos(int n) {
  258. if (n > 999999999 || n < 0) {
  259. throw new IllegalArgumentException("nanos > 999999999 or < 0");
  260. }
  261. nanos = n;
  262. }
  263. /**
  264. * Tests to see if this <code>Timestamp</code> object is
  265. * equal to the given <code>Timestamp</code> object.
  266. *
  267. * @param ts the <code>Timestamp</code> value to compare with
  268. */
  269. public boolean equals(Timestamp ts) {
  270. if (super.equals(ts)) {
  271. if (nanos == ts.nanos) {
  272. return true;
  273. } else {
  274. return false;
  275. }
  276. } else {
  277. return false;
  278. }
  279. }
  280. /**
  281. * Tests to see if this <code>Timestamp</code> object is
  282. * equal to the given object.
  283. *
  284. * This version of the method <code>equals</code> has been added
  285. * to fix the incorrect
  286. * signature of <code>Timestamp.equals(Timestamp)</code> and to preserve backward
  287. * compatibility with existing class files.
  288. *
  289. * Note: This method is not symmetric with respect to the
  290. * <code>equals(Object)</code> method in the base class.
  291. *
  292. * @param ts the <code>Object</code> value to compare with
  293. */
  294. public boolean equals(java.lang.Object ts) {
  295. if (ts instanceof Timestamp) {
  296. return this.equals((Timestamp)ts);
  297. } else {
  298. return false;
  299. }
  300. }
  301. /**
  302. * Indicates whether this <code>Timestamp</code> object is
  303. * earlier than the given <code>Timestamp</code> object.
  304. *
  305. * @param ts the <code>Timestamp</code> value to compare with
  306. * @return <code>true</code> if this <code>Timestamp</code> object is earlier;
  307. * <code>false</code> otherwise
  308. */
  309. public boolean before(Timestamp ts) {
  310. if (super.before(ts)) {
  311. return true;
  312. } else {
  313. if (super.equals(ts)) {
  314. if (nanos < ts.nanos) {
  315. return true;
  316. } else {
  317. return false;
  318. }
  319. } else {
  320. return false;
  321. }
  322. }
  323. }
  324. /**
  325. * Indicates whether this <code>Timestamp</code> object is
  326. * later than the given <code>Timestamp</code> object.
  327. *
  328. * @param ts the <code>Timestamp</code> value to compare with
  329. * @return <code>true</code> if this <code>Timestamp</code> object is later;
  330. * <code>false</code> otherwise
  331. */
  332. public boolean after(Timestamp ts) {
  333. if (super.after(ts)) {
  334. return true;
  335. } else {
  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. static final long serialVersionUID = 2745179027874758501L;
  348. }