001 /* =========================================================== 002 * JFreeChart : a free chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C) Copyright 2000-2008, by Object Refinery Limited and Contributors. 006 * 007 * Project Info: http://www.jfree.org/jfreechart/index.html 008 * 009 * This library is free software; you can redistribute it and/or modify it 010 * under the terms of the GNU Lesser General Public License as published by 011 * the Free Software Foundation; either version 2.1 of the License, or 012 * (at your option) any later version. 013 * 014 * This library is distributed in the hope that it will be useful, but 015 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 016 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 017 * License for more details. 018 * 019 * You should have received a copy of the GNU Lesser General Public 020 * License along with this library; if not, write to the Free Software 021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 022 * USA. 023 * 024 * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 025 * in the United States and other countries.] 026 * 027 * ---------------- 028 * Millisecond.java 029 * ---------------- 030 * (C) Copyright 2001-2008, by Object Refinery Limited. 031 * 032 * Original Author: David Gilbert (for Object Refinery Limited); 033 * Contributor(s): -; 034 * 035 * Changes 036 * ------- 037 * 11-Oct-2001 : Version 1 (DG); 038 * 19-Dec-2001 : Added new constructors as suggested by Paul English (DG); 039 * 26-Feb-2002 : Added new getStart() and getEnd() methods (DG); 040 * 29-Mar-2002 : Fixed bug in getStart(), getEnd() and compareTo() methods (DG); 041 * 10-Sep-2002 : Added getSerialIndex() method (DG); 042 * 07-Oct-2002 : Fixed errors reported by Checkstyle (DG); 043 * 10-Jan-2003 : Changed base class and method names (DG); 044 * 13-Mar-2003 : Moved to com.jrefinery.data.time package and implemented 045 * Serializable (DG); 046 * 21-Oct-2003 : Added hashCode() method (DG); 047 * ------------- JFREECHART 1.0.x --------------------------------------------- 048 * 05-Oct-2006 : Updated API docs (DG); 049 * 06-Oct-2006 : Refactored to cache first and last millisecond values (DG); 050 * 04-Apr-2007 : In Millisecond(Date, TimeZone), peg milliseconds to the 051 * specified zone (DG); 052 * 06-Jun-2008 : Added handling for general RegularTimePeriod in compareTo() 053 * method: 054 * see http://www.jfree.org/phpBB2/viewtopic.php?t=24805 (DG); 055 * 056 */ 057 058 package org.jfree.data.time; 059 060 import java.io.Serializable; 061 import java.util.Calendar; 062 import java.util.Date; 063 import java.util.TimeZone; 064 065 /** 066 * Represents a millisecond. This class is immutable, which is a requirement 067 * for all {@link RegularTimePeriod} subclasses. 068 */ 069 public class Millisecond extends RegularTimePeriod implements Serializable { 070 071 /** For serialization. */ 072 static final long serialVersionUID = -5316836467277638485L; 073 074 /** A constant for the first millisecond in a second. */ 075 public static final int FIRST_MILLISECOND_IN_SECOND = 0; 076 077 /** A constant for the last millisecond in a second. */ 078 public static final int LAST_MILLISECOND_IN_SECOND = 999; 079 080 /** The day. */ 081 private Day day; 082 083 /** The hour in the day. */ 084 private byte hour; 085 086 /** The minute. */ 087 private byte minute; 088 089 /** The second. */ 090 private byte second; 091 092 /** The millisecond. */ 093 private int millisecond; 094 095 /** 096 * The pegged millisecond. 097 */ 098 private long firstMillisecond; 099 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 }