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