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: * Minute.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: Minute.java,v 1.5.2.4 2006/12/11 10:03:22 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 Minute(Date) constructor, and changed the range 43: * to start from zero instead of 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 parseMinute() method (DG); 47: * 19-Mar-2002 : Changed API, the minute is now defined in relation to an 48: * Hour (DG); 49: * 10-Sep-2002 : Added getSerialIndex() method (DG); 50: * 07-Oct-2002 : Fixed errors reported by Checkstyle (DG); 51: * 10-Jan-2003 : Changed base class and method names (DG); 52: * 13-Mar-2003 : Moved to com.jrefinery.data.time package and implemented 53: * Serializable (DG); 54: * 21-Oct-2003 : Added hashCode() method, and new constructor for 55: * convenience (DG); 56: * 30-Sep-2004 : Replaced getTime().getTime() with getTimeInMillis() (DG); 57: * 04-Nov-2004 : Reverted change of 30-Sep-2004, because it won't work for 58: * JDK 1.3 (DG); 59: * ------------- JFREECHART 1.0.x --------------------------------------------- 60: * 05-Oct-2006 : Updated API docs (DG); 61: * 06-Oct-2006 : Refactored to cache first and last millisecond values (DG); 62: * 11-Dec-2006 : Fix for previous() - bug 1611872 (DG); 63: * 64: */ 65: 66: package org.jfree.data.time; 67: 68: import java.io.Serializable; 69: import java.util.Calendar; 70: import java.util.Date; 71: import java.util.TimeZone; 72: 73: /** 74: * Represents a minute. This class is immutable, which is a requirement for 75: * all {@link RegularTimePeriod} subclasses. 76: */ 77: public class Minute extends RegularTimePeriod implements Serializable { 78: 79: /** For serialization. */ 80: private static final long serialVersionUID = 2144572840034842871L; 81: 82: /** Useful constant for the first minute in a day. */ 83: public static final int FIRST_MINUTE_IN_HOUR = 0; 84: 85: /** Useful constant for the last minute in a day. */ 86: public static final int LAST_MINUTE_IN_HOUR = 59; 87: 88: /** The day. */ 89: private Day day; 90: 91: /** The hour in which the minute falls. */ 92: private byte hour; 93: 94: /** The minute. */ 95: private byte minute; 96: 97: /** The first millisecond. */ 98: private long firstMillisecond; 99: 100: /** The last millisecond. */ 101: private long lastMillisecond; 102: 103: /** 104: * Constructs a new Minute, based on the system date/time. 105: */ 106: public Minute() { 107: this(new Date()); 108: } 109: 110: /** 111: * Constructs a new Minute. 112: * 113: * @param minute the minute (0 to 59). 114: * @param hour the hour (<code>null</code> not permitted). 115: */ 116: public Minute(int minute, Hour hour) { 117: if (hour == null) { 118: throw new IllegalArgumentException("Null 'hour' argument."); 119: } 120: this.minute = (byte) minute; 121: this.hour = (byte) hour.getHour(); 122: this.day = hour.getDay(); 123: peg(Calendar.getInstance()); 124: } 125: 126: /** 127: * Constructs a new Minute, based on the supplied date/time. 128: * 129: * @param time the time (<code>null</code> not permitted). 130: */ 131: public Minute(Date time) { 132: // defer argument checking 133: this(time, RegularTimePeriod.DEFAULT_TIME_ZONE); 134: } 135: 136: /** 137: * Constructs a new Minute, based on the supplied date/time and timezone. 138: * 139: * @param time the time (<code>null</code> not permitted). 140: * @param zone the time zone (<code>null</code> not permitted). 141: */ 142: public Minute(Date time, TimeZone zone) { 143: if (time == null) { 144: throw new IllegalArgumentException("Null 'time' argument."); 145: } 146: if (zone == null) { 147: throw new IllegalArgumentException("Null 'zone' argument."); 148: } 149: Calendar calendar = Calendar.getInstance(zone); 150: calendar.setTime(time); 151: int min = calendar.get(Calendar.MINUTE); 152: this.minute = (byte) min; 153: this.hour = (byte) calendar.get(Calendar.HOUR_OF_DAY); 154: this.day = new Day(time, zone); 155: peg(calendar); 156: } 157: 158: /** 159: * Creates a new minute. 160: * 161: * @param minute the minute (0-59). 162: * @param hour the hour (0-23). 163: * @param day the day (1-31). 164: * @param month the month (1-12). 165: * @param year the year (1900-9999). 166: */ 167: public Minute(int minute, 168: int hour, 169: int day, 170: int month, 171: int year) { 172: this(minute, new Hour(hour, new Day(day, month, year))); 173: } 174: 175: /** 176: * Returns the day. 177: * 178: * @return The day. 179: * 180: * @since 1.0.3 181: */ 182: public Day getDay() { 183: return this.day; 184: } 185: 186: /** 187: * Returns the hour. 188: * 189: * @return The hour (never <code>null</code>). 190: */ 191: public Hour getHour() { 192: return new Hour(this.hour, this.day); 193: } 194: 195: /** 196: * Returns the hour. 197: * 198: * @return The hour. 199: * 200: * @since 1.0.3 201: */ 202: public int getHourValue() { 203: return this.hour; 204: } 205: 206: /** 207: * Returns the minute. 208: * 209: * @return The minute. 210: */ 211: public int getMinute() { 212: return this.minute; 213: } 214: 215: /** 216: * Returns the first millisecond of the minute. This will be determined 217: * relative to the time zone specified in the constructor, or in the 218: * calendar instance passed in the most recent call to the 219: * {@link #peg(Calendar)} method. 220: * 221: * @return The first millisecond of the minute. 222: * 223: * @see #getLastMillisecond() 224: */ 225: public long getFirstMillisecond() { 226: return this.firstMillisecond; 227: } 228: 229: /** 230: * Returns the last millisecond of the minute. This will be 231: * determined relative to the time zone specified in the constructor, or 232: * in the calendar instance passed in the most recent call to the 233: * {@link #peg(Calendar)} method. 234: * 235: * @return The last millisecond of the minute. 236: * 237: * @see #getFirstMillisecond() 238: */ 239: public long getLastMillisecond() { 240: return this.lastMillisecond; 241: } 242: 243: /** 244: * Recalculates the start date/time and end date/time for this time period 245: * relative to the supplied calendar (which incorporates a time zone). 246: * 247: * @param calendar the calendar (<code>null</code> not permitted). 248: * 249: * @since 1.0.3 250: */ 251: public void peg(Calendar calendar) { 252: this.firstMillisecond = getFirstMillisecond(calendar); 253: this.lastMillisecond = getLastMillisecond(calendar); 254: } 255: 256: /** 257: * Returns the minute preceding this one. 258: * 259: * @return The minute preceding this one. 260: */ 261: public RegularTimePeriod previous() { 262: Minute result; 263: if (this.minute != FIRST_MINUTE_IN_HOUR) { 264: result = new Minute(this.minute - 1, getHour()); 265: } 266: else { 267: Hour h = (Hour) getHour().previous(); 268: if (h != null) { 269: result = new Minute(LAST_MINUTE_IN_HOUR, h); 270: } 271: else { 272: result = null; 273: } 274: } 275: return result; 276: } 277: 278: /** 279: * Returns the minute following this one. 280: * 281: * @return The minute following this one. 282: */ 283: public RegularTimePeriod next() { 284: 285: Minute result; 286: if (this.minute != LAST_MINUTE_IN_HOUR) { 287: result = new Minute(this.minute + 1, getHour()); 288: } 289: else { // we are at the last minute in the hour... 290: Hour nextHour = (Hour) getHour().next(); 291: if (nextHour != null) { 292: result = new Minute(FIRST_MINUTE_IN_HOUR, nextHour); 293: } 294: else { 295: result = null; 296: } 297: } 298: return result; 299: 300: } 301: 302: /** 303: * Returns a serial index number for the minute. 304: * 305: * @return The serial index number. 306: */ 307: public long getSerialIndex() { 308: long hourIndex = this.day.getSerialIndex() * 24L + this.hour; 309: return hourIndex * 60L + this.minute; 310: } 311: 312: /** 313: * Returns the first millisecond of the minute. 314: * 315: * @param calendar the calendar which defines the timezone 316: * (<code>null</code> not permitted). 317: * 318: * @return The first millisecond. 319: * 320: * @throws NullPointerException if <code>calendar</code> is 321: * <code>null</code>. 322: */ 323: public long getFirstMillisecond(Calendar calendar) { 324: 325: int year = this.day.getYear(); 326: int month = this.day.getMonth() - 1; 327: int day = this.day.getDayOfMonth(); 328: 329: calendar.clear(); 330: calendar.set(year, month, day, this.hour, this.minute, 0); 331: calendar.set(Calendar.MILLISECOND, 0); 332: 333: //return calendar.getTimeInMillis(); // this won't work for JDK 1.3 334: return calendar.getTime().getTime(); 335: 336: } 337: 338: /** 339: * Returns the last millisecond of the minute. 340: * 341: * @param calendar the calendar / timezone (<code>null</code> not 342: * permitted). 343: * 344: * @return The last millisecond. 345: * 346: * @throws NullPointerException if <code>calendar</code> is 347: * <code>null</code>. 348: */ 349: public long getLastMillisecond(Calendar calendar) { 350: 351: int year = this.day.getYear(); 352: int month = this.day.getMonth() - 1; 353: int day = this.day.getDayOfMonth(); 354: 355: calendar.clear(); 356: calendar.set(year, month, day, this.hour, this.minute, 59); 357: calendar.set(Calendar.MILLISECOND, 999); 358: 359: //return calendar.getTimeInMillis(); // this won't work for JDK 1.3 360: return calendar.getTime().getTime(); 361: 362: } 363: 364: /** 365: * Tests the equality of this object against an arbitrary Object. 366: * <P> 367: * This method will return true ONLY if the object is a Minute object 368: * representing the same minute as this instance. 369: * 370: * @param obj the object to compare (<code>null</code> permitted). 371: * 372: * @return <code>true</code> if the minute and hour value of this and the 373: * object are the same. 374: */ 375: public boolean equals(Object obj) { 376: if (obj == this) { 377: return true; 378: } 379: if (!(obj instanceof Minute)) { 380: return false; 381: } 382: Minute that = (Minute) obj; 383: if (this.minute != that.minute) { 384: return false; 385: } 386: if (this.hour != that.hour) { 387: return false; 388: } 389: return true; 390: } 391: 392: /** 393: * Returns a hash code for this object instance. The approach described 394: * by Joshua Bloch in "Effective Java" has been used here: 395: * <p> 396: * <code>http://developer.java.sun.com/developer/Books/effectivejava 397: * /Chapter3.pdf</code> 398: * 399: * @return A hash code. 400: */ 401: public int hashCode() { 402: int result = 17; 403: result = 37 * result + this.minute; 404: result = 37 * result + this.hour; 405: result = 37 * result + this.day.hashCode(); 406: return result; 407: } 408: 409: /** 410: * Returns an integer indicating the order of this Minute object relative 411: * to the specified object: 412: * 413: * negative == before, zero == same, positive == after. 414: * 415: * @param o1 object to compare. 416: * 417: * @return negative == before, zero == same, positive == after. 418: */ 419: public int compareTo(Object o1) { 420: 421: int result; 422: 423: // CASE 1 : Comparing to another Minute object 424: // ------------------------------------------- 425: if (o1 instanceof Minute) { 426: Minute m = (Minute) o1; 427: result = getHour().compareTo(m.getHour()); 428: if (result == 0) { 429: result = this.minute - m.getMinute(); 430: } 431: } 432: 433: // CASE 2 : Comparing to another TimePeriod object 434: // ----------------------------------------------- 435: else if (o1 instanceof RegularTimePeriod) { 436: // more difficult case - evaluate later... 437: result = 0; 438: } 439: 440: // CASE 3 : Comparing to a non-TimePeriod object 441: // --------------------------------------------- 442: else { 443: // consider time periods to be ordered after general objects 444: result = 1; 445: } 446: 447: return result; 448: 449: } 450: 451: /** 452: * Creates a Minute instance by parsing a string. The string is assumed to 453: * be in the format "YYYY-MM-DD HH:MM", perhaps with leading or trailing 454: * whitespace. 455: * 456: * @param s the minute string to parse. 457: * 458: * @return <code>null</code>, if the string is not parseable, the minute 459: * otherwise. 460: */ 461: public static Minute parseMinute(String s) { 462: 463: Minute result = null; 464: s = s.trim(); 465: 466: String daystr = s.substring(0, Math.min(10, s.length())); 467: Day day = Day.parseDay(daystr); 468: if (day != null) { 469: String hmstr = s.substring( 470: Math.min(daystr.length() + 1, s.length()), s.length() 471: ); 472: hmstr = hmstr.trim(); 473: 474: String hourstr = hmstr.substring(0, Math.min(2, hmstr.length())); 475: int hour = Integer.parseInt(hourstr); 476: 477: if ((hour >= 0) && (hour <= 23)) { 478: String minstr = hmstr.substring( 479: Math.min(hourstr.length() + 1, hmstr.length()), 480: hmstr.length() 481: ); 482: int minute = Integer.parseInt(minstr); 483: if ((minute >= 0) && (minute <= 59)) { 484: result = new Minute(minute, new Hour(hour, day)); 485: } 486: } 487: } 488: 489: return result; 490: 491: } 492: 493: }