Frames | No Frames |
1: /* =========================================================== 2: * JFreeChart : a free chart library for the Java(tm) platform 3: * =========================================================== 4: * 5: * (C) Copyright 2000-2006, 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 10: * under the terms of the GNU Lesser General Public License as published by 11: * the Free Software Foundation; either version 2.1 of the License, or 12: * (at your option) any later version. 13: * 14: * This library is distributed in the hope that it will be useful, but 15: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 16: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 17: * License for more details. 18: * 19: * You should have received a copy of the GNU Lesser General Public 20: * License along with this library; if not, write to the Free Software 21: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 22: * USA. 23: * 24: * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 25: * in the United States and other countries.] 26: * 27: * --------- 28: * Hour.java 29: * --------- 30: * (C) Copyright 2001-2006, by Object Refinery Limited. 31: * 32: * Original Author: David Gilbert (for Object Refinery Limited); 33: * Contributor(s): -; 34: * 35: * $Id: Hour.java,v 1.5.2.3 2006/10/06 14:00:15 mungady Exp $ 36: * 37: * Changes 38: * ------- 39: * 11-Oct-2001 : Version 1 (DG); 40: * 18-Dec-2001 : Changed order of parameters in constructor (DG); 41: * 19-Dec-2001 : Added a new constructor as suggested by Paul English (DG); 42: * 14-Feb-2002 : Fixed bug in Hour(Date) constructor (DG); 43: * 26-Feb-2002 : Changed getStart(), getMiddle() and getEnd() methods to 44: * evaluate with reference to a particular time zone (DG); 45: * 15-Mar-2002 : Changed API (DG); 46: * 16-Apr-2002 : Fixed small time zone bug in constructor (DG); 47: * 10-Sep-2002 : Added getSerialIndex() method (DG); 48: * 07-Oct-2002 : Fixed errors reported by Checkstyle (DG); 49: * 10-Jan-2003 : Changed base class and method names (DG); 50: * 13-Mar-2003 : Moved to com.jrefinery.data.time package, and implemented 51: * Serializable (DG); 52: * 21-Oct-2003 : Added hashCode() method, and new constructor for 53: * convenience (DG); 54: * 30-Sep-2004 : Replaced getTime().getTime() with getTimeInMillis() (DG); 55: * 04-Nov-2004 : Reverted change of 30-Sep-2004, because it won't work for 56: * JDK 1.3 (DG); 57: * ------------- JFREECHART 1.0.x --------------------------------------------- 58: * 05-Oct-2006 : Updated API docs (DG); 59: * 06-Oct-2006 : Refactored to cache first and last millisecond values (DG); 60: * 61: */ 62: 63: package org.jfree.data.time; 64: 65: import java.io.Serializable; 66: import java.util.Calendar; 67: import java.util.Date; 68: import java.util.TimeZone; 69: 70: /** 71: * Represents an hour in a specific day. This class is immutable, which is a 72: * requirement for all {@link RegularTimePeriod} subclasses. 73: */ 74: public class Hour extends RegularTimePeriod implements Serializable { 75: 76: /** For serialization. */ 77: private static final long serialVersionUID = -835471579831937652L; 78: 79: /** Useful constant for the first hour in the day. */ 80: public static final int FIRST_HOUR_IN_DAY = 0; 81: 82: /** Useful constant for the last hour in the day. */ 83: public static final int LAST_HOUR_IN_DAY = 23; 84: 85: /** The day. */ 86: private Day day; 87: 88: /** The hour. */ 89: private byte hour; 90: 91: /** The first millisecond. */ 92: private long firstMillisecond; 93: 94: /** The last millisecond. */ 95: private long lastMillisecond; 96: 97: /** 98: * Constructs a new Hour, based on the system date/time. 99: */ 100: public Hour() { 101: this(new Date()); 102: } 103: 104: /** 105: * Constructs a new Hour. 106: * 107: * @param hour the hour (in the range 0 to 23). 108: * @param day the day (<code>null</code> not permitted). 109: */ 110: public Hour(int hour, Day day) { 111: if (day == null) { 112: throw new IllegalArgumentException("Null 'day' argument."); 113: } 114: this.hour = (byte) hour; 115: this.day = day; 116: peg(Calendar.getInstance()); 117: } 118: 119: /** 120: * Creates a new hour. 121: * 122: * @param hour the hour (0-23). 123: * @param day the day (1-31). 124: * @param month the month (1-12). 125: * @param year the year (1900-9999). 126: */ 127: public Hour(int hour, int day, int month, int year) { 128: this(hour, new Day(day, month, year)); 129: } 130: 131: /** 132: * Constructs a new Hour, based on the supplied date/time. 133: * 134: * @param time the date-time (<code>null</code> not permitted). 135: */ 136: public Hour(Date time) { 137: // defer argument checking... 138: this(time, RegularTimePeriod.DEFAULT_TIME_ZONE); 139: } 140: 141: /** 142: * Constructs a new Hour, based on the supplied date/time evaluated in the 143: * specified time zone. 144: * 145: * @param time the date-time (<code>null</code> not permitted). 146: * @param zone the time zone (<code>null</code> not permitted). 147: */ 148: public Hour(Date time, TimeZone zone) { 149: if (time == null) { 150: throw new IllegalArgumentException("Null 'time' argument."); 151: } 152: if (zone == null) { 153: throw new IllegalArgumentException("Null 'zone' argument."); 154: } 155: Calendar calendar = Calendar.getInstance(zone); 156: calendar.setTime(time); 157: this.hour = (byte) calendar.get(Calendar.HOUR_OF_DAY); 158: this.day = new Day(time, zone); 159: peg(Calendar.getInstance()); 160: } 161: 162: /** 163: * Returns the hour. 164: * 165: * @return The hour (0 <= hour <= 23). 166: */ 167: public int getHour() { 168: return this.hour; 169: } 170: 171: /** 172: * Returns the day in which this hour falls. 173: * 174: * @return The day. 175: */ 176: public Day getDay() { 177: return this.day; 178: } 179: 180: /** 181: * Returns the year in which this hour falls. 182: * 183: * @return The year. 184: */ 185: public int getYear() { 186: return this.day.getYear(); 187: } 188: 189: /** 190: * Returns the month in which this hour falls. 191: * 192: * @return The month. 193: */ 194: public int getMonth() { 195: return this.day.getMonth(); 196: } 197: 198: /** 199: * Returns the day-of-the-month in which this hour falls. 200: * 201: * @return The day-of-the-month. 202: */ 203: public int getDayOfMonth() { 204: return this.day.getDayOfMonth(); 205: } 206: 207: /** 208: * Returns the first millisecond of the hour. This will be determined 209: * relative to the time zone specified in the constructor, or in the 210: * calendar instance passed in the most recent call to the 211: * {@link #peg(Calendar)} method. 212: * 213: * @return The first millisecond of the hour. 214: * 215: * @see #getLastMillisecond() 216: */ 217: public long getFirstMillisecond() { 218: return this.firstMillisecond; 219: } 220: 221: /** 222: * Returns the last millisecond of the hour. This will be 223: * determined relative to the time zone specified in the constructor, or 224: * in the calendar instance passed in the most recent call to the 225: * {@link #peg(Calendar)} method. 226: * 227: * @return The last millisecond of the hour. 228: * 229: * @see #getFirstMillisecond() 230: */ 231: public long getLastMillisecond() { 232: return this.lastMillisecond; 233: } 234: 235: /** 236: * Recalculates the start date/time and end date/time for this time period 237: * relative to the supplied calendar (which incorporates a time zone). 238: * 239: * @param calendar the calendar (<code>null</code> not permitted). 240: * 241: * @since 1.0.3 242: */ 243: public void peg(Calendar calendar) { 244: this.firstMillisecond = getFirstMillisecond(calendar); 245: this.lastMillisecond = getLastMillisecond(calendar); 246: } 247: 248: /** 249: * Returns the hour preceding this one. 250: * 251: * @return The hour preceding this one. 252: */ 253: public RegularTimePeriod previous() { 254: 255: Hour result; 256: if (this.hour != FIRST_HOUR_IN_DAY) { 257: result = new Hour(this.hour - 1, this.day); 258: } 259: else { // we are at the first hour in the day... 260: Day prevDay = (Day) this.day.previous(); 261: if (prevDay != null) { 262: result = new Hour(LAST_HOUR_IN_DAY, prevDay); 263: } 264: else { 265: result = null; 266: } 267: } 268: return result; 269: 270: } 271: 272: /** 273: * Returns the hour following this one. 274: * 275: * @return The hour following this one. 276: */ 277: public RegularTimePeriod next() { 278: 279: Hour result; 280: if (this.hour != LAST_HOUR_IN_DAY) { 281: result = new Hour(this.hour + 1, this.day); 282: } 283: else { // we are at the last hour in the day... 284: Day nextDay = (Day) this.day.next(); 285: if (nextDay != null) { 286: result = new Hour(FIRST_HOUR_IN_DAY, nextDay); 287: } 288: else { 289: result = null; 290: } 291: } 292: return result; 293: 294: } 295: 296: /** 297: * Returns a serial index number for the hour. 298: * 299: * @return The serial index number. 300: */ 301: public long getSerialIndex() { 302: return this.day.getSerialIndex() * 24L + this.hour; 303: } 304: 305: /** 306: * Returns the first millisecond of the hour. 307: * 308: * @param calendar the calendar/timezone (<code>null</code> not permitted). 309: * 310: * @return The first millisecond. 311: * 312: * @throws NullPointerException if <code>calendar</code> is 313: * <code>null</code>. 314: */ 315: public long getFirstMillisecond(Calendar calendar) { 316: int year = this.day.getYear(); 317: int month = this.day.getMonth() - 1; 318: int dom = this.day.getDayOfMonth(); 319: calendar.set(year, month, dom, this.hour, 0, 0); 320: calendar.set(Calendar.MILLISECOND, 0); 321: //return calendar.getTimeInMillis(); // this won't work for JDK 1.3 322: return calendar.getTime().getTime(); 323: } 324: 325: /** 326: * Returns the last millisecond of the hour. 327: * 328: * @param calendar the calendar/timezone (<code>null</code> not permitted). 329: * 330: * @return The last millisecond. 331: * 332: * @throws NullPointerException if <code>calendar</code> is 333: * <code>null</code>. 334: */ 335: public long getLastMillisecond(Calendar calendar) { 336: int year = this.day.getYear(); 337: int month = this.day.getMonth() - 1; 338: int dom = this.day.getDayOfMonth(); 339: calendar.set(year, month, dom, this.hour, 59, 59); 340: calendar.set(Calendar.MILLISECOND, 999); 341: //return calendar.getTimeInMillis(); // this won't work for JDK 1.3 342: return calendar.getTime().getTime(); 343: } 344: 345: /** 346: * Tests the equality of this object against an arbitrary Object. 347: * <P> 348: * This method will return true ONLY if the object is an Hour object 349: * representing the same hour as this instance. 350: * 351: * @param obj the object to compare (<code>null</code> permitted). 352: * 353: * @return <code>true</code> if the hour and day value of the object 354: * is the same as this. 355: */ 356: public boolean equals(Object obj) { 357: if (obj == this) { 358: return true; 359: } 360: if (!(obj instanceof Hour)) { 361: return false; 362: } 363: Hour that = (Hour) obj; 364: if (this.hour != that.hour) { 365: return false; 366: } 367: if (!this.day.equals(that.day)) { 368: return false; 369: } 370: return true; 371: } 372: 373: /** 374: * Returns a hash code for this object instance. The approach described by 375: * Joshua Bloch in "Effective Java" has been used here: 376: * <p> 377: * <code>http://developer.java.sun.com/developer/Books/effectivejava 378: * /Chapter3.pdf</code> 379: * 380: * @return A hash code. 381: */ 382: public int hashCode() { 383: int result = 17; 384: result = 37 * result + this.hour; 385: result = 37 * result + this.day.hashCode(); 386: return result; 387: } 388: 389: /** 390: * Returns an integer indicating the order of this Hour object relative to 391: * the specified object: 392: * 393: * negative == before, zero == same, positive == after. 394: * 395: * @param o1 the object to compare. 396: * 397: * @return negative == before, zero == same, positive == after. 398: */ 399: public int compareTo(Object o1) { 400: 401: int result; 402: 403: // CASE 1 : Comparing to another Hour object 404: // ----------------------------------------- 405: if (o1 instanceof Hour) { 406: Hour h = (Hour) o1; 407: result = getDay().compareTo(h.getDay()); 408: if (result == 0) { 409: result = this.hour - h.getHour(); 410: } 411: } 412: 413: // CASE 2 : Comparing to another TimePeriod object 414: // ----------------------------------------------- 415: else if (o1 instanceof RegularTimePeriod) { 416: // more difficult case - evaluate later... 417: result = 0; 418: } 419: 420: // CASE 3 : Comparing to a non-TimePeriod object 421: // --------------------------------------------- 422: else { 423: // consider time periods to be ordered after general objects 424: result = 1; 425: } 426: 427: return result; 428: 429: } 430: 431: /** 432: * Creates an Hour instance by parsing a string. The string is assumed to 433: * be in the format "YYYY-MM-DD HH", perhaps with leading or trailing 434: * whitespace. 435: * 436: * @param s the hour string to parse. 437: * 438: * @return <code>null</code> if the string is not parseable, the hour 439: * otherwise. 440: */ 441: public static Hour parseHour(String s) { 442: 443: Hour result = null; 444: s = s.trim(); 445: 446: String daystr = s.substring(0, Math.min(10, s.length())); 447: Day day = Day.parseDay(daystr); 448: if (day != null) { 449: String hourstr = s.substring( 450: Math.min(daystr.length() + 1, s.length()), s.length() 451: ); 452: hourstr = hourstr.trim(); 453: int hour = Integer.parseInt(hourstr); 454: // if the hour is 0 - 23 then create an hour 455: if ((hour >= FIRST_HOUR_IN_DAY) && (hour <= LAST_HOUR_IN_DAY)) { 456: result = new Hour(hour, day); 457: } 458: } 459: 460: return result; 461: 462: } 463: 464: }