1. /* ===========================================================
  2. * JFreeChart : a free chart library for the Java(tm) platform
  3. * ===========================================================
  4. *
  5. * (C) Copyright 2000-2004, 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. * Hour.java
  26. * ---------
  27. * (C) Copyright 2001-2004, by Object Refinery Limited.
  28. *
  29. * Original Author: David Gilbert (for Object Refinery Limited);
  30. * Contributor(s): -;
  31. *
  32. * $Id: Hour.java,v 1.3 2004/11/04 11:21:55 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 Hour(Date) constructor (DG);
  40. * 26-Feb-2002 : Changed getStart(), getMiddle() and getEnd() methods to evaluate with reference
  41. * to a particular time zone (DG);
  42. * 15-Mar-2002 : Changed API (DG);
  43. * 16-Apr-2002 : Fixed small time zone bug in constructor (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. * 13-Mar-2003 : Moved to com.jrefinery.data.time package, and implemented Serializable (DG);
  48. * 21-Oct-2003 : Added hashCode() method, and new constructor for convenience (DG);
  49. * 30-Sep-2004 : Replaced getTime().getTime() with getTimeInMillis() (DG);
  50. * 04-Nov-2004 : Reverted change of 30-Sep-2004, because it won't work for JDK 1.3 (DG);
  51. *
  52. */
  53. package org.jfree.data.time;
  54. import java.io.Serializable;
  55. import java.util.Calendar;
  56. import java.util.Date;
  57. import java.util.TimeZone;
  58. /**
  59. * Represents an hour in a specific day. This class is immutable, which is a
  60. * requirement for all {@link RegularTimePeriod} subclasses.
  61. */
  62. public class Hour extends RegularTimePeriod implements Serializable {
  63. /** Useful constant for the first hour in the day. */
  64. public static final int FIRST_HOUR_IN_DAY = 0;
  65. /** Useful constant for the last hour in the day. */
  66. public static final int LAST_HOUR_IN_DAY = 23;
  67. /** The day. */
  68. private Day day;
  69. /** The hour. */
  70. private int hour;
  71. /**
  72. * Constructs a new Hour, based on the system date/time.
  73. */
  74. public Hour() {
  75. this(new Date());
  76. }
  77. /**
  78. * Constructs a new Hour.
  79. *
  80. * @param hour the hour (in the range 0 to 23).
  81. * @param day the day (<code>null</code> not permitted).
  82. */
  83. public Hour(int hour, Day day) {
  84. if (day == null) {
  85. throw new IllegalArgumentException("Null 'day' argument.");
  86. }
  87. this.hour = hour;
  88. this.day = day;
  89. }
  90. /**
  91. * Creates a new hour.
  92. *
  93. * @param hour the hour (0-23).
  94. * @param day the day (1-31).
  95. * @param month the month (1-12).
  96. * @param year the year (1900-9999).
  97. */
  98. public Hour(int hour, int day, int month, int year) {
  99. this(hour, new Day(day, month, year));
  100. }
  101. /**
  102. * Constructs a new Hour, based on the supplied date/time.
  103. *
  104. * @param time the date-time (<code>null</code> not permitted).
  105. */
  106. public Hour(Date time) {
  107. // defer argument checking...
  108. this(time, RegularTimePeriod.DEFAULT_TIME_ZONE);
  109. }
  110. /**
  111. * Constructs a new Hour, based on the supplied date/time evaluated in the
  112. * specified time zone.
  113. *
  114. * @param time the date-time (<code>null</code> not permitted).
  115. * @param zone the time zone (<code>null</code> not permitted).
  116. */
  117. public Hour(Date time, TimeZone zone) {
  118. if (time == null) {
  119. throw new IllegalArgumentException("Null 'time' argument.");
  120. }
  121. if (zone == null) {
  122. throw new IllegalArgumentException("Null 'zone' argument.");
  123. }
  124. Calendar calendar = Calendar.getInstance(zone);
  125. calendar.setTime(time);
  126. this.hour = calendar.get(Calendar.HOUR_OF_DAY);
  127. this.day = new Day(time, zone);
  128. }
  129. /**
  130. * Returns the hour.
  131. *
  132. * @return The hour (0 <= hour <= 23).
  133. */
  134. public int getHour() {
  135. return this.hour;
  136. }
  137. /**
  138. * Returns the day in which this hour falls.
  139. *
  140. * @return The day.
  141. */
  142. public Day getDay() {
  143. return this.day;
  144. }
  145. /**
  146. * Returns the year in which this hour falls.
  147. *
  148. * @return The year.
  149. */
  150. public int getYear() {
  151. return this.day.getYear();
  152. }
  153. /**
  154. * Returns the month in which this hour falls.
  155. *
  156. * @return The month.
  157. */
  158. public int getMonth() {
  159. return this.day.getMonth();
  160. }
  161. /**
  162. * Returns the day-of-the-month in which this hour falls.
  163. *
  164. * @return The day-of-the-month.
  165. */
  166. public int getDayOfMonth() {
  167. return this.day.getDayOfMonth();
  168. }
  169. /**
  170. * Returns the hour preceding this one.
  171. *
  172. * @return The hour preceding this one.
  173. */
  174. public RegularTimePeriod previous() {
  175. Hour result;
  176. if (this.hour != FIRST_HOUR_IN_DAY) {
  177. result = new Hour(this.hour - 1, this.day);
  178. }
  179. else { // we are at the first hour in the day...
  180. Day prevDay = (Day) this.day.previous();
  181. if (prevDay != null) {
  182. result = new Hour(LAST_HOUR_IN_DAY, prevDay);
  183. }
  184. else {
  185. result = null;
  186. }
  187. }
  188. return result;
  189. }
  190. /**
  191. * Returns the hour following this one.
  192. *
  193. * @return The hour following this one.
  194. */
  195. public RegularTimePeriod next() {
  196. Hour result;
  197. if (this.hour != LAST_HOUR_IN_DAY) {
  198. result = new Hour(this.hour + 1, this.day);
  199. }
  200. else { // we are at the last hour in the day...
  201. Day nextDay = (Day) this.day.next();
  202. if (nextDay != null) {
  203. result = new Hour(FIRST_HOUR_IN_DAY, nextDay);
  204. }
  205. else {
  206. result = null;
  207. }
  208. }
  209. return result;
  210. }
  211. /**
  212. * Returns a serial index number for the hour.
  213. *
  214. * @return The serial index number.
  215. */
  216. public long getSerialIndex() {
  217. return this.day.getSerialIndex() * 24L + this.hour;
  218. }
  219. /**
  220. * Returns the first millisecond of the hour.
  221. *
  222. * @param calendar the calendar/timezone.
  223. *
  224. * @return The first millisecond.
  225. */
  226. public long getFirstMillisecond(Calendar calendar) {
  227. int year = this.day.getYear();
  228. int month = this.day.getMonth() - 1;
  229. int dom = this.day.getDayOfMonth();
  230. calendar.set(year, month, dom, this.hour, 0, 0);
  231. calendar.set(Calendar.MILLISECOND, 0);
  232. //return calendar.getTimeInMillis(); // this won't work for JDK 1.3
  233. return calendar.getTime().getTime();
  234. }
  235. /**
  236. * Returns the last millisecond of the hour.
  237. *
  238. * @param calendar the calendar/timezone.
  239. *
  240. * @return The last millisecond.
  241. */
  242. public long getLastMillisecond(Calendar calendar) {
  243. int year = this.day.getYear();
  244. int month = this.day.getMonth() - 1;
  245. int dom = this.day.getDayOfMonth();
  246. calendar.set(year, month, dom, this.hour, 59, 59);
  247. calendar.set(Calendar.MILLISECOND, 999);
  248. //return calendar.getTimeInMillis(); // this won't work for JDK 1.3
  249. return calendar.getTime().getTime();
  250. }
  251. /**
  252. * Tests the equality of this object against an arbitrary Object.
  253. * <P>
  254. * This method will return true ONLY if the object is an Hour object
  255. * representing the same hour as this instance.
  256. *
  257. * @param obj the object to compare (<code>null</code> permitted).
  258. *
  259. * @return <code>true</code> if the hour and day value of the object
  260. * is the same as this.
  261. */
  262. public boolean equals(Object obj) {
  263. if (obj == this) {
  264. return true;
  265. }
  266. if (!(obj instanceof Hour)) {
  267. return false;
  268. }
  269. Hour that = (Hour) obj;
  270. if (this.hour != that.hour) {
  271. return false;
  272. }
  273. if (!this.day.equals(that.day)) {
  274. return false;
  275. }
  276. return true;
  277. }
  278. /**
  279. * Returns a hash code for this object instance.
  280. * <p>
  281. * The approach described by Joshua Bloch in "Effective Java" has been used here:
  282. * <p>
  283. * <code>http://developer.java.sun.com/developer/Books/effectivejava/Chapter3.pdf</code>
  284. *
  285. * @return A hash code.
  286. */
  287. public int hashCode() {
  288. int result = 17;
  289. result = 37 * result + this.hour;
  290. result = 37 * result + this.day.hashCode();
  291. return result;
  292. }
  293. /**
  294. * Returns an integer indicating the order of this Hour object relative to
  295. * the specified object:
  296. *
  297. * negative == before, zero == same, positive == after.
  298. *
  299. * @param o1 the object to compare.
  300. *
  301. * @return negative == before, zero == same, positive == after.
  302. */
  303. public int compareTo(Object o1) {
  304. int result;
  305. // CASE 1 : Comparing to another Hour object
  306. // -----------------------------------------
  307. if (o1 instanceof Hour) {
  308. Hour h = (Hour) o1;
  309. result = getDay().compareTo(h.getDay());
  310. if (result == 0) {
  311. result = this.hour - h.getHour();
  312. }
  313. }
  314. // CASE 2 : Comparing to another TimePeriod object
  315. // -----------------------------------------------
  316. else if (o1 instanceof RegularTimePeriod) {
  317. // more difficult case - evaluate later...
  318. result = 0;
  319. }
  320. // CASE 3 : Comparing to a non-TimePeriod object
  321. // ---------------------------------------------
  322. else {
  323. // consider time periods to be ordered after general objects
  324. result = 1;
  325. }
  326. return result;
  327. }
  328. /**
  329. * Creates an Hour instance by parsing a string. The string is assumed to
  330. * be in the format "YYYY-MM-DD HH", perhaps with leading or trailing
  331. * whitespace.
  332. *
  333. * @param s the hour string to parse.
  334. *
  335. * @return <code>null</code> if the string is not parseable, the hour otherwise.
  336. */
  337. public static Hour parseHour(String s) {
  338. Hour result = null;
  339. s = s.trim();
  340. String daystr = s.substring(0, Math.min(10, s.length()));
  341. Day day = Day.parseDay(daystr);
  342. if (day != null) {
  343. String hourstr = s.substring(Math.min(daystr.length() + 1, s.length()),
  344. s.length());
  345. hourstr = hourstr.trim();
  346. int hour = Integer.parseInt(hourstr);
  347. // if the hour is 0 - 23 then create an hour
  348. if ((hour >= FIRST_HOUR_IN_DAY) && (hour <= LAST_HOUR_IN_DAY)) {
  349. result = new Hour(hour, day);
  350. }
  351. }
  352. return result;
  353. }
  354. }