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): Chris Boek; 034 * 035 * Changes 036 * ------- 037 * 08-Nov-2002 : Moved to new package com.jrefinery.chart.axis (DG); 038 * 27-Nov-2002 : Added IllegalArgumentException to getMillisecondCount() 039 * method (DG); 040 * 26-Mar-2003 : Implemented Serializable (DG); 041 * 12-Nov-2003 : Added roll fields that can improve the labelling on segmented 042 * date axes (DG); 043 * 03-Dec-2003 : DateFormat constructor argument is now filled with an default 044 * if null (TM); 045 * 07-Dec-2003 : Fixed bug (null pointer exception) in constructor (DG); 046 * ------------- JFREECHART 1.0.x --------------------------------------------- 047 * 21-Mar-2007 : Added toString() for debugging (DG); 048 * 04-Apr-2007 : Added new methods addToDate(Date, TimeZone) and rollDate(Date, 049 * TimeZone) (CB); 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 import java.util.TimeZone; 060 061 import org.jfree.util.ObjectUtilities; 062 063 /** 064 * A tick unit for use by subclasses of {@link DateAxis}. Instances of this 065 * class are immutable. 066 */ 067 public class DateTickUnit extends TickUnit implements Serializable { 068 069 /** For serialization. */ 070 private static final long serialVersionUID = -7289292157229621901L; 071 072 /** A constant for years. */ 073 public static final int YEAR = 0; 074 075 /** A constant for months. */ 076 public static final int MONTH = 1; 077 078 /** A constant for days. */ 079 public static final int DAY = 2; 080 081 /** A constant for hours. */ 082 public static final int HOUR = 3; 083 084 /** A constant for minutes. */ 085 public static final int MINUTE = 4; 086 087 /** A constant for seconds. */ 088 public static final int SECOND = 5; 089 090 /** A constant for milliseconds. */ 091 public static final int MILLISECOND = 6; 092 093 /** The unit. */ 094 private int unit; 095 096 /** The unit count. */ 097 private int count; 098 099 /** 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 }