001 /* =========================================================== 002 * JFreeChart : a free chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C) Copyright 2000-2005, 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-2005, 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.1 2005/10/25 20:37:34 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 * 049 */ 050 051 package org.jfree.chart.axis; 052 053 import java.io.Serializable; 054 import java.text.DateFormat; 055 import java.util.Calendar; 056 import java.util.Date; 057 058 import org.jfree.util.ObjectUtilities; 059 060 /** 061 * A tick unit for use by subclasses of {@link DateAxis}. 062 * <p> 063 * Instances of this class are immutable. 064 */ 065 public class DateTickUnit extends TickUnit implements Serializable { 066 067 /** For serialization. */ 068 private static final long serialVersionUID = -7289292157229621901L; 069 070 /** A constant for years. */ 071 public static final int YEAR = 0; 072 073 /** A constant for months. */ 074 public static final int MONTH = 1; 075 076 /** A constant for days. */ 077 public static final int DAY = 2; 078 079 /** A constant for hours. */ 080 public static final int HOUR = 3; 081 082 /** A constant for minutes. */ 083 public static final int MINUTE = 4; 084 085 /** A constant for seconds. */ 086 public static final int SECOND = 5; 087 088 /** A constant for milliseconds. */ 089 public static final int MILLISECOND = 6; 090 091 /** The unit. */ 092 private int unit; 093 094 /** The unit count. */ 095 private int count; 096 097 /** The roll unit. */ 098 private int rollUnit; 099 100 /** The roll count. */ 101 private int rollCount; 102 103 /** The date formatter. */ 104 private DateFormat formatter; 105 106 /** 107 * Creates a new date tick unit. The dates will be formatted using a 108 * SHORT format for the default locale. 109 * 110 * @param unit the unit. 111 * @param count the unit count. 112 */ 113 public DateTickUnit(int unit, int count) { 114 this(unit, count, null); 115 } 116 117 /** 118 * Creates a new date tick unit. You can specify the units using one of 119 * the constants YEAR, MONTH, DAY, HOUR, MINUTE, SECOND or MILLISECOND. 120 * In addition, you can specify a unit count, and a date format. 121 * 122 * @param unit the unit. 123 * @param count the unit count. 124 * @param formatter the date formatter (defaults to DateFormat.SHORT). 125 */ 126 public DateTickUnit(int unit, int count, DateFormat formatter) { 127 128 this(unit, count, unit, count, formatter); 129 130 } 131 132 /** 133 * Creates a new unit. 134 * 135 * @param unit the unit. 136 * @param count the count. 137 * @param rollUnit the roll unit. 138 * @param rollCount the roll count. 139 * @param formatter the date formatter (defaults to DateFormat.SHORT). 140 */ 141 public DateTickUnit(int unit, int count, int rollUnit, int rollCount, 142 DateFormat formatter) { 143 super(DateTickUnit.getMillisecondCount(unit, count)); 144 this.unit = unit; 145 this.count = count; 146 this.rollUnit = rollUnit; 147 this.rollCount = rollCount; 148 this.formatter = formatter; 149 if (formatter == null) { 150 this.formatter = DateFormat.getDateInstance(DateFormat.SHORT); 151 } 152 } 153 154 /** 155 * Returns the date unit. This will be one of the constants 156 * <code>YEAR</code>, <code>MONTH</code>, <code>DAY</code>, 157 * <code>HOUR</code>, <code>MINUTE</code>, <code>SECOND</code> or 158 * <code>MILLISECOND</code>, defined by this class. Note that these 159 * constants do NOT correspond to those defined in Java's 160 * <code>Calendar</code> class. 161 * 162 * @return The date unit. 163 */ 164 public int getUnit() { 165 return this.unit; 166 } 167 168 /** 169 * Returns the unit count. 170 * 171 * @return The unit count. 172 */ 173 public int getCount() { 174 return this.count; 175 } 176 177 /** 178 * Returns the roll unit. This is the amount by which the tick advances if 179 * it is "hidden" when displayed on a segmented date axis. Typically the 180 * roll will be smaller than the regular tick unit (for example, a 7 day 181 * tick unit might use a 1 day roll). 182 * 183 * @return The roll unit. 184 */ 185 public int getRollUnit() { 186 return this.rollUnit; 187 } 188 189 /** 190 * Returns the roll count. 191 * 192 * @return The roll count. 193 */ 194 public int getRollCount() { 195 return this.rollCount; 196 } 197 198 /** 199 * Formats a value. 200 * 201 * @param milliseconds date in milliseconds since 01-01-1970. 202 * 203 * @return The formatted date. 204 */ 205 public String valueToString(double milliseconds) { 206 return this.formatter.format(new Date((long) milliseconds)); 207 } 208 209 /** 210 * Formats a date using the tick unit's formatter. 211 * 212 * @param date the date. 213 * 214 * @return The formatted date. 215 */ 216 public String dateToString(Date date) { 217 return this.formatter.format(date); 218 } 219 220 /** 221 * Calculates a new date by adding this unit to the base date. 222 * 223 * @param base the base date. 224 * 225 * @return A new date one unit after the base date. 226 */ 227 public Date addToDate(Date base) { 228 229 Calendar calendar = Calendar.getInstance(); 230 calendar.setTime(base); 231 calendar.add(getCalendarField(this.unit), this.count); 232 return calendar.getTime(); 233 234 } 235 236 /** 237 * Rolls the date forward by the amount specified by the roll unit and 238 * count. 239 * 240 * @param base the base date. 241 242 * @return The rolled date. 243 */ 244 public Date rollDate(Date base) { 245 Calendar calendar = Calendar.getInstance(); 246 calendar.setTime(base); 247 calendar.add(getCalendarField(this.rollUnit), this.rollCount); 248 return calendar.getTime(); 249 } 250 251 /** 252 * Returns a field code that can be used with the <code>Calendar</code> 253 * class. 254 * 255 * @return The field code. 256 */ 257 public int getCalendarField() { 258 return getCalendarField(this.unit); 259 } 260 261 /** 262 * Returns a field code (that can be used with the Calendar class) for a 263 * given 'unit' code. The 'unit' is one of: {@link #YEAR}, {@link #MONTH}, 264 * {@link #DAY}, {@link #HOUR}, {@link #MINUTE}, {@link #SECOND} and 265 * {@link #MILLISECOND}. 266 * 267 * @param tickUnit the unit. 268 * 269 * @return The field code. 270 */ 271 private int getCalendarField(int tickUnit) { 272 273 switch (tickUnit) { 274 case (YEAR): 275 return Calendar.YEAR; 276 case (MONTH): 277 return Calendar.MONTH; 278 case (DAY): 279 return Calendar.DATE; 280 case (HOUR): 281 return Calendar.HOUR_OF_DAY; 282 case (MINUTE): 283 return Calendar.MINUTE; 284 case (SECOND): 285 return Calendar.SECOND; 286 case (MILLISECOND): 287 return Calendar.MILLISECOND; 288 default: 289 return Calendar.MILLISECOND; 290 } 291 292 } 293 294 /** 295 * Returns the (approximate) number of milliseconds for the given unit and 296 * unit count. 297 * <P> 298 * This value is an approximation some of the time (e.g. months are 299 * assumed to have 31 days) but this shouldn't matter. 300 * 301 * @param unit the unit. 302 * @param count the unit count. 303 * 304 * @return The number of milliseconds. 305 */ 306 private static long getMillisecondCount(int unit, int count) { 307 308 switch (unit) { 309 case (YEAR): 310 return (365L * 24L * 60L * 60L * 1000L) * count; 311 case (MONTH): 312 return (31L * 24L * 60L * 60L * 1000L) * count; 313 case (DAY): 314 return (24L * 60L * 60L * 1000L) * count; 315 case (HOUR): 316 return (60L * 60L * 1000L) * count; 317 case (MINUTE): 318 return (60L * 1000L) * count; 319 case (SECOND): 320 return 1000L * count; 321 case (MILLISECOND): 322 return count; 323 default: 324 throw new IllegalArgumentException( 325 "DateTickUnit.getMillisecondCount() : unit must " 326 + "be one of the constants YEAR, MONTH, DAY, HOUR, MINUTE, " 327 + "SECOND or MILLISECOND defined in the DateTickUnit " 328 + "class. Do *not* use the constants defined in " 329 + "java.util.Calendar." 330 ); 331 } 332 333 } 334 335 /** 336 * Tests this unit for equality with another object. 337 * 338 * @param obj the object (<code>null</code> permitted). 339 * 340 * @return <code>true</code> or <code>false</code>. 341 */ 342 public boolean equals(Object obj) { 343 if (obj == this) { 344 return true; 345 } 346 if (!(obj instanceof DateTickUnit)) { 347 return false; 348 } 349 if (!super.equals(obj)) { 350 return false; 351 } 352 DateTickUnit that = (DateTickUnit) obj; 353 if (this.unit != that.unit) { 354 return false; 355 } 356 if (this.count != that.count) { 357 return false; 358 } 359 if (!ObjectUtilities.equal(this.formatter, that.formatter)) { 360 return false; 361 } 362 return true; 363 } 364 365 /** 366 * Returns a hash code for this object. 367 * 368 * @return A hash code. 369 */ 370 public int hashCode() { 371 int result = 19; 372 result = 37 * result + this.unit; 373 result = 37 * result + this.count; 374 result = 37 * result + this.formatter.hashCode(); 375 return result; 376 } 377 378 }