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