001 /* =========================================================== 002 * JFreeChart : a free chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C) Copyright 2000-2007, by Object Refinery Limited and Contributors. 006 * 007 * Project Info: http://www.jfree.org/jfreechart/index.html 008 * 009 * This library is free software; you can redistribute it and/or modify it 010 * under the terms of the GNU Lesser General Public License as published by 011 * the Free Software Foundation; either version 2.1 of the License, or 012 * (at your option) any later version. 013 * 014 * This library is distributed in the hope that it will be useful, but 015 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 016 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 017 * License for more details. 018 * 019 * You should have received a copy of the GNU Lesser General Public 020 * License along with this library; if not, write to the Free Software 021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 022 * USA. 023 * 024 * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 025 * in the United States and other countries.] 026 * 027 * ----------------- 028 * DateTickUnit.java 029 * ----------------- 030 * (C) Copyright 2000-2007, by Object Refinery Limited. 031 * 032 * Original Author: David Gilbert (for Object Refinery Limited); 033 * Contributor(s): -; 034 * 035 * $Id: DateTickUnit.java,v 1.7.2.2 2007/03/21 10:07:47 mungady Exp $ 036 * 037 * Changes (from 8-Nov-2002) 038 * -------------------------- 039 * 08-Nov-2002 : Moved to new package com.jrefinery.chart.axis (DG); 040 * 27-Nov-2002 : Added IllegalArgumentException to getMillisecondCount() 041 * method (DG); 042 * 26-Mar-2003 : Implemented Serializable (DG); 043 * 12-Nov-2003 : Added roll fields that can improve the labelling on segmented 044 * date axes (DG); 045 * 03-Dec-2003 : DateFormat constructor argument is now filled with an default 046 * if null (TM); 047 * 07-Dec-2003 : Fixed bug (null pointer exception) in constructor (DG); 048 * ------------- JFREECHART 1.0.x --------------------------------------------- 049 * 21-Mar-2007 : Added toString() for debugging (DG); 050 * 051 */ 052 053 package org.jfree.chart.axis; 054 055 import java.io.Serializable; 056 import java.text.DateFormat; 057 import java.util.Calendar; 058 import java.util.Date; 059 060 import org.jfree.util.ObjectUtilities; 061 062 /** 063 * A tick unit for use by subclasses of {@link DateAxis}. Instances of this 064 * class are immutable. 065 */ 066 public class DateTickUnit extends TickUnit implements Serializable { 067 068 /** For serialization. */ 069 private static final long serialVersionUID = -7289292157229621901L; 070 071 /** A constant for years. */ 072 public static final int YEAR = 0; 073 074 /** A constant for months. */ 075 public static final int MONTH = 1; 076 077 /** A constant for days. */ 078 public static final int DAY = 2; 079 080 /** A constant for hours. */ 081 public static final int HOUR = 3; 082 083 /** A constant for minutes. */ 084 public static final int MINUTE = 4; 085 086 /** A constant for seconds. */ 087 public static final int SECOND = 5; 088 089 /** A constant for milliseconds. */ 090 public static final int MILLISECOND = 6; 091 092 /** The unit. */ 093 private int unit; 094 095 /** The unit count. */ 096 private int count; 097 098 /** The roll unit. */ 099 private int rollUnit; 100 101 /** The roll count. */ 102 private int rollCount; 103 104 /** The date formatter. */ 105 private DateFormat formatter; 106 107 /** 108 * Creates a new date tick unit. The dates will be formatted using a 109 * SHORT format for the default locale. 110 * 111 * @param unit the unit. 112 * @param count the unit count. 113 */ 114 public DateTickUnit(int unit, int count) { 115 this(unit, count, null); 116 } 117 118 /** 119 * Creates a new date tick unit. You can specify the units using one of 120 * the constants YEAR, MONTH, DAY, HOUR, MINUTE, SECOND or MILLISECOND. 121 * In addition, you can specify a unit count, and a date format. 122 * 123 * @param unit the unit. 124 * @param count the unit count. 125 * @param formatter the date formatter (defaults to DateFormat.SHORT). 126 */ 127 public DateTickUnit(int unit, int count, DateFormat formatter) { 128 129 this(unit, count, unit, count, formatter); 130 131 } 132 133 /** 134 * Creates a new unit. 135 * 136 * @param unit the unit. 137 * @param count the count. 138 * @param rollUnit the roll unit. 139 * @param rollCount the roll count. 140 * @param formatter the date formatter (defaults to DateFormat.SHORT). 141 */ 142 public DateTickUnit(int unit, int count, int rollUnit, int rollCount, 143 DateFormat formatter) { 144 super(DateTickUnit.getMillisecondCount(unit, count)); 145 this.unit = unit; 146 this.count = count; 147 this.rollUnit = rollUnit; 148 this.rollCount = rollCount; 149 this.formatter = formatter; 150 if (formatter == null) { 151 this.formatter = DateFormat.getDateInstance(DateFormat.SHORT); 152 } 153 } 154 155 /** 156 * Returns the date unit. This will be one of the constants 157 * <code>YEAR</code>, <code>MONTH</code>, <code>DAY</code>, 158 * <code>HOUR</code>, <code>MINUTE</code>, <code>SECOND</code> or 159 * <code>MILLISECOND</code>, defined by this class. Note that these 160 * constants do NOT correspond to those defined in Java's 161 * <code>Calendar</code> class. 162 * 163 * @return The date unit. 164 */ 165 public int getUnit() { 166 return this.unit; 167 } 168 169 /** 170 * Returns the unit count. 171 * 172 * @return The unit count. 173 */ 174 public int getCount() { 175 return this.count; 176 } 177 178 /** 179 * Returns the roll unit. This is the amount by which the tick advances if 180 * it is "hidden" when displayed on a segmented date axis. Typically the 181 * roll will be smaller than the regular tick unit (for example, a 7 day 182 * tick unit might use a 1 day roll). 183 * 184 * @return The roll unit. 185 */ 186 public int getRollUnit() { 187 return this.rollUnit; 188 } 189 190 /** 191 * Returns the roll count. 192 * 193 * @return The roll count. 194 */ 195 public int getRollCount() { 196 return this.rollCount; 197 } 198 199 /** 200 * Formats a value. 201 * 202 * @param milliseconds date in milliseconds since 01-01-1970. 203 * 204 * @return The formatted date. 205 */ 206 public String valueToString(double milliseconds) { 207 return this.formatter.format(new Date((long) milliseconds)); 208 } 209 210 /** 211 * Formats a date using the tick unit's formatter. 212 * 213 * @param date the date. 214 * 215 * @return The formatted date. 216 */ 217 public String dateToString(Date date) { 218 return this.formatter.format(date); 219 } 220 221 /** 222 * Calculates a new date by adding this unit to the base date. 223 * 224 * @param base the base date. 225 * 226 * @return A new date one unit after the base date. 227 */ 228 public Date addToDate(Date base) { 229 230 Calendar calendar = Calendar.getInstance(); 231 calendar.setTime(base); 232 calendar.add(getCalendarField(this.unit), this.count); 233 return calendar.getTime(); 234 235 } 236 237 /** 238 * Rolls the date forward by the amount specified by the roll unit and 239 * count. 240 * 241 * @param base the base date. 242 243 * @return The rolled date. 244 */ 245 public Date rollDate(Date base) { 246 Calendar calendar = Calendar.getInstance(); 247 calendar.setTime(base); 248 calendar.add(getCalendarField(this.rollUnit), this.rollCount); 249 return calendar.getTime(); 250 } 251 252 /** 253 * Returns a field code that can be used with the <code>Calendar</code> 254 * class. 255 * 256 * @return The field code. 257 */ 258 public int getCalendarField() { 259 return getCalendarField(this.unit); 260 } 261 262 /** 263 * Returns a field code (that can be used with the Calendar class) for a 264 * given 'unit' code. The 'unit' is one of: {@link #YEAR}, {@link #MONTH}, 265 * {@link #DAY}, {@link #HOUR}, {@link #MINUTE}, {@link #SECOND} and 266 * {@link #MILLISECOND}. 267 * 268 * @param tickUnit the unit. 269 * 270 * @return The field code. 271 */ 272 private int getCalendarField(int tickUnit) { 273 274 switch (tickUnit) { 275 case (YEAR): 276 return Calendar.YEAR; 277 case (MONTH): 278 return Calendar.MONTH; 279 case (DAY): 280 return Calendar.DATE; 281 case (HOUR): 282 return Calendar.HOUR_OF_DAY; 283 case (MINUTE): 284 return Calendar.MINUTE; 285 case (SECOND): 286 return Calendar.SECOND; 287 case (MILLISECOND): 288 return Calendar.MILLISECOND; 289 default: 290 return Calendar.MILLISECOND; 291 } 292 293 } 294 295 /** 296 * Returns the (approximate) number of milliseconds for the given unit and 297 * unit count. 298 * <P> 299 * This value is an approximation some of the time (e.g. months are 300 * assumed to have 31 days) but this shouldn't matter. 301 * 302 * @param unit the unit. 303 * @param count the unit count. 304 * 305 * @return The number of milliseconds. 306 */ 307 private static long getMillisecondCount(int unit, int count) { 308 309 switch (unit) { 310 case (YEAR): 311 return (365L * 24L * 60L * 60L * 1000L) * count; 312 case (MONTH): 313 return (31L * 24L * 60L * 60L * 1000L) * count; 314 case (DAY): 315 return (24L * 60L * 60L * 1000L) * count; 316 case (HOUR): 317 return (60L * 60L * 1000L) * count; 318 case (MINUTE): 319 return (60L * 1000L) * count; 320 case (SECOND): 321 return 1000L * count; 322 case (MILLISECOND): 323 return count; 324 default: 325 throw new IllegalArgumentException( 326 "DateTickUnit.getMillisecondCount() : unit must " 327 + "be one of the constants YEAR, MONTH, DAY, HOUR, MINUTE, " 328 + "SECOND or MILLISECOND defined in the DateTickUnit " 329 + "class. Do *not* use the constants defined in " 330 + "java.util.Calendar." 331 ); 332 } 333 334 } 335 336 /** 337 * Tests this unit for equality with another object. 338 * 339 * @param obj the object (<code>null</code> permitted). 340 * 341 * @return <code>true</code> or <code>false</code>. 342 */ 343 public boolean equals(Object obj) { 344 if (obj == this) { 345 return true; 346 } 347 if (!(obj instanceof DateTickUnit)) { 348 return false; 349 } 350 if (!super.equals(obj)) { 351 return false; 352 } 353 DateTickUnit that = (DateTickUnit) obj; 354 if (this.unit != that.unit) { 355 return false; 356 } 357 if (this.count != that.count) { 358 return false; 359 } 360 if (!ObjectUtilities.equal(this.formatter, that.formatter)) { 361 return false; 362 } 363 return true; 364 } 365 366 /** 367 * Returns a hash code for this object. 368 * 369 * @return A hash code. 370 */ 371 public int hashCode() { 372 int result = 19; 373 result = 37 * result + this.unit; 374 result = 37 * result + this.count; 375 result = 37 * result + this.formatter.hashCode(); 376 return result; 377 } 378 379 /** 380 * Strings for use by the toString() method. 381 */ 382 private static final String[] units = {"YEAR", "MONTH", "DAY", "HOUR", 383 "MINUTE", "SECOND", "MILLISECOND"}; 384 385 /** 386 * Returns a string representation of this instance, primarily used for 387 * debugging purposes. 388 * 389 * @return A string representation of this instance. 390 */ 391 public String toString() { 392 return "DateTickUnit[" + DateTickUnit.units[this.unit] + ", " 393 + this.count + "]"; 394 } 395 396 }