Frames | No Frames |
1: /* =========================================================== 2: * JFreeChart : a free chart library for the Java(tm) platform 3: * =========================================================== 4: * 5: * (C) Copyright 2000-2005, 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: * Day.java 29: * -------- 30: * (C) Copyright 2001-2004, by Object Refinery Limited. 31: * 32: * Original Author: David Gilbert (for Object Refinery Limited); 33: * Contributor(s): -; 34: * 35: * $Id: Day.java,v 1.7.2.1 2005/10/25 21:35:24 mungady Exp $ 36: * 37: * Changes 38: * ------- 39: * 11-Oct-2001 : Version 1 (DG); 40: * 15-Nov-2001 : Updated Javadoc comments (DG); 41: * 04-Dec-2001 : Added static method to parse a string into a Day object (DG); 42: * 19-Dec-2001 : Added new constructor as suggested by Paul English (DG); 43: * 29-Jan-2002 : Changed getDay() method to getSerialDate() (DG); 44: * 26-Feb-2002 : Changed getStart(), getMiddle() and getEnd() methods to 45: * evaluate with reference to a particular time zone (DG); 46: * 19-Mar-2002 : Changed the API for the TimePeriod classes (DG); 47: * 29-May-2002 : Fixed bug in equals method (DG); 48: * 24-Jun-2002 : Removed unnecessary imports (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 (DG); 55: * 30-Sep-2004 : Replaced getTime().getTime() with getTimeInMillis() (DG); 56: * 04-Nov-2004 : Reverted change of 30-Sep-2004, because it won't work for 57: * JDK 1.3 (DG); 58: * 59: */ 60: 61: package org.jfree.data.time; 62: 63: import java.io.Serializable; 64: import java.text.DateFormat; 65: import java.text.ParseException; 66: import java.text.SimpleDateFormat; 67: import java.util.Calendar; 68: import java.util.Date; 69: import java.util.TimeZone; 70: 71: import org.jfree.date.SerialDate; 72: 73: /** 74: * Represents a single day in the range 1-Jan-1900 to 31-Dec-9999. This class 75: * is immutable, which is a requirement for all {@link RegularTimePeriod} 76: * subclasses. 77: */ 78: public class Day extends RegularTimePeriod implements Serializable { 79: 80: /** For serialization. */ 81: private static final long serialVersionUID = -7082667380758962755L; 82: 83: /** A standard date formatter. */ 84: protected static final DateFormat DATE_FORMAT 85: = new SimpleDateFormat("yyyy-MM-dd"); 86: 87: /** A date formatter for the default locale. */ 88: protected static final DateFormat 89: DATE_FORMAT_SHORT = DateFormat.getDateInstance(DateFormat.SHORT); 90: 91: /** A date formatter for the default locale. */ 92: protected static final DateFormat 93: DATE_FORMAT_MEDIUM = DateFormat.getDateInstance(DateFormat.MEDIUM); 94: 95: /** A date formatter for the default locale. */ 96: protected static final DateFormat 97: DATE_FORMAT_LONG = DateFormat.getDateInstance(DateFormat.LONG); 98: 99: /** The day (uses SerialDate for convenience). */ 100: private SerialDate serialDate; 101: 102: /** 103: * Creates a new instance, derived from the system date/time (and assuming 104: * the default timezone). 105: */ 106: public Day() { 107: this(new Date()); 108: } 109: 110: /** 111: * Constructs a new one day time period. 112: * 113: * @param day the day-of-the-month. 114: * @param month the month (1 to 12). 115: * @param year the year (1900 <= year <= 9999). 116: */ 117: public Day(int day, int month, int year) { 118: this.serialDate = SerialDate.createInstance(day, month, year); 119: } 120: 121: /** 122: * Constructs a new one day time period. 123: * 124: * @param serialDate the day (<code>null</code> not permitted). 125: */ 126: public Day(SerialDate serialDate) { 127: if (serialDate == null) { 128: throw new IllegalArgumentException("Null 'serialDate' argument."); 129: } 130: this.serialDate = serialDate; 131: } 132: 133: /** 134: * Constructs a new instance, based on a particular date/time and the 135: * default time zone. 136: * 137: * @param time the time (<code>null</code> not permitted). 138: */ 139: public Day(Date time) { 140: // defer argument checking... 141: this(time, RegularTimePeriod.DEFAULT_TIME_ZONE); 142: } 143: 144: /** 145: * Constructs a new instance, based on a particular date/time and time zone. 146: * 147: * @param time the date/time. 148: * @param zone the time zone. 149: */ 150: public Day(Date time, TimeZone zone) { 151: if (time == null) { 152: throw new IllegalArgumentException("Null 'time' argument."); 153: } 154: if (zone == null) { 155: throw new IllegalArgumentException("Null 'zone' argument."); 156: } 157: Calendar calendar = Calendar.getInstance(zone); 158: calendar.setTime(time); 159: int d = calendar.get(Calendar.DAY_OF_MONTH); 160: int m = calendar.get(Calendar.MONTH) + 1; 161: int y = calendar.get(Calendar.YEAR); 162: this.serialDate = SerialDate.createInstance(d, m, y); 163: } 164: 165: /** 166: * Returns the day as a {@link SerialDate}. Note: the reference that is 167: * returned should be an instance of an immutable {@link SerialDate} 168: * (otherwise the caller could use the reference to alter the state of 169: * this <code>Day</code> instance, and <code>Day</code> is supposed 170: * to be immutable). 171: * 172: * @return The day as a {@link SerialDate}. 173: */ 174: public SerialDate getSerialDate() { 175: return this.serialDate; 176: } 177: 178: /** 179: * Returns the year. 180: * 181: * @return The year. 182: */ 183: public int getYear() { 184: return this.serialDate.getYYYY(); 185: } 186: 187: /** 188: * Returns the month. 189: * 190: * @return The month. 191: */ 192: public int getMonth() { 193: return this.serialDate.getMonth(); 194: } 195: 196: /** 197: * Returns the day of the month. 198: * 199: * @return The day of the month. 200: */ 201: public int getDayOfMonth() { 202: return this.serialDate.getDayOfMonth(); 203: } 204: 205: /** 206: * Returns the day preceding this one. 207: * 208: * @return The day preceding this one. 209: */ 210: public RegularTimePeriod previous() { 211: 212: Day result; 213: int serial = this.serialDate.toSerial(); 214: if (serial > SerialDate.SERIAL_LOWER_BOUND) { 215: SerialDate yesterday = SerialDate.createInstance(serial - 1); 216: return new Day(yesterday); 217: } 218: else { 219: result = null; 220: } 221: return result; 222: 223: } 224: 225: /** 226: * Returns the day following this one, or <code>null</code> if some limit 227: * has been reached. 228: * 229: * @return The day following this one, or <code>null</code> if some limit 230: * has been reached. 231: */ 232: public RegularTimePeriod next() { 233: 234: Day result; 235: int serial = this.serialDate.toSerial(); 236: if (serial < SerialDate.SERIAL_UPPER_BOUND) { 237: SerialDate tomorrow = SerialDate.createInstance(serial + 1); 238: return new Day(tomorrow); 239: } 240: else { 241: result = null; 242: } 243: return result; 244: 245: } 246: 247: /** 248: * Returns a serial index number for the day. 249: * 250: * @return The serial index number. 251: */ 252: public long getSerialIndex() { 253: return this.serialDate.toSerial(); 254: } 255: 256: /** 257: * Returns the first millisecond of the day, evaluated using the supplied 258: * calendar (which determines the time zone). 259: * 260: * @param calendar calendar to use. 261: * 262: * @return The start of the day as milliseconds since 01-01-1970. 263: */ 264: public long getFirstMillisecond(Calendar calendar) { 265: 266: int year = this.serialDate.getYYYY(); 267: int month = this.serialDate.getMonth(); 268: int day = this.serialDate.getDayOfMonth(); 269: calendar.clear(); 270: calendar.set(year, month - 1, day, 0, 0, 0); 271: calendar.set(Calendar.MILLISECOND, 0); 272: //return calendar.getTimeInMillis(); // this won't work for JDK 1.3 273: return calendar.getTime().getTime(); 274: 275: } 276: 277: /** 278: * Returns the last millisecond of the day, evaluated using the supplied 279: * calendar (which determines the time zone). 280: * 281: * @param calendar calendar to use. 282: * 283: * @return The end of the day as milliseconds since 01-01-1970. 284: */ 285: public long getLastMillisecond(Calendar calendar) { 286: 287: int year = this.serialDate.getYYYY(); 288: int month = this.serialDate.getMonth(); 289: int day = this.serialDate.getDayOfMonth(); 290: calendar.clear(); 291: calendar.set(year, month - 1, day, 23, 59, 59); 292: calendar.set(Calendar.MILLISECOND, 999); 293: //return calendar.getTimeInMillis(); // this won't work for JDK 1.3 294: return calendar.getTime().getTime(); 295: 296: } 297: 298: /** 299: * Tests the equality of this Day object to an arbitrary object. Returns 300: * true if the target is a Day instance or a SerialDate instance 301: * representing the same day as this object. In all other cases, 302: * returns false. 303: * 304: * @param obj the object. 305: * 306: * @return A flag indicating whether or not an object is equal to this day. 307: */ 308: public boolean equals(Object obj) { 309: 310: if (obj == this) { 311: return true; 312: } 313: if (!(obj instanceof Day)) { 314: return false; 315: } 316: Day that = (Day) obj; 317: if (!this.serialDate.equals(that.getSerialDate())) { 318: return false; 319: } 320: return true; 321: 322: } 323: 324: /** 325: * Returns a hash code for this object instance. The approach described by 326: * Joshua Bloch in "Effective Java" has been used here: 327: * <p> 328: * <code>http://developer.java.sun.com/developer/Books/effectivejava 329: * /Chapter3.pdf</code> 330: * 331: * @return A hash code. 332: */ 333: public int hashCode() { 334: return this.serialDate.hashCode(); 335: } 336: 337: /** 338: * Returns an integer indicating the order of this Day object relative to 339: * the specified object: 340: * 341: * negative == before, zero == same, positive == after. 342: * 343: * @param o1 the object to compare. 344: * 345: * @return negative == before, zero == same, positive == after. 346: */ 347: public int compareTo(Object o1) { 348: 349: int result; 350: 351: // CASE 1 : Comparing to another Day object 352: // ---------------------------------------- 353: if (o1 instanceof Day) { 354: Day d = (Day) o1; 355: result = -d.getSerialDate().compare(this.serialDate); 356: } 357: 358: // CASE 2 : Comparing to another TimePeriod object 359: // ----------------------------------------------- 360: else if (o1 instanceof RegularTimePeriod) { 361: // more difficult case - evaluate later... 362: result = 0; 363: } 364: 365: // CASE 3 : Comparing to a non-TimePeriod object 366: // --------------------------------------------- 367: else { 368: // consider time periods to be ordered after general objects 369: result = 1; 370: } 371: 372: return result; 373: 374: } 375: 376: /** 377: * Returns a string representing the day. 378: * 379: * @return A string representing the day. 380: */ 381: public String toString() { 382: return this.serialDate.toString(); 383: } 384: 385: /** 386: * Parses the string argument as a day. 387: * <P> 388: * This method is required to recognise YYYY-MM-DD as a valid format. 389: * Anything else, for now, is a bonus. 390: * 391: * @param s the date string to parse. 392: * 393: * @return <code>null</code> if the string does not contain any parseable 394: * string, the day otherwise. 395: */ 396: public static Day parseDay(String s) { 397: 398: try { 399: return new Day (Day.DATE_FORMAT.parse(s)); 400: } 401: catch (ParseException e1) { 402: try { 403: return new Day (Day.DATE_FORMAT_SHORT.parse(s)); 404: } 405: catch (ParseException e2) { 406: // ignore 407: } 408: } 409: return null; 410: 411: } 412: 413: }