Source for org.jfree.data.time.Day

   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: }