Source for org.jfree.data.time.Millisecond

   1: /* ===========================================================
   2:  * JFreeChart : a free chart library for the Java(tm) platform
   3:  * ===========================================================
   4:  *
   5:  * (C) Copyright 2000-2008, 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:  * Millisecond.java
  29:  * ----------------
  30:  * (C) Copyright 2001-2008, by Object Refinery Limited.
  31:  *
  32:  * Original Author:  David Gilbert (for Object Refinery Limited);
  33:  * Contributor(s):   -;
  34:  *
  35:  * Changes
  36:  * -------
  37:  * 11-Oct-2001 : Version 1 (DG);
  38:  * 19-Dec-2001 : Added new constructors as suggested by Paul English (DG);
  39:  * 26-Feb-2002 : Added new getStart() and getEnd() methods (DG);
  40:  * 29-Mar-2002 : Fixed bug in getStart(), getEnd() and compareTo() methods (DG);
  41:  * 10-Sep-2002 : Added getSerialIndex() method (DG);
  42:  * 07-Oct-2002 : Fixed errors reported by Checkstyle (DG);
  43:  * 10-Jan-2003 : Changed base class and method names (DG);
  44:  * 13-Mar-2003 : Moved to com.jrefinery.data.time package and implemented
  45:  *               Serializable (DG);
  46:  * 21-Oct-2003 : Added hashCode() method (DG);
  47:  * ------------- JFREECHART 1.0.x ---------------------------------------------
  48:  * 05-Oct-2006 : Updated API docs (DG);
  49:  * 06-Oct-2006 : Refactored to cache first and last millisecond values (DG);
  50:  * 04-Apr-2007 : In Millisecond(Date, TimeZone), peg milliseconds to the
  51:  *               specified zone (DG);
  52:  * 06-Jun-2008 : Added handling for general RegularTimePeriod in compareTo()
  53:  *               method:
  54:  *               see http://www.jfree.org/phpBB2/viewtopic.php?t=24805 (DG);
  55:  *
  56:  */
  57: 
  58: package org.jfree.data.time;
  59: 
  60: import java.io.Serializable;
  61: import java.util.Calendar;
  62: import java.util.Date;
  63: import java.util.TimeZone;
  64: 
  65: /**
  66:  * Represents a millisecond.  This class is immutable, which is a requirement
  67:  * for all {@link RegularTimePeriod} subclasses.
  68:  */
  69: public class Millisecond extends RegularTimePeriod implements Serializable {
  70: 
  71:     /** For serialization. */
  72:     static final long serialVersionUID = -5316836467277638485L;
  73: 
  74:     /** A constant for the first millisecond in a second. */
  75:     public static final int FIRST_MILLISECOND_IN_SECOND = 0;
  76: 
  77:     /** A constant for the last millisecond in a second. */
  78:     public static final int LAST_MILLISECOND_IN_SECOND = 999;
  79: 
  80:     /** The day. */
  81:     private Day day;
  82: 
  83:     /** The hour in the day. */
  84:     private byte hour;
  85: 
  86:     /** The minute. */
  87:     private byte minute;
  88: 
  89:     /** The second. */
  90:     private byte second;
  91: 
  92:     /** The millisecond. */
  93:     private int millisecond;
  94: 
  95:     /**
  96:      * The pegged millisecond.
  97:      */
  98:     private long firstMillisecond;
  99: 
 100:     /**
 101:      * Constructs a millisecond based on the current system time.
 102:      */
 103:     public Millisecond() {
 104:         this(new Date());
 105:     }
 106: 
 107:     /**
 108:      * Constructs a millisecond.
 109:      *
 110:      * @param millisecond  the millisecond (0-999).
 111:      * @param second  the second.
 112:      */
 113:     public Millisecond(int millisecond, Second second) {
 114:         this.millisecond = millisecond;
 115:         this.second = (byte) second.getSecond();
 116:         this.minute = (byte) second.getMinute().getMinute();
 117:         this.hour = (byte) second.getMinute().getHourValue();
 118:         this.day = second.getMinute().getDay();
 119:         peg(Calendar.getInstance());
 120:     }
 121: 
 122:     /**
 123:      * Creates a new millisecond.
 124:      *
 125:      * @param millisecond  the millisecond (0-999).
 126:      * @param second  the second (0-59).
 127:      * @param minute  the minute (0-59).
 128:      * @param hour  the hour (0-23).
 129:      * @param day  the day (1-31).
 130:      * @param month  the month (1-12).
 131:      * @param year  the year (1900-9999).
 132:      */
 133:     public Millisecond(int millisecond, int second, int minute, int hour,
 134:                        int day, int month, int year) {
 135: 
 136:         this(millisecond, new Second(second, minute, hour, day, month, year));
 137: 
 138:     }
 139: 
 140:     /**
 141:      * Constructs a millisecond.
 142:      *
 143:      * @param time  the time.
 144:      */
 145:     public Millisecond(Date time) {
 146:         this(time, RegularTimePeriod.DEFAULT_TIME_ZONE);
 147:     }
 148: 
 149:     /**
 150:      * Creates a millisecond.
 151:      *
 152:      * @param time  the instant in time.
 153:      * @param zone  the time zone.
 154:      */
 155:     public Millisecond(Date time, TimeZone zone) {
 156:         Calendar calendar = Calendar.getInstance(zone);
 157:         calendar.setTime(time);
 158:         this.millisecond = calendar.get(Calendar.MILLISECOND);
 159:         this.second = (byte) calendar.get(Calendar.SECOND);
 160:         this.minute = (byte) calendar.get(Calendar.MINUTE);
 161:         this.hour = (byte) calendar.get(Calendar.HOUR_OF_DAY);
 162:         this.day = new Day(time, zone);
 163:         peg(calendar);
 164:     }
 165: 
 166:     /**
 167:      * Returns the second.
 168:      *
 169:      * @return The second.
 170:      */
 171:     public Second getSecond() {
 172:         return new Second(this.second, this.minute, this.hour,
 173:                 this.day.getDayOfMonth(), this.day.getMonth(),
 174:                 this.day.getYear());
 175:     }
 176: 
 177:     /**
 178:      * Returns the millisecond.
 179:      *
 180:      * @return The millisecond.
 181:      */
 182:     public long getMillisecond() {
 183:         return this.millisecond;
 184:     }
 185: 
 186:     /**
 187:      * Returns the first millisecond of the second.  This will be determined
 188:      * relative to the time zone specified in the constructor, or in the
 189:      * calendar instance passed in the most recent call to the
 190:      * {@link #peg(Calendar)} method.
 191:      *
 192:      * @return The first millisecond of the second.
 193:      *
 194:      * @see #getLastMillisecond()
 195:      */
 196:     public long getFirstMillisecond() {
 197:         return this.firstMillisecond;
 198:     }
 199: 
 200:     /**
 201:      * Returns the last millisecond of the second.  This will be
 202:      * determined relative to the time zone specified in the constructor, or
 203:      * in the calendar instance passed in the most recent call to the
 204:      * {@link #peg(Calendar)} method.
 205:      *
 206:      * @return The last millisecond of the second.
 207:      *
 208:      * @see #getFirstMillisecond()
 209:      */
 210:     public long getLastMillisecond() {
 211:         return this.firstMillisecond;
 212:     }
 213: 
 214:     /**
 215:      * Recalculates the start date/time and end date/time for this time period
 216:      * relative to the supplied calendar (which incorporates a time zone).
 217:      *
 218:      * @param calendar  the calendar (<code>null</code> not permitted).
 219:      *
 220:      * @since 1.0.3
 221:      */
 222:     public void peg(Calendar calendar) {
 223:         this.firstMillisecond = getFirstMillisecond(calendar);
 224:     }
 225: 
 226:     /**
 227:      * Returns the millisecond preceding this one.
 228:      *
 229:      * @return The millisecond preceding this one.
 230:      */
 231:     public RegularTimePeriod previous() {
 232: 
 233:         RegularTimePeriod result = null;
 234: 
 235:         if (this.millisecond != FIRST_MILLISECOND_IN_SECOND) {
 236:             result = new Millisecond(this.millisecond - 1, getSecond());
 237:         }
 238:         else {
 239:             Second previous = (Second) getSecond().previous();
 240:             if (previous != null) {
 241:                 result = new Millisecond(LAST_MILLISECOND_IN_SECOND, previous);
 242:             }
 243:         }
 244:         return result;
 245: 
 246:     }
 247: 
 248:     /**
 249:      * Returns the millisecond following this one.
 250:      *
 251:      * @return The millisecond following this one.
 252:      */
 253:     public RegularTimePeriod next() {
 254: 
 255:         RegularTimePeriod result = null;
 256:         if (this.millisecond != LAST_MILLISECOND_IN_SECOND) {
 257:             result = new Millisecond(this.millisecond + 1, getSecond());
 258:         }
 259:         else {
 260:             Second next = (Second) getSecond().next();
 261:             if (next != null) {
 262:                 result = new Millisecond(FIRST_MILLISECOND_IN_SECOND, next);
 263:             }
 264:         }
 265:         return result;
 266: 
 267:     }
 268: 
 269:     /**
 270:      * Returns a serial index number for the millisecond.
 271:      *
 272:      * @return The serial index number.
 273:      */
 274:     public long getSerialIndex() {
 275:         long hourIndex = this.day.getSerialIndex() * 24L + this.hour;
 276:         long minuteIndex = hourIndex * 60L + this.minute;
 277:         long secondIndex = minuteIndex * 60L + this.second;
 278:         return secondIndex * 1000L + this.millisecond;
 279:     }
 280: 
 281:     /**
 282:      * Tests the equality of this object against an arbitrary Object.
 283:      * <P>
 284:      * This method will return true ONLY if the object is a Millisecond object
 285:      * representing the same millisecond as this instance.
 286:      *
 287:      * @param obj  the object to compare
 288:      *
 289:      * @return <code>true</code> if milliseconds and seconds of this and object
 290:      *      are the same.
 291:      */
 292:     public boolean equals(Object obj) {
 293:         if (obj == this) {
 294:             return true;
 295:         }
 296:         if (!(obj instanceof Millisecond)) {
 297:             return false;
 298:         }
 299:         Millisecond that = (Millisecond) obj;
 300:         if (this.millisecond != that.millisecond) {
 301:             return false;
 302:         }
 303:         if (this.second != that.second) {
 304:             return false;
 305:         }
 306:         if (this.minute != that.minute) {
 307:             return false;
 308:         }
 309:         if (this.hour != that.hour) {
 310:             return false;
 311:         }
 312:         if (!this.day.equals(that.day)) {
 313:             return false;
 314:         }
 315:         return true;
 316:     }
 317: 
 318:     /**
 319:      * Returns a hash code for this object instance.  The approach described by
 320:      * Joshua Bloch in "Effective Java" has been used here:
 321:      * <p>
 322:      * <code>http://developer.java.sun.com/developer/Books/effectivejava
 323:      * /Chapter3.pdf</code>
 324:      *
 325:      * @return A hashcode.
 326:      */
 327:     public int hashCode() {
 328:         int result = 17;
 329:         result = 37 * result + this.millisecond;
 330:         result = 37 * result + getSecond().hashCode();
 331:         return result;
 332:     }
 333: 
 334:     /**
 335:      * Returns an integer indicating the order of this Millisecond object
 336:      * relative to the specified object:
 337:      *
 338:      * negative == before, zero == same, positive == after.
 339:      *
 340:      * @param obj  the object to compare
 341:      *
 342:      * @return negative == before, zero == same, positive == after.
 343:      */
 344:     public int compareTo(Object obj) {
 345: 
 346:         int result;
 347:         long difference;
 348: 
 349:         // CASE 1 : Comparing to another Second object
 350:         // -------------------------------------------
 351:         if (obj instanceof Millisecond) {
 352:             Millisecond ms = (Millisecond) obj;
 353:             difference = getFirstMillisecond() - ms.getFirstMillisecond();
 354:             if (difference > 0) {
 355:                 result = 1;
 356:             }
 357:             else {
 358:                 if (difference < 0) {
 359:                     result = -1;
 360:                 }
 361:                 else {
 362:                     result = 0;
 363:                 }
 364:             }
 365:         }
 366: 
 367:         // CASE 2 : Comparing to another TimePeriod object
 368:         // -----------------------------------------------
 369:         else if (obj instanceof RegularTimePeriod) {
 370:             RegularTimePeriod rtp = (RegularTimePeriod) obj;
 371:             final long thisVal = this.getFirstMillisecond();
 372:             final long anotherVal = rtp.getFirstMillisecond();
 373:             result = (thisVal < anotherVal ? -1
 374:                     : (thisVal == anotherVal ? 0 : 1));
 375:         }
 376: 
 377:         // CASE 3 : Comparing to a non-TimePeriod object
 378:         // ---------------------------------------------
 379:         else {
 380:             // consider time periods to be ordered after general objects
 381:             result = 1;
 382:         }
 383: 
 384:         return result;
 385: 
 386:     }
 387: 
 388:     /**
 389:      * Returns the first millisecond of the time period.
 390:      *
 391:      * @param calendar  the calendar (<code>null</code> not permitted).
 392:      *
 393:      * @return The first millisecond of the time period.
 394:      *
 395:      * @throws NullPointerException if <code>calendar</code> is
 396:      *     <code>null</code>.
 397:      */
 398:     public long getFirstMillisecond(Calendar calendar) {
 399:         int year = this.day.getYear();
 400:         int month = this.day.getMonth() - 1;
 401:         int day = this.day.getDayOfMonth();
 402:         calendar.clear();
 403:         calendar.set(year, month, day, this.hour, this.minute, this.second);
 404:         calendar.set(Calendar.MILLISECOND, this.millisecond);
 405:         //return calendar.getTimeInMillis();  // this won't work for JDK 1.3
 406:         return calendar.getTime().getTime();
 407:     }
 408: 
 409:     /**
 410:      * Returns the last millisecond of the time period.
 411:      *
 412:      * @param calendar  the calendar (<code>null</code> not permitted).
 413:      *
 414:      * @return The last millisecond of the time period.
 415:      *
 416:      * @throws NullPointerException if <code>calendar</code> is
 417:      *     <code>null</code>.
 418:      */
 419:     public long getLastMillisecond(Calendar calendar) {
 420:         return getFirstMillisecond(calendar);
 421:     }
 422: 
 423: }