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