1. /* ===========================================================
  2. * JFreeChart : a free chart library for the Java(tm) platform
  3. * ===========================================================
  4. *
  5. * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
  6. *
  7. * Project Info: http://www.jfree.org/jfreechart/index.html
  8. *
  9. * This library is free software; you can redistribute it and/or modify it under the terms
  10. * of the GNU Lesser General Public License as published by the Free Software Foundation;
  11. * either version 2.1 of the License, or (at your option) any later version.
  12. *
  13. * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
  14. * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  15. * See the GNU Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public License along with this
  18. * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  19. * Boston, MA 02111-1307, USA.
  20. *
  21. * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
  22. * in the United States and other countries.]
  23. *
  24. * -----------
  25. * Second.java
  26. * -----------
  27. * (C) Copyright 2001-2005, by Object Refinery Limited.
  28. *
  29. * Original Author: David Gilbert (for Object Refinery Limited);
  30. * Contributor(s): -;
  31. *
  32. * $Id: Second.java,v 1.3 2005/01/14 17:29:48 mungady Exp $
  33. *
  34. * Changes
  35. * -------
  36. * 11-Oct-2001 : Version 1 (DG);
  37. * 18-Dec-2001 : Changed order of parameters in constructor (DG);
  38. * 19-Dec-2001 : Added a new constructor as suggested by Paul English (DG);
  39. * 14-Feb-2002 : Fixed bug in Second(Date) constructor, and changed start of range to zero from
  40. * one (DG);
  41. * 26-Feb-2002 : Changed getStart(), getMiddle() and getEnd() methods to evaluate with reference
  42. * to a particular time zone (DG);
  43. * 13-Mar-2002 : Added parseSecond() method (DG);
  44. * 10-Sep-2002 : Added getSerialIndex() method (DG);
  45. * 07-Oct-2002 : Fixed errors reported by Checkstyle (DG);
  46. * 10-Jan-2003 : Changed base class and method names (DG);
  47. * 05-Mar-2003 : Fixed bug in getLastMillisecond(...) picked up in JUnit tests (DG);
  48. * 13-Mar-2003 : Moved to com.jrefinery.data.time package and implemented Serializable (DG);
  49. * 21-Oct-2003 : Added hashCode() method (DG);
  50. *
  51. */
  52. package org.jfree.data.time;
  53. import java.io.Serializable;
  54. import java.util.Calendar;
  55. import java.util.Date;
  56. import java.util.TimeZone;
  57. /**
  58. * Represents a second in a particular day.
  59. * <P>
  60. * This class is immutable, which is a requirement for all {@link RegularTimePeriod} subclasses.
  61. */
  62. public class Second extends RegularTimePeriod implements Serializable {
  63. /** Useful constant for the first second in a minute. */
  64. public static final int FIRST_SECOND_IN_MINUTE = 0;
  65. /** Useful constant for the last second in a minute. */
  66. public static final int LAST_SECOND_IN_MINUTE = 59;
  67. /** The minute. */
  68. private Minute minute;
  69. /** The second. */
  70. private int second;
  71. /**
  72. * Constructs a new Second, based on the system date/time.
  73. */
  74. public Second() {
  75. this(new Date());
  76. }
  77. /**
  78. * Constructs a new Second.
  79. *
  80. * @param second the second (0 to 24*60*60-1).
  81. * @param minute the minute (<code>null</code> not permitted).
  82. */
  83. public Second(int second, Minute minute) {
  84. if (minute == null) {
  85. throw new IllegalArgumentException("Null 'minute' argument.");
  86. }
  87. this.minute = minute;
  88. this.second = second;
  89. }
  90. /**
  91. * Creates a new second.
  92. *
  93. * @param second the second (0-59).
  94. * @param minute the minute (0-59).
  95. * @param hour the hour (0-23).
  96. * @param day the day (1-31).
  97. * @param month the month (1-12).
  98. * @param year the year (1900-9999).
  99. */
  100. public Second(int second, int minute, int hour,
  101. int day, int month, int year) {
  102. this(second, new Minute(minute, hour, day, month, year));
  103. }
  104. /**
  105. * Constructs a second.
  106. *
  107. * @param time the time.
  108. */
  109. public Second(Date time) {
  110. this(time, RegularTimePeriod.DEFAULT_TIME_ZONE);
  111. }
  112. /**
  113. * Creates a new second based on the supplied time and time zone.
  114. *
  115. * @param time the instant in time.
  116. * @param zone the time zone.
  117. */
  118. public Second(Date time, final TimeZone zone) {
  119. this.minute = new Minute(time, zone);
  120. Calendar calendar = Calendar.getInstance(zone);
  121. calendar.setTime(time);
  122. this.second = calendar.get(Calendar.SECOND);
  123. }
  124. /**
  125. * Returns the second within the minute.
  126. *
  127. * @return The second (0 - 59).
  128. */
  129. public int getSecond() {
  130. return this.second;
  131. }
  132. /**
  133. * Returns the minute.
  134. *
  135. * @return The minute (never <code>null</code>).
  136. */
  137. public Minute getMinute() {
  138. return this.minute;
  139. }
  140. /**
  141. * Returns the second preceding this one.
  142. *
  143. * @return The second preceding this one.
  144. */
  145. public RegularTimePeriod previous() {
  146. Second result = null;
  147. if (this.second != FIRST_SECOND_IN_MINUTE) {
  148. result = new Second(this.second - 1, this.minute);
  149. }
  150. else {
  151. Minute previous = (Minute) this.minute.previous();
  152. if (previous != null) {
  153. result = new Second(LAST_SECOND_IN_MINUTE, previous);
  154. }
  155. }
  156. return result;
  157. }
  158. /**
  159. * Returns the second following this one.
  160. *
  161. * @return The second following this one.
  162. */
  163. public RegularTimePeriod next() {
  164. Second result = null;
  165. if (this.second != LAST_SECOND_IN_MINUTE) {
  166. result = new Second(this.second + 1, this.minute);
  167. }
  168. else {
  169. Minute next = (Minute) this.minute.next();
  170. if (next != null) {
  171. result = new Second(FIRST_SECOND_IN_MINUTE, next);
  172. }
  173. }
  174. return result;
  175. }
  176. /**
  177. * Returns a serial index number for the minute.
  178. *
  179. * @return The serial index number.
  180. */
  181. public long getSerialIndex() {
  182. return this.minute.getSerialIndex() * 60L + this.second;
  183. }
  184. /**
  185. * Returns the first millisecond of the minute.
  186. *
  187. * @param calendar the calendar/timezone.
  188. *
  189. * @return The first millisecond.
  190. */
  191. public long getFirstMillisecond(Calendar calendar) {
  192. return this.minute.getFirstMillisecond(calendar) + this.second * 1000L;
  193. }
  194. /**
  195. * Returns the last millisecond of the second.
  196. *
  197. * @param calendar the calendar/timezone.
  198. *
  199. * @return The last millisecond.
  200. */
  201. public long getLastMillisecond(Calendar calendar) {
  202. return this.minute.getFirstMillisecond(calendar) + this.second * 1000L + 999L;
  203. }
  204. /**
  205. * Tests the equality of this object against an arbitrary Object.
  206. * <P>
  207. * This method will return true ONLY if the object is a Second object
  208. * representing the same second as this instance.
  209. *
  210. * @param obj the object to compare.
  211. *
  212. * @return <code>true</code> if second and minute of this and the object are the same.
  213. */
  214. public boolean equals(Object obj) {
  215. if (obj instanceof Second) {
  216. Second s = (Second) obj;
  217. return ((this.second == s.getSecond()) && (this.minute.equals(s.getMinute())));
  218. }
  219. else {
  220. return false;
  221. }
  222. }
  223. /**
  224. * Returns a hash code for this object instance.
  225. * <p>
  226. * The approach described by Joshua Bloch in "Effective Java" has been used here:
  227. * <p>
  228. * <code>http://developer.java.sun.com/developer/Books/effectivejava/Chapter3.pdf</code>
  229. *
  230. * @return A hash code.
  231. */
  232. public int hashCode() {
  233. int result = 17;
  234. result = 37 * result + this.second;
  235. result = 37 * result + this.minute.hashCode();
  236. return result;
  237. }
  238. /**
  239. * Returns an integer indicating the order of this Second object relative
  240. * to the specified
  241. * object: negative == before, zero == same, positive == after.
  242. *
  243. * @param o1 the object to compare.
  244. *
  245. * @return negative == before, zero == same, positive == after.
  246. */
  247. public int compareTo(Object o1) {
  248. int result;
  249. // CASE 1 : Comparing to another Second object
  250. // -------------------------------------------
  251. if (o1 instanceof Second) {
  252. Second s = (Second) o1;
  253. result = this.minute.compareTo(s.minute);
  254. if (result == 0) {
  255. result = this.second - s.second;
  256. }
  257. }
  258. // CASE 2 : Comparing to another TimePeriod object
  259. // -----------------------------------------------
  260. else if (o1 instanceof RegularTimePeriod) {
  261. // more difficult case - evaluate later...
  262. result = 0;
  263. }
  264. // CASE 3 : Comparing to a non-TimePeriod object
  265. // ---------------------------------------------
  266. else {
  267. // consider time periods to be ordered after general objects
  268. result = 1;
  269. }
  270. return result;
  271. }
  272. /**
  273. * Creates a new instance by parsing a string. The string is assumed to
  274. * be in the format "YYYY-MM-DD HH:MM:SS", perhaps with leading or trailing
  275. * whitespace.
  276. *
  277. * @param s the string to parse.
  278. *
  279. * @return The second, or <code>null</code> if the string is not parseable.
  280. */
  281. public static Second parseSecond(String s) {
  282. Second result = null;
  283. s = s.trim();
  284. String daystr = s.substring(0, Math.min(10, s.length()));
  285. Day day = Day.parseDay(daystr);
  286. if (day != null) {
  287. String hmsstr = s.substring(Math.min(daystr.length() + 1, s.length()),
  288. s.length());
  289. hmsstr = hmsstr.trim();
  290. int l = hmsstr.length();
  291. String hourstr = hmsstr.substring(0, Math.min(2, l));
  292. String minstr = hmsstr.substring(Math.min(3, l), Math.min(5, l));
  293. String secstr = hmsstr.substring(Math.min(6, l), Math.min(8, l));
  294. int hour = Integer.parseInt(hourstr);
  295. if ((hour >= 0) && (hour <= 23)) {
  296. int minute = Integer.parseInt(minstr);
  297. if ((minute >= 0) && (minute <= 59)) {
  298. Minute m = new Minute(minute, new Hour(hour, day));
  299. int second = Integer.parseInt(secstr);
  300. if ((second >= 0) && (second <= 59)) {
  301. result = new Second(second, m);
  302. }
  303. }
  304. }
  305. }
  306. return result;
  307. }
  308. }