Source for org.jfree.data.time.Hour

   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 
  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-2004, 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.1 2005/10/25 21:35:24 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:  *
  58:  */
  59: 
  60: package org.jfree.data.time;
  61: 
  62: import java.io.Serializable;
  63: import java.util.Calendar;
  64: import java.util.Date;
  65: import java.util.TimeZone;
  66: 
  67: /**
  68:  * Represents an hour in a specific day.  This class is immutable, which is a 
  69:  * requirement for all {@link RegularTimePeriod} subclasses.
  70:  */
  71: public class Hour extends RegularTimePeriod implements Serializable {
  72: 
  73:     /** For serialization. */
  74:     private static final long serialVersionUID = -835471579831937652L;
  75:     
  76:     /** Useful constant for the first hour in the day. */
  77:     public static final int FIRST_HOUR_IN_DAY = 0;
  78: 
  79:     /** Useful constant for the last hour in the day. */
  80:     public static final int LAST_HOUR_IN_DAY = 23;
  81: 
  82:     /** The day. */
  83:     private Day day;
  84: 
  85:     /** The hour. */
  86:     private int hour;
  87: 
  88:     /**
  89:      * Constructs a new Hour, based on the system date/time.
  90:      */
  91:     public Hour() {
  92:         this(new Date());
  93:     }
  94: 
  95:     /**
  96:      * Constructs a new Hour.
  97:      *
  98:      * @param hour  the hour (in the range 0 to 23).
  99:      * @param day  the day (<code>null</code> not permitted).
 100:      */
 101:     public Hour(int hour, Day day) {
 102:         if (day == null) {
 103:             throw new IllegalArgumentException("Null 'day' argument.");
 104:         }
 105:         this.hour = hour;
 106:         this.day = day;
 107:     }
 108: 
 109:     /**
 110:      * Creates a new hour.
 111:      * 
 112:      * @param hour  the hour (0-23).
 113:      * @param day  the day (1-31).
 114:      * @param month  the month (1-12).
 115:      * @param year  the year (1900-9999).
 116:      */
 117:     public Hour(int hour, int day, int month, int year) {
 118:         this(hour, new Day(day, month, year));
 119:     }
 120:     
 121:     /**
 122:      * Constructs a new Hour, based on the supplied date/time.
 123:      *
 124:      * @param time  the date-time (<code>null</code> not permitted).
 125:      */
 126:     public Hour(Date time) {
 127:         // defer argument checking...
 128:         this(time, RegularTimePeriod.DEFAULT_TIME_ZONE);
 129:     }
 130: 
 131:     /**
 132:      * Constructs a new Hour, based on the supplied date/time evaluated in the
 133:      * specified time zone.
 134:      *
 135:      * @param time  the date-time (<code>null</code> not permitted).
 136:      * @param zone  the time zone (<code>null</code> not permitted).
 137:      */
 138:     public Hour(Date time, TimeZone zone) {
 139:         if (time == null) {
 140:             throw new IllegalArgumentException("Null 'time' argument.");
 141:         }
 142:         if (zone == null) {
 143:             throw new IllegalArgumentException("Null 'zone' argument.");
 144:         }
 145:         Calendar calendar = Calendar.getInstance(zone);
 146:         calendar.setTime(time);
 147:         this.hour = calendar.get(Calendar.HOUR_OF_DAY);
 148:         this.day = new Day(time, zone);
 149:     }
 150: 
 151:     /**
 152:      * Returns the hour.
 153:      *
 154:      * @return The hour (0 <= hour <= 23).
 155:      */
 156:     public int getHour() {
 157:         return this.hour;
 158:     }
 159: 
 160:     /**
 161:      * Returns the day in which this hour falls.
 162:      *
 163:      * @return The day.
 164:      */
 165:     public Day getDay() {
 166:         return this.day;
 167:     }
 168: 
 169:     /**
 170:      * Returns the year in which this hour falls.
 171:      *
 172:      * @return The year.
 173:      */
 174:     public int getYear() {
 175:         return this.day.getYear();
 176:     }
 177: 
 178:     /**
 179:      * Returns the month in which this hour falls.
 180:      *
 181:      * @return The month.
 182:      */
 183:     public int getMonth() {
 184:         return this.day.getMonth();
 185:     }
 186: 
 187:     /**
 188:      * Returns the day-of-the-month in which this hour falls.
 189:      *
 190:      * @return The day-of-the-month.
 191:      */
 192:     public int getDayOfMonth() {
 193:         return this.day.getDayOfMonth();
 194:     }
 195: 
 196:     /**
 197:      * Returns the hour preceding this one.
 198:      *
 199:      * @return The hour preceding this one.
 200:      */
 201:     public RegularTimePeriod previous() {
 202: 
 203:         Hour result;
 204:         if (this.hour != FIRST_HOUR_IN_DAY) {
 205:             result = new Hour(this.hour - 1, this.day);
 206:         }
 207:         else { // we are at the first hour in the day...
 208:             Day prevDay = (Day) this.day.previous();
 209:             if (prevDay != null) {
 210:                 result = new Hour(LAST_HOUR_IN_DAY, prevDay);
 211:             }
 212:             else {
 213:                 result = null;
 214:             }
 215:         }
 216:         return result;
 217: 
 218:     }
 219: 
 220:     /**
 221:      * Returns the hour following this one.
 222:      *
 223:      * @return The hour following this one.
 224:      */
 225:     public RegularTimePeriod next() {
 226: 
 227:         Hour result;
 228:         if (this.hour != LAST_HOUR_IN_DAY) {
 229:             result = new Hour(this.hour + 1, this.day);
 230:         }
 231:         else { // we are at the last hour in the day...
 232:             Day nextDay = (Day) this.day.next();
 233:             if (nextDay != null) {
 234:                 result = new Hour(FIRST_HOUR_IN_DAY, nextDay);
 235:             }
 236:             else {
 237:                 result = null;
 238:             }
 239:         }
 240:         return result;
 241: 
 242:     }
 243: 
 244:     /**
 245:      * Returns a serial index number for the hour.
 246:      *
 247:      * @return The serial index number.
 248:      */
 249:     public long getSerialIndex() {
 250:         return this.day.getSerialIndex() * 24L + this.hour;
 251:     }
 252: 
 253:     /**
 254:      * Returns the first millisecond of the hour.
 255:      *
 256:      * @param calendar  the calendar/timezone.
 257:      *
 258:      * @return The first millisecond.
 259:      */
 260:     public long getFirstMillisecond(Calendar calendar) {
 261: 
 262:         int year = this.day.getYear();
 263:         int month = this.day.getMonth() - 1;
 264:         int dom = this.day.getDayOfMonth();
 265: 
 266:         calendar.set(year, month, dom, this.hour, 0, 0);
 267:         calendar.set(Calendar.MILLISECOND, 0);
 268: 
 269:         //return calendar.getTimeInMillis();  // this won't work for JDK 1.3
 270:         return calendar.getTime().getTime();
 271: 
 272:     }
 273: 
 274:     /**
 275:      * Returns the last millisecond of the hour.
 276:      *
 277:      * @param calendar  the calendar/timezone.
 278:      *
 279:      * @return The last millisecond.
 280:      */
 281:     public long getLastMillisecond(Calendar calendar) {
 282: 
 283:         int year = this.day.getYear();
 284:         int month = this.day.getMonth() - 1;
 285:         int dom = this.day.getDayOfMonth();
 286: 
 287:         calendar.set(year, month, dom, this.hour, 59, 59);
 288:         calendar.set(Calendar.MILLISECOND, 999);
 289: 
 290:         //return calendar.getTimeInMillis();  // this won't work for JDK 1.3
 291:         return calendar.getTime().getTime();
 292: 
 293:     }
 294: 
 295:     /**
 296:      * Tests the equality of this object against an arbitrary Object.
 297:      * <P>
 298:      * This method will return true ONLY if the object is an Hour object
 299:      * representing the same hour as this instance.
 300:      *
 301:      * @param obj  the object to compare (<code>null</code> permitted).
 302:      *
 303:      * @return <code>true</code> if the hour and day value of the object
 304:      *      is the same as this.
 305:      */
 306:     public boolean equals(Object obj) {
 307:         if (obj == this) {
 308:             return true;
 309:         }
 310:         if (!(obj instanceof Hour)) {
 311:             return false;
 312:         }
 313:         Hour that = (Hour) obj;
 314:         if (this.hour != that.hour) {
 315:             return false;
 316:         }
 317:         if (!this.day.equals(that.day)) {
 318:             return false;
 319:         }
 320:         return true;
 321:     }
 322: 
 323:     /**
 324:      * Returns a hash code for this object instance.  The approach described by 
 325:      * Joshua Bloch in "Effective Java" has been used here:
 326:      * <p>
 327:      * <code>http://developer.java.sun.com/developer/Books/effectivejava
 328:      * /Chapter3.pdf</code>
 329:      * 
 330:      * @return A hash code.
 331:      */
 332:     public int hashCode() {
 333:         int result = 17;
 334:         result = 37 * result + this.hour;
 335:         result = 37 * result + this.day.hashCode();
 336:         return result;
 337:     }
 338: 
 339:     /**
 340:      * Returns an integer indicating the order of this Hour object relative to
 341:      * the specified object:
 342:      *
 343:      * negative == before, zero == same, positive == after.
 344:      *
 345:      * @param o1  the object to compare.
 346:      *
 347:      * @return negative == before, zero == same, positive == after.
 348:      */
 349:     public int compareTo(Object o1) {
 350: 
 351:         int result;
 352: 
 353:         // CASE 1 : Comparing to another Hour object
 354:         // -----------------------------------------
 355:         if (o1 instanceof Hour) {
 356:             Hour h = (Hour) o1;
 357:             result = getDay().compareTo(h.getDay());
 358:             if (result == 0) {
 359:                 result = this.hour - h.getHour();
 360:             }
 361:         }
 362: 
 363:         // CASE 2 : Comparing to another TimePeriod object
 364:         // -----------------------------------------------
 365:         else if (o1 instanceof RegularTimePeriod) {
 366:             // more difficult case - evaluate later...
 367:             result = 0;
 368:         }
 369: 
 370:         // CASE 3 : Comparing to a non-TimePeriod object
 371:         // ---------------------------------------------
 372:         else {
 373:             // consider time periods to be ordered after general objects
 374:             result = 1;
 375:         }
 376: 
 377:         return result;
 378: 
 379:     }
 380: 
 381:     /**
 382:      * Creates an Hour instance by parsing a string.  The string is assumed to
 383:      * be in the format "YYYY-MM-DD HH", perhaps with leading or trailing
 384:      * whitespace.
 385:      *
 386:      * @param s  the hour string to parse.
 387:      *
 388:      * @return <code>null</code> if the string is not parseable, the hour 
 389:      *         otherwise.
 390:      */
 391:     public static Hour parseHour(String s) {
 392: 
 393:         Hour result = null;
 394:         s = s.trim();
 395: 
 396:         String daystr = s.substring(0, Math.min(10, s.length()));
 397:         Day day = Day.parseDay(daystr);
 398:         if (day != null) {
 399:             String hourstr = s.substring(
 400:                 Math.min(daystr.length() + 1, s.length()), s.length()
 401:             );
 402:             hourstr = hourstr.trim();
 403:             int hour = Integer.parseInt(hourstr);
 404:             // if the hour is 0 - 23 then create an hour
 405:             if ((hour >= FIRST_HOUR_IN_DAY) && (hour <= LAST_HOUR_IN_DAY)) {
 406:                 result = new Hour(hour, day);
 407:             }
 408:         }
 409: 
 410:         return result;
 411: 
 412:     }
 413: 
 414: }