001/* =========================================================== 002 * JFreeChart : a free chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C) Copyright 2000-present, by David Gilbert 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 * [Oracle and Java are registered trademarks of Oracle and/or its affiliates. 025 * Other names may be trademarks of their respective owners.] 026 * 027 * ---------------- 028 * Millisecond.java 029 * ---------------- 030 * (C) Copyright 2001-present, by David Gilbert. 031 * 032 * Original Author: David Gilbert; 033 * Contributor(s): -; 034 * 035 */ 036 037package org.jfree.data.time; 038 039import org.jfree.chart.util.Args; 040 041import java.io.Serializable; 042import java.util.Calendar; 043import java.util.Date; 044import java.util.Locale; 045import java.util.TimeZone; 046 047/** 048 * Represents a millisecond. This class is immutable, which is a requirement 049 * for all {@link RegularTimePeriod} subclasses. 050 */ 051public class Millisecond extends RegularTimePeriod implements Serializable { 052 053 /** For serialization. */ 054 static final long serialVersionUID = -5316836467277638485L; 055 056 /** A constant for the first millisecond in a second. */ 057 public static final int FIRST_MILLISECOND_IN_SECOND = 0; 058 059 /** A constant for the last millisecond in a second. */ 060 public static final int LAST_MILLISECOND_IN_SECOND = 999; 061 062 /** The day. */ 063 private Day day; 064 065 /** The hour in the day. */ 066 private byte hour; 067 068 /** The minute. */ 069 private byte minute; 070 071 /** The second. */ 072 private byte second; 073 074 /** The millisecond. */ 075 private int millisecond; 076 077 /** 078 * The pegged millisecond. 079 */ 080 private long firstMillisecond; 081 082 /** 083 * Constructs a millisecond based on the current system time. 084 * The time zone and locale are determined by the calendar 085 * returned by {@link RegularTimePeriod#getCalendarInstance()}. 086 */ 087 public Millisecond() { 088 this(new Date()); 089 } 090 091 /** 092 * Constructs a millisecond. 093 * The time zone and locale are determined by the calendar 094 * returned by {@link RegularTimePeriod#getCalendarInstance()}. 095 * 096 * @param millisecond the millisecond (0-999). 097 * @param second the second ({@code null} not permitted). 098 */ 099 public Millisecond(int millisecond, Second second) { 100 Args.nullNotPermitted(second, "second"); 101 this.millisecond = millisecond; 102 this.second = (byte) second.getSecond(); 103 this.minute = (byte) second.getMinute().getMinute(); 104 this.hour = (byte) second.getMinute().getHourValue(); 105 this.day = second.getMinute().getDay(); 106 peg(getCalendarInstance()); 107 } 108 109 /** 110 * Creates a new millisecond. 111 * The time zone and locale are determined by the calendar 112 * returned by {@link RegularTimePeriod#getCalendarInstance()}. 113 * 114 * @param millisecond the millisecond (0-999). 115 * @param second the second (0-59). 116 * @param minute the minute (0-59). 117 * @param hour the hour (0-23). 118 * @param day the day (1-31). 119 * @param month the month (1-12). 120 * @param year the year (1900-9999). 121 */ 122 public Millisecond(int millisecond, int second, int minute, int hour, 123 int day, int month, int year) { 124 125 this(millisecond, new Second(second, minute, hour, day, month, year)); 126 127 } 128 129 /** 130 * Constructs a new millisecond. 131 * The time zone and locale are determined by the calendar 132 * returned by {@link RegularTimePeriod#getCalendarInstance()}. 133 * 134 * @param time the time. 135 * 136 * @see #Millisecond(Date, TimeZone, Locale) 137 */ 138 public Millisecond(Date time) { 139 this(time, getCalendarInstance()); 140 } 141 142 /** 143 * Creates a millisecond. 144 * 145 * @param time the date-time ({@code null} not permitted). 146 * @param zone the time zone ({@code null} not permitted). 147 * @param locale the locale ({@code null} not permitted). 148 */ 149 public Millisecond(Date time, TimeZone zone, Locale locale) { 150 Args.nullNotPermitted(time, "time"); 151 Args.nullNotPermitted(zone, "zone"); 152 Args.nullNotPermitted(locale, "locale"); 153 Calendar calendar = Calendar.getInstance(zone, locale); 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, locale); 160 peg(calendar); 161 } 162 163 /** 164 * Constructs a new instance, based on a particular date/time. 165 * The time zone and locale are determined by the {@code calendar} 166 * parameter. 167 * 168 * @param time the date/time ({@code null} not permitted). 169 * @param calendar the calendar to use for calculations ({@code null} not permitted). 170 */ 171 public Millisecond(Date time, Calendar calendar) { 172 Args.nullNotPermitted(time, "time"); 173 Args.nullNotPermitted(calendar, "calendar"); 174 calendar.setTime(time); 175 this.millisecond = calendar.get(Calendar.MILLISECOND); 176 this.second = (byte) calendar.get(Calendar.SECOND); 177 this.minute = (byte) calendar.get(Calendar.MINUTE); 178 this.hour = (byte) calendar.get(Calendar.HOUR_OF_DAY); 179 this.day = new Day(time, calendar); 180 peg(calendar); 181 } 182 183 /** 184 * Returns the second. 185 * 186 * @return The second. 187 */ 188 public Second getSecond() { 189 return new Second(this.second, this.minute, this.hour, 190 this.day.getDayOfMonth(), this.day.getMonth(), 191 this.day.getYear()); 192 } 193 194 /** 195 * Returns the millisecond. 196 * 197 * @return The millisecond. 198 */ 199 public long getMillisecond() { 200 return this.millisecond; 201 } 202 203 /** 204 * Returns the first millisecond of the second. This will be determined 205 * relative to the time zone specified in the constructor, or in the 206 * calendar instance passed in the most recent call to the 207 * {@link #peg(Calendar)} method. 208 * 209 * @return The first millisecond of the second. 210 * 211 * @see #getLastMillisecond() 212 */ 213 @Override 214 public long getFirstMillisecond() { 215 return this.firstMillisecond; 216 } 217 218 /** 219 * Returns the last millisecond of the second. This will be 220 * determined relative to the time zone specified in the constructor, or 221 * in the calendar instance passed in the most recent call to the 222 * {@link #peg(Calendar)} method. 223 * 224 * @return The last millisecond of the second. 225 * 226 * @see #getFirstMillisecond() 227 */ 228 @Override 229 public long getLastMillisecond() { 230 return this.firstMillisecond; 231 } 232 233 /** 234 * Recalculates the start date/time and end date/time for this time period 235 * relative to the supplied calendar (which incorporates a time zone). 236 * 237 * @param calendar the calendar ({@code null} not permitted). 238 */ 239 @Override 240 public void peg(Calendar calendar) { 241 this.firstMillisecond = getFirstMillisecond(calendar); 242 } 243 244 /** 245 * Returns the millisecond preceding this one. 246 * No matter what time zone and locale this instance was created with, 247 * the returned instance will use the default calendar for time 248 * calculations, obtained with {@link RegularTimePeriod#getCalendarInstance()}. 249 * 250 * @return The millisecond preceding this one. 251 */ 252 @Override 253 public RegularTimePeriod previous() { 254 RegularTimePeriod result = null; 255 if (this.millisecond != FIRST_MILLISECOND_IN_SECOND) { 256 result = new Millisecond(this.millisecond - 1, getSecond()); 257 } 258 else { 259 Second previous = (Second) getSecond().previous(); 260 if (previous != null) { 261 result = new Millisecond(LAST_MILLISECOND_IN_SECOND, previous); 262 } 263 } 264 return result; 265 } 266 267 /** 268 * Returns the millisecond following this one. 269 * No matter what time zone and locale this instance was created with, 270 * the returned instance will use the default calendar for time 271 * calculations, obtained with {@link RegularTimePeriod#getCalendarInstance()}. 272 * 273 * @return The millisecond following this one. 274 */ 275 @Override 276 public RegularTimePeriod next() { 277 RegularTimePeriod result = null; 278 if (this.millisecond != LAST_MILLISECOND_IN_SECOND) { 279 result = new Millisecond(this.millisecond + 1, getSecond()); 280 } 281 else { 282 Second next = (Second) getSecond().next(); 283 if (next != null) { 284 result = new Millisecond(FIRST_MILLISECOND_IN_SECOND, next); 285 } 286 } 287 return result; 288 } 289 290 /** 291 * Returns a serial index number for the millisecond. 292 * 293 * @return The serial index number. 294 */ 295 @Override 296 public long getSerialIndex() { 297 long hourIndex = this.day.getSerialIndex() * 24L + this.hour; 298 long minuteIndex = hourIndex * 60L + this.minute; 299 long secondIndex = minuteIndex * 60L + this.second; 300 return secondIndex * 1000L + this.millisecond; 301 } 302 303 /** 304 * Tests the equality of this object against an arbitrary Object. 305 * <P> 306 * This method will return true ONLY if the object is a Millisecond object 307 * representing the same millisecond as this instance. 308 * 309 * @param obj the object to compare 310 * 311 * @return {@code true} if milliseconds and seconds of this and object 312 * are the same. 313 */ 314 @Override 315 public boolean equals(Object obj) { 316 if (obj == this) { 317 return true; 318 } 319 if (!(obj instanceof Millisecond)) { 320 return false; 321 } 322 Millisecond that = (Millisecond) obj; 323 if (this.millisecond != that.millisecond) { 324 return false; 325 } 326 if (this.second != that.second) { 327 return false; 328 } 329 if (this.minute != that.minute) { 330 return false; 331 } 332 if (this.hour != that.hour) { 333 return false; 334 } 335 if (!this.day.equals(that.day)) { 336 return false; 337 } 338 return true; 339 } 340 341 /** 342 * Returns a hash code for this object instance. The approach described by 343 * Joshua Bloch in "Effective Java" has been used here: 344 * <p> 345 * {@code http://developer.java.sun.com/developer/Books/effectivejava 346 * /Chapter3.pdf} 347 * 348 * @return A hashcode. 349 */ 350 @Override 351 public int hashCode() { 352 int result = 17; 353 result = 37 * result + this.millisecond; 354 result = 37 * result + getSecond().hashCode(); 355 return result; 356 } 357 358 /** 359 * Returns an integer indicating the order of this Millisecond object 360 * relative to the specified object: 361 * 362 * negative == before, zero == same, positive == after. 363 * 364 * @param obj the object to compare 365 * 366 * @return negative == before, zero == same, positive == after. 367 */ 368 @Override 369 public int compareTo(Object obj) { 370 int result; 371 long difference; 372 373 // CASE 1 : Comparing to another Second object 374 // ------------------------------------------- 375 if (obj instanceof Millisecond) { 376 Millisecond ms = (Millisecond) obj; 377 difference = getFirstMillisecond() - ms.getFirstMillisecond(); 378 if (difference > 0) { 379 result = 1; 380 } 381 else { 382 if (difference < 0) { 383 result = -1; 384 } 385 else { 386 result = 0; 387 } 388 } 389 } 390 391 // CASE 2 : Comparing to another TimePeriod object 392 // ----------------------------------------------- 393 else if (obj instanceof RegularTimePeriod) { 394 RegularTimePeriod rtp = (RegularTimePeriod) obj; 395 final long thisVal = this.getFirstMillisecond(); 396 final long anotherVal = rtp.getFirstMillisecond(); 397 result = (thisVal < anotherVal ? -1 398 : (thisVal == anotherVal ? 0 : 1)); 399 } 400 401 // CASE 3 : Comparing to a non-TimePeriod object 402 // --------------------------------------------- 403 else { 404 // consider time periods to be ordered after general objects 405 result = 1; 406 } 407 408 return result; 409 } 410 411 /** 412 * Returns the first millisecond of the time period. 413 * 414 * @param calendar the calendar ({@code null} not permitted). 415 * 416 * @return The first millisecond of the time period. 417 * 418 * @throws NullPointerException if {@code calendar} is 419 * {@code null}. 420 */ 421 @Override 422 public long getFirstMillisecond(Calendar calendar) { 423 int year = this.day.getYear(); 424 int month = this.day.getMonth() - 1; 425 int d = this.day.getDayOfMonth(); 426 calendar.clear(); 427 calendar.set(year, month, d, this.hour, this.minute, this.second); 428 calendar.set(Calendar.MILLISECOND, this.millisecond); 429 return calendar.getTimeInMillis(); 430 } 431 432 /** 433 * Returns the last millisecond of the time period. 434 * 435 * @param calendar the calendar ({@code null} not permitted). 436 * 437 * @return The last millisecond of the time period. 438 * 439 * @throws NullPointerException if {@code calendar} is 440 * {@code null}. 441 */ 442 @Override 443 public long getLastMillisecond(Calendar calendar) { 444 return getFirstMillisecond(calendar); 445 } 446 447}