Source for org.jfree.chart.axis.DateTickUnit

   1: /* ===========================================================
   2:  * JFreeChart : a free chart library for the Java(tm) platform
   3:  * ===========================================================
   4:  *
   5:  * (C) Copyright 2000-2008, 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:  * DateTickUnit.java
  29:  * -----------------
  30:  * (C) Copyright 2000-2008, by Object Refinery Limited.
  31:  *
  32:  * Original Author:  David Gilbert (for Object Refinery Limited);
  33:  * Contributor(s):   Chris Boek;
  34:  *
  35:  * Changes
  36:  * -------
  37:  * 08-Nov-2002 : Moved to new package com.jrefinery.chart.axis (DG);
  38:  * 27-Nov-2002 : Added IllegalArgumentException to getMillisecondCount()
  39:  *               method (DG);
  40:  * 26-Mar-2003 : Implemented Serializable (DG);
  41:  * 12-Nov-2003 : Added roll fields that can improve the labelling on segmented
  42:  *               date axes (DG);
  43:  * 03-Dec-2003 : DateFormat constructor argument is now filled with an default
  44:  *               if null (TM);
  45:  * 07-Dec-2003 : Fixed bug (null pointer exception) in constructor (DG);
  46:  * ------------- JFREECHART 1.0.x ---------------------------------------------
  47:  * 21-Mar-2007 : Added toString() for debugging (DG);
  48:  * 04-Apr-2007 : Added new methods addToDate(Date, TimeZone) and rollDate(Date,
  49:  *               TimeZone) (CB);
  50:  * 09-Jun-2008 : Deprecated addToDate(Date) (DG);
  51:  *
  52:  */
  53: 
  54: package org.jfree.chart.axis;
  55: 
  56: import java.io.Serializable;
  57: import java.text.DateFormat;
  58: import java.util.Calendar;
  59: import java.util.Date;
  60: import java.util.TimeZone;
  61: 
  62: import org.jfree.util.ObjectUtilities;
  63: 
  64: /**
  65:  * A tick unit for use by subclasses of {@link DateAxis}. Instances of this
  66:  * class are immutable.
  67:  */
  68: public class DateTickUnit extends TickUnit implements Serializable {
  69: 
  70:     /** For serialization. */
  71:     private static final long serialVersionUID = -7289292157229621901L;
  72: 
  73:     /** A constant for years. */
  74:     public static final int YEAR = 0;
  75: 
  76:     /** A constant for months. */
  77:     public static final int MONTH = 1;
  78: 
  79:     /** A constant for days. */
  80:     public static final int DAY = 2;
  81: 
  82:     /** A constant for hours. */
  83:     public static final int HOUR = 3;
  84: 
  85:     /** A constant for minutes. */
  86:     public static final int MINUTE = 4;
  87: 
  88:     /** A constant for seconds. */
  89:     public static final int SECOND = 5;
  90: 
  91:     /** A constant for milliseconds. */
  92:     public static final int MILLISECOND = 6;
  93: 
  94:     /** The unit. */
  95:     private int unit;
  96: 
  97:     /** The unit count. */
  98:     private int count;
  99: 
 100:     /** The roll unit. */
 101:     private int rollUnit;
 102: 
 103:     /** The roll count. */
 104:     private int rollCount;
 105: 
 106:     /** The date formatter. */
 107:     private DateFormat formatter;
 108: 
 109:     /**
 110:      * Creates a new date tick unit.  The dates will be formatted using a
 111:      * SHORT format for the default locale.
 112:      *
 113:      * @param unit  the unit.
 114:      * @param count  the unit count.
 115:      */
 116:     public DateTickUnit(int unit, int count) {
 117:         this(unit, count, null);
 118:     }
 119: 
 120:     /**
 121:      * Creates a new date tick unit.  You can specify the units using one of
 122:      * the constants YEAR, MONTH, DAY, HOUR, MINUTE, SECOND or MILLISECOND.
 123:      * In addition, you can specify a unit count, and a date format.
 124:      *
 125:      * @param unit  the unit.
 126:      * @param count  the unit count.
 127:      * @param formatter  the date formatter (defaults to DateFormat.SHORT).
 128:      */
 129:     public DateTickUnit(int unit, int count, DateFormat formatter) {
 130: 
 131:         this(unit, count, unit, count, formatter);
 132: 
 133:     }
 134: 
 135:     /**
 136:      * Creates a new unit.
 137:      *
 138:      * @param unit  the unit.
 139:      * @param count  the count.
 140:      * @param rollUnit  the roll unit.
 141:      * @param rollCount  the roll count.
 142:      * @param formatter  the date formatter (defaults to DateFormat.SHORT).
 143:      */
 144:     public DateTickUnit(int unit, int count, int rollUnit, int rollCount,
 145:                         DateFormat formatter) {
 146:         super(DateTickUnit.getMillisecondCount(unit, count));
 147:         this.unit = unit;
 148:         this.count = count;
 149:         this.rollUnit = rollUnit;
 150:         this.rollCount = rollCount;
 151:         this.formatter = formatter;
 152:         if (formatter == null) {
 153:             this.formatter = DateFormat.getDateInstance(DateFormat.SHORT);
 154:         }
 155:     }
 156: 
 157:     /**
 158:      * Returns the date unit.  This will be one of the constants
 159:      * <code>YEAR</code>, <code>MONTH</code>, <code>DAY</code>,
 160:      * <code>HOUR</code>, <code>MINUTE</code>, <code>SECOND</code> or
 161:      * <code>MILLISECOND</code>, defined by this class.  Note that these
 162:      * constants do NOT correspond to those defined in Java's
 163:      * <code>Calendar</code> class.
 164:      *
 165:      * @return The date unit.
 166:      */
 167:     public int getUnit() {
 168:         return this.unit;
 169:     }
 170: 
 171:     /**
 172:      * Returns the unit count.
 173:      *
 174:      * @return The unit count.
 175:      */
 176:     public int getCount() {
 177:         return this.count;
 178:     }
 179: 
 180:     /**
 181:      * Returns the roll unit.  This is the amount by which the tick advances if
 182:      * it is "hidden" when displayed on a segmented date axis.  Typically the
 183:      * roll will be smaller than the regular tick unit (for example, a 7 day
 184:      * tick unit might use a 1 day roll).
 185:      *
 186:      * @return The roll unit.
 187:      */
 188:     public int getRollUnit() {
 189:         return this.rollUnit;
 190:     }
 191: 
 192:     /**
 193:      * Returns the roll count.
 194:      *
 195:      * @return The roll count.
 196:      */
 197:     public int getRollCount() {
 198:         return this.rollCount;
 199:     }
 200: 
 201:     /**
 202:      * Formats a value.
 203:      *
 204:      * @param milliseconds  date in milliseconds since 01-01-1970.
 205:      *
 206:      * @return The formatted date.
 207:      */
 208:     public String valueToString(double milliseconds) {
 209:         return this.formatter.format(new Date((long) milliseconds));
 210:     }
 211: 
 212:     /**
 213:      * Formats a date using the tick unit's formatter.
 214:      *
 215:      * @param date  the date.
 216:      *
 217:      * @return The formatted date.
 218:      */
 219:     public String dateToString(Date date) {
 220:         return this.formatter.format(date);
 221:     }
 222: 
 223:     /**
 224:      * Calculates a new date by adding this unit to the base date, with
 225:      * calculations performed in the default timezone and locale.
 226:      *
 227:      * @param base  the base date.
 228:      *
 229:      * @return A new date one unit after the base date.
 230:      *
 231:      * @see #addToDate(Date, TimeZone)
 232:      *
 233:      * @deprecated As of JFreeChart 1.0.10, this method is deprecated - you
 234:      *     should use {@link #addToDate(Date, TimeZone)} instead.
 235:      */
 236:     public Date addToDate(Date base) {
 237:         return addToDate(base, TimeZone.getDefault());
 238:     }
 239: 
 240:     /**
 241:      * Calculates a new date by adding this unit to the base date.
 242:      *
 243:      * @param base  the base date.
 244:      * @param zone  the time zone for the date calculation.
 245:      *
 246:      * @return A new date one unit after the base date.
 247:      *
 248:      * @since 1.0.6
 249:      */
 250:     public Date addToDate(Date base, TimeZone zone) {
 251:         // as far as I know, the Locale for the calendar only affects week
 252:         // number calculations, and since DateTickUnit doesn't do week
 253:         // arithmetic, the default locale (whatever it is) should be fine
 254:         // here...
 255:         Calendar calendar = Calendar.getInstance(zone);
 256:         calendar.setTime(base);
 257:         calendar.add(getCalendarField(this.unit), this.count);
 258:         return calendar.getTime();
 259:     }
 260: 
 261:     /**
 262:      * Rolls the date forward by the amount specified by the roll unit and
 263:      * count.
 264:      *
 265:      * @param base  the base date.
 266: 
 267:      * @return The rolled date.
 268:      *
 269:      * @see #rollDate(Date, TimeZone)
 270:      */
 271:     public Date rollDate(Date base) {
 272:         return rollDate(base, TimeZone.getDefault());
 273:     }
 274: 
 275:     /**
 276:      * Rolls the date forward by the amount specified by the roll unit and
 277:      * count.
 278:      *
 279:      * @param base  the base date.
 280:      * @param zone  the time zone.
 281:      *
 282:      * @return The rolled date.
 283:      *
 284:      * @since 1.0.6
 285:      */
 286:     public Date rollDate(Date base, TimeZone zone) {
 287:         // as far as I know, the Locale for the calendar only affects week
 288:         // number calculations, and since DateTickUnit doesn't do week
 289:         // arithmetic, the default locale (whatever it is) should be fine
 290:         // here...
 291:         Calendar calendar = Calendar.getInstance(zone);
 292:         calendar.setTime(base);
 293:         calendar.add(getCalendarField(this.rollUnit), this.rollCount);
 294:         return calendar.getTime();
 295:     }
 296: 
 297:     /**
 298:      * Returns a field code that can be used with the <code>Calendar</code>
 299:      * class.
 300:      *
 301:      * @return The field code.
 302:      */
 303:     public int getCalendarField() {
 304:         return getCalendarField(this.unit);
 305:     }
 306: 
 307:     /**
 308:      * Returns a field code (that can be used with the Calendar class) for a
 309:      * given 'unit' code.  The 'unit' is one of:  {@link #YEAR}, {@link #MONTH},
 310:      * {@link #DAY}, {@link #HOUR}, {@link #MINUTE}, {@link #SECOND} and
 311:      * {@link #MILLISECOND}.
 312:      *
 313:      * @param tickUnit  the unit.
 314:      *
 315:      * @return The field code.
 316:      */
 317:     private int getCalendarField(int tickUnit) {
 318: 
 319:         switch (tickUnit) {
 320:             case (YEAR):
 321:                 return Calendar.YEAR;
 322:             case (MONTH):
 323:                 return Calendar.MONTH;
 324:             case (DAY):
 325:                 return Calendar.DATE;
 326:             case (HOUR):
 327:                 return Calendar.HOUR_OF_DAY;
 328:             case (MINUTE):
 329:                 return Calendar.MINUTE;
 330:             case (SECOND):
 331:                 return Calendar.SECOND;
 332:             case (MILLISECOND):
 333:                 return Calendar.MILLISECOND;
 334:             default:
 335:                 return Calendar.MILLISECOND;
 336:         }
 337: 
 338:     }
 339: 
 340:     /**
 341:      * Returns the (approximate) number of milliseconds for the given unit and
 342:      * unit count.
 343:      * <P>
 344:      * This value is an approximation some of the time (e.g. months are
 345:      * assumed to have 31 days) but this shouldn't matter.
 346:      *
 347:      * @param unit  the unit.
 348:      * @param count  the unit count.
 349:      *
 350:      * @return The number of milliseconds.
 351:      */
 352:     private static long getMillisecondCount(int unit, int count) {
 353: 
 354:         switch (unit) {
 355:             case (YEAR):
 356:                 return (365L * 24L * 60L * 60L * 1000L) * count;
 357:             case (MONTH):
 358:                 return (31L * 24L * 60L * 60L * 1000L) * count;
 359:             case (DAY):
 360:                 return (24L * 60L * 60L * 1000L) * count;
 361:             case (HOUR):
 362:                 return (60L * 60L * 1000L) * count;
 363:             case (MINUTE):
 364:                 return (60L * 1000L) * count;
 365:             case (SECOND):
 366:                 return 1000L * count;
 367:             case (MILLISECOND):
 368:                 return count;
 369:             default:
 370:                 throw new IllegalArgumentException(
 371:                     "DateTickUnit.getMillisecondCount() : unit must "
 372:                     + "be one of the constants YEAR, MONTH, DAY, HOUR, MINUTE, "
 373:                     + "SECOND or MILLISECOND defined in the DateTickUnit "
 374:                     + "class. Do *not* use the constants defined in "
 375:                     + "java.util.Calendar."
 376:                 );
 377:         }
 378: 
 379:     }
 380: 
 381:     /**
 382:      * Tests this unit for equality with another object.
 383:      *
 384:      * @param obj  the object (<code>null</code> permitted).
 385:      *
 386:      * @return <code>true</code> or <code>false</code>.
 387:      */
 388:     public boolean equals(Object obj) {
 389:         if (obj == this) {
 390:             return true;
 391:         }
 392:         if (!(obj instanceof DateTickUnit)) {
 393:             return false;
 394:         }
 395:         if (!super.equals(obj)) {
 396:             return false;
 397:         }
 398:         DateTickUnit that = (DateTickUnit) obj;
 399:         if (this.unit != that.unit) {
 400:             return false;
 401:         }
 402:         if (this.count != that.count) {
 403:             return false;
 404:         }
 405:         if (!ObjectUtilities.equal(this.formatter, that.formatter)) {
 406:             return false;
 407:         }
 408:         return true;
 409:     }
 410: 
 411:     /**
 412:      * Returns a hash code for this object.
 413:      *
 414:      * @return A hash code.
 415:      */
 416:     public int hashCode() {
 417:         int result = 19;
 418:         result = 37 * result + this.unit;
 419:         result = 37 * result + this.count;
 420:         result = 37 * result + this.formatter.hashCode();
 421:         return result;
 422:     }
 423: 
 424:     /**
 425:      * Strings for use by the toString() method.
 426:      */
 427:     private static final String[] units = {"YEAR", "MONTH", "DAY", "HOUR",
 428:             "MINUTE", "SECOND", "MILLISECOND"};
 429: 
 430:     /**
 431:      * Returns a string representation of this instance, primarily used for
 432:      * debugging purposes.
 433:      *
 434:      * @return A string representation of this instance.
 435:      */
 436:     public String toString() {
 437:         return "DateTickUnit[" + DateTickUnit.units[this.unit] + ", "
 438:                 + this.count + "]";
 439:     }
 440: 
 441: }