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