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