Frames | No Frames |
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: * Second.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: Second.java,v 1.6.2.3 2006/10/06 14:00:15 mungady Exp $ 36: * 37: * Changes 38: * ------- 39: * 11-Oct-2001 : Version 1 (DG); 40: * 18-Dec-2001 : Changed order of parameters in constructor (DG); 41: * 19-Dec-2001 : Added a new constructor as suggested by Paul English (DG); 42: * 14-Feb-2002 : Fixed bug in Second(Date) constructor, and changed start of 43: * range to zero from one (DG); 44: * 26-Feb-2002 : Changed getStart(), getMiddle() and getEnd() methods to 45: * evaluate with reference to a particular time zone (DG); 46: * 13-Mar-2002 : Added parseSecond() method (DG); 47: * 10-Sep-2002 : Added getSerialIndex() method (DG); 48: * 07-Oct-2002 : Fixed errors reported by Checkstyle (DG); 49: * 10-Jan-2003 : Changed base class and method names (DG); 50: * 05-Mar-2003 : Fixed bug in getLastMillisecond() picked up in JUnit 51: * tests (DG); 52: * 13-Mar-2003 : Moved to com.jrefinery.data.time package and implemented 53: * Serializable (DG); 54: * 21-Oct-2003 : Added hashCode() method (DG); 55: * ------------- JFREECHART 1.0.x --------------------------------------------- 56: * 05-Oct-2006 : Updated API docs (DG); 57: * 06-Oct-2006 : Refactored to cache first and last millisecond values (DG); 58: * 59: */ 60: 61: package org.jfree.data.time; 62: 63: import java.io.Serializable; 64: import java.util.Calendar; 65: import java.util.Date; 66: import java.util.TimeZone; 67: 68: /** 69: * Represents a second in a particular day. This class is immutable, which is 70: * a requirement for all {@link RegularTimePeriod} subclasses. 71: */ 72: public class Second extends RegularTimePeriod implements Serializable { 73: 74: /** For serialization. */ 75: private static final long serialVersionUID = -6536564190712383466L; 76: 77: /** Useful constant for the first second in a minute. */ 78: public static final int FIRST_SECOND_IN_MINUTE = 0; 79: 80: /** Useful constant for the last second in a minute. */ 81: public static final int LAST_SECOND_IN_MINUTE = 59; 82: 83: /** The day. */ 84: private Day day; 85: 86: /** The hour of the day. */ 87: private byte hour; 88: 89: /** The minute. */ 90: private byte minute; 91: 92: /** The second. */ 93: private byte second; 94: 95: /** 96: * The first millisecond. We don't store the last millisecond, because it 97: * is always firstMillisecond + 999L. 98: */ 99: private long firstMillisecond; 100: 101: /** 102: * Constructs a new Second, based on the system date/time. 103: */ 104: public Second() { 105: this(new Date()); 106: } 107: 108: /** 109: * Constructs a new Second. 110: * 111: * @param second the second (0 to 24*60*60-1). 112: * @param minute the minute (<code>null</code> not permitted). 113: */ 114: public Second(int second, Minute minute) { 115: if (minute == null) { 116: throw new IllegalArgumentException("Null 'minute' argument."); 117: } 118: this.day = minute.getDay(); 119: this.hour = (byte) minute.getHourValue(); 120: this.minute = (byte) minute.getMinute(); 121: this.second = (byte) second; 122: peg(Calendar.getInstance()); 123: } 124: 125: /** 126: * Creates a new second. 127: * 128: * @param second the second (0-59). 129: * @param minute the minute (0-59). 130: * @param hour the hour (0-23). 131: * @param day the day (1-31). 132: * @param month the month (1-12). 133: * @param year the year (1900-9999). 134: */ 135: public Second(int second, int minute, int hour, 136: int day, int month, int year) { 137: this(second, new Minute(minute, hour, day, month, year)); 138: } 139: 140: /** 141: * Constructs a second. 142: * 143: * @param time the time. 144: */ 145: public Second(Date time) { 146: this(time, RegularTimePeriod.DEFAULT_TIME_ZONE); 147: } 148: 149: /** 150: * Creates a new second based on the supplied time and time zone. 151: * 152: * @param time the instant in time. 153: * @param zone the time zone. 154: */ 155: public Second(Date time, final TimeZone zone) { 156: Calendar calendar = Calendar.getInstance(zone); 157: calendar.setTime(time); 158: this.second = (byte) calendar.get(Calendar.SECOND); 159: this.minute = (byte) calendar.get(Calendar.MINUTE); 160: this.hour = (byte) calendar.get(Calendar.HOUR_OF_DAY); 161: this.day = new Day(time, zone); 162: peg(calendar); 163: } 164: 165: /** 166: * Returns the second within the minute. 167: * 168: * @return The second (0 - 59). 169: */ 170: public int getSecond() { 171: return this.second; 172: } 173: 174: /** 175: * Returns the minute. 176: * 177: * @return The minute (never <code>null</code>). 178: */ 179: public Minute getMinute() { 180: return new Minute(this.minute, new Hour(this.hour, this.day)); 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 + 999L; 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 second preceding this one. 225: * 226: * @return The second preceding this one. 227: */ 228: public RegularTimePeriod previous() { 229: 230: Second result = null; 231: if (this.second != FIRST_SECOND_IN_MINUTE) { 232: result = new Second(this.second - 1, getMinute()); 233: } 234: else { 235: Minute previous = (Minute) getMinute().previous(); 236: if (previous != null) { 237: result = new Second(LAST_SECOND_IN_MINUTE, previous); 238: } 239: } 240: return result; 241: 242: } 243: 244: /** 245: * Returns the second following this one. 246: * 247: * @return The second following this one. 248: */ 249: public RegularTimePeriod next() { 250: 251: Second result = null; 252: if (this.second != LAST_SECOND_IN_MINUTE) { 253: result = new Second(this.second + 1, getMinute()); 254: } 255: else { 256: Minute next = (Minute) getMinute().next(); 257: if (next != null) { 258: result = new Second(FIRST_SECOND_IN_MINUTE, next); 259: } 260: } 261: return result; 262: 263: } 264: 265: /** 266: * Returns a serial index number for the minute. 267: * 268: * @return The serial index number. 269: */ 270: public long getSerialIndex() { 271: long hourIndex = this.day.getSerialIndex() * 24L + this.hour; 272: long minuteIndex = hourIndex * 60L + this.minute; 273: return minuteIndex * 60L + this.second; 274: } 275: 276: /** 277: * Returns the first millisecond of the minute. 278: * 279: * @param calendar the calendar/timezone (<code>null</code> not permitted). 280: * 281: * @return The first millisecond. 282: * 283: * @throws NullPointerException if <code>calendar</code> is 284: * <code>null</code>. 285: */ 286: public long getFirstMillisecond(Calendar calendar) { 287: int year = this.day.getYear(); 288: int month = this.day.getMonth() - 1; 289: int day = this.day.getDayOfMonth(); 290: calendar.clear(); 291: calendar.set(year, month, day, this.hour, this.minute, this.second); 292: calendar.set(Calendar.MILLISECOND, 0); 293: //return calendar.getTimeInMillis(); // this won't work for JDK 1.3 294: return calendar.getTime().getTime(); 295: } 296: 297: /** 298: * Returns the last millisecond of the second. 299: * 300: * @param calendar the calendar/timezone (<code>null</code> not permitted). 301: * 302: * @return The last millisecond. 303: * 304: * @throws NullPointerException if <code>calendar</code> is 305: * <code>null</code>. 306: */ 307: public long getLastMillisecond(Calendar calendar) { 308: return getFirstMillisecond(calendar) + 999L; 309: } 310: 311: /** 312: * Tests the equality of this object against an arbitrary Object. 313: * <P> 314: * This method will return true ONLY if the object is a Second object 315: * representing the same second as this instance. 316: * 317: * @param obj the object to compare (<code>null</code> permitted). 318: * 319: * @return <code>true</code> if second and minute of this and the object 320: * are the same. 321: */ 322: public boolean equals(Object obj) { 323: if (obj == this) { 324: return true; 325: } 326: if (!(obj instanceof Second)) { 327: return false; 328: } 329: Second that = (Second) obj; 330: if (this.second != that.second) { 331: return false; 332: } 333: if (this.minute != that.minute) { 334: return false; 335: } 336: if (this.hour != that.hour) { 337: return false; 338: } 339: if (!this.day.equals(that.day)) { 340: return false; 341: } 342: return true; 343: } 344: 345: /** 346: * Returns a hash code for this object instance. The approach described by 347: * Joshua Bloch in "Effective Java" has been used here: 348: * <p> 349: * <code>http://developer.java.sun.com/developer/Books/effectivejava 350: * /Chapter3.pdf</code> 351: * 352: * @return A hash code. 353: */ 354: public int hashCode() { 355: int result = 17; 356: result = 37 * result + this.second; 357: result = 37 * result + this.minute; 358: result = 37 * result + this.hour; 359: result = 37 * result + this.day.hashCode(); 360: return result; 361: } 362: 363: /** 364: * Returns an integer indicating the order of this Second object relative 365: * to the specified 366: * object: negative == before, zero == same, positive == after. 367: * 368: * @param o1 the object to compare. 369: * 370: * @return negative == before, zero == same, positive == after. 371: */ 372: public int compareTo(Object o1) { 373: 374: int result; 375: 376: // CASE 1 : Comparing to another Second object 377: // ------------------------------------------- 378: if (o1 instanceof Second) { 379: Second s = (Second) o1; 380: if (this.firstMillisecond < s.firstMillisecond) { 381: return -1; 382: } 383: else if (this.firstMillisecond > s.firstMillisecond) { 384: return 1; 385: } 386: else { 387: return 0; 388: } 389: } 390: 391: // CASE 2 : Comparing to another TimePeriod object 392: // ----------------------------------------------- 393: else if (o1 instanceof RegularTimePeriod) { 394: // more difficult case - evaluate later... 395: result = 0; 396: } 397: 398: // CASE 3 : Comparing to a non-TimePeriod object 399: // --------------------------------------------- 400: else { 401: // consider time periods to be ordered after general objects 402: result = 1; 403: } 404: 405: return result; 406: 407: } 408: 409: /** 410: * Creates a new instance by parsing a string. The string is assumed to 411: * be in the format "YYYY-MM-DD HH:MM:SS", perhaps with leading or trailing 412: * whitespace. 413: * 414: * @param s the string to parse. 415: * 416: * @return The second, or <code>null</code> if the string is not parseable. 417: */ 418: public static Second parseSecond(String s) { 419: 420: Second result = null; 421: s = s.trim(); 422: 423: String daystr = s.substring(0, Math.min(10, s.length())); 424: Day day = Day.parseDay(daystr); 425: if (day != null) { 426: String hmsstr = s.substring( 427: Math.min(daystr.length() + 1, s.length()), s.length() 428: ); 429: hmsstr = hmsstr.trim(); 430: 431: int l = hmsstr.length(); 432: String hourstr = hmsstr.substring(0, Math.min(2, l)); 433: String minstr = hmsstr.substring(Math.min(3, l), Math.min(5, l)); 434: String secstr = hmsstr.substring(Math.min(6, l), Math.min(8, l)); 435: int hour = Integer.parseInt(hourstr); 436: 437: if ((hour >= 0) && (hour <= 23)) { 438: 439: int minute = Integer.parseInt(minstr); 440: if ((minute >= 0) && (minute <= 59)) { 441: 442: Minute m = new Minute(minute, new Hour(hour, day)); 443: int second = Integer.parseInt(secstr); 444: if ((second >= 0) && (second <= 59)) { 445: result = new Second(second, m); 446: } 447: } 448: } 449: } 450: 451: return result; 452: 453: } 454: 455: }