001 /* =========================================================== 002 * JFreeChart : a free chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C) Copyright 2000-2007, 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-2007, 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 * 053 */ 054 055 package org.jfree.data.time; 056 057 import java.io.Serializable; 058 import java.util.Calendar; 059 import java.util.Date; 060 import java.util.TimeZone; 061 062 /** 063 * Represents a millisecond. This class is immutable, which is a requirement 064 * for all {@link RegularTimePeriod} subclasses. 065 */ 066 public class Millisecond extends RegularTimePeriod implements Serializable { 067 068 /** For serialization. */ 069 static final long serialVersionUID = -5316836467277638485L; 070 071 /** A constant for the first millisecond in a second. */ 072 public static final int FIRST_MILLISECOND_IN_SECOND = 0; 073 074 /** A constant for the last millisecond in a second. */ 075 public static final int LAST_MILLISECOND_IN_SECOND = 999; 076 077 /** The day. */ 078 private Day day; 079 080 /** The hour in the day. */ 081 private byte hour; 082 083 /** The minute. */ 084 private byte minute; 085 086 /** The second. */ 087 private byte second; 088 089 /** The millisecond. */ 090 private int millisecond; 091 092 /** 093 * The pegged millisecond. 094 */ 095 private long firstMillisecond; 096 097 /** 098 * Constructs a millisecond based on the current system time. 099 */ 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); 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 }