Frames | No Frames |
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: * Year.java 29: * --------- 30: * (C) Copyright 2001-2007, by Object Refinery Limited. 31: * 32: * Original Author: David Gilbert (for Object Refinery Limited); 33: * Contributor(s): -; 34: * 35: * Changes 36: * ------- 37: * 11-Oct-2001 : Version 1 (DG); 38: * 14-Nov-2001 : Override for toString() method (DG); 39: * 19-Dec-2001 : Added a new constructor as suggested by Paul English (DG); 40: * 29-Jan-2002 : Worked on parseYear() method (DG); 41: * 14-Feb-2002 : Fixed bug in Year(Date) constructor (DG); 42: * 26-Feb-2002 : Changed getStart(), getMiddle() and getEnd() methods to 43: * evaluate with reference to a particular time zone (DG); 44: * 19-Mar-2002 : Changed API for TimePeriod classes (DG); 45: * 10-Sep-2002 : Added getSerialIndex() method (DG); 46: * 04-Oct-2002 : Fixed errors reported by Checkstyle (DG); 47: * 10-Jan-2003 : Changed base class and method names (DG); 48: * 05-Mar-2003 : Fixed bug in getFirstMillisecond() picked up in JUnit 49: * tests (DG); 50: * 13-Mar-2003 : Moved to com.jrefinery.data.time package, and implemented 51: * Serializable (DG); 52: * 21-Oct-2003 : Added hashCode() method (DG); 53: * ------------- JFREECHART 1.0.x --------------------------------------------- 54: * 05-Oct-2006 : Updated API docs (DG); 55: * 06-Oct-2006 : Refactored to cache first and last millisecond values (DG); 56: * 57: */ 58: 59: package org.jfree.data.time; 60: 61: import java.io.Serializable; 62: import java.util.Calendar; 63: import java.util.Date; 64: import java.util.TimeZone; 65: 66: import org.jfree.date.SerialDate; 67: 68: /** 69: * Represents a year in the range 1900 to 9999. This class is immutable, which 70: * is a requirement for all {@link RegularTimePeriod} subclasses. 71: */ 72: public class Year extends RegularTimePeriod implements Serializable { 73: 74: /** For serialization. */ 75: private static final long serialVersionUID = -7659990929736074836L; 76: 77: /** The year. */ 78: private short year; 79: 80: /** The first millisecond. */ 81: private long firstMillisecond; 82: 83: /** The last millisecond. */ 84: private long lastMillisecond; 85: 86: /** 87: * Creates a new <code>Year</code>, based on the current system date/time. 88: */ 89: public Year() { 90: this(new Date()); 91: } 92: 93: /** 94: * Creates a time period representing a single year. 95: * 96: * @param year the year. 97: */ 98: public Year(int year) { 99: if ((year < SerialDate.MINIMUM_YEAR_SUPPORTED) 100: || (year > SerialDate.MAXIMUM_YEAR_SUPPORTED)) { 101: 102: throw new IllegalArgumentException( 103: "Year constructor: year (" + year + ") outside valid range."); 104: } 105: this.year = (short) year; 106: peg(Calendar.getInstance()); 107: } 108: 109: /** 110: * Creates a new <code>Year</code>, based on a particular instant in time, 111: * using the default time zone. 112: * 113: * @param time the time (<code>null</code> not permitted). 114: */ 115: public Year(Date time) { 116: this(time, RegularTimePeriod.DEFAULT_TIME_ZONE); 117: } 118: 119: /** 120: * Constructs a year, based on a particular instant in time and a time zone. 121: * 122: * @param time the time. 123: * @param zone the time zone. 124: */ 125: public Year(Date time, TimeZone zone) { 126: Calendar calendar = Calendar.getInstance(zone); 127: calendar.setTime(time); 128: this.year = (short) calendar.get(Calendar.YEAR); 129: peg(calendar); 130: } 131: 132: /** 133: * Returns the year. 134: * 135: * @return The year. 136: */ 137: public int getYear() { 138: return this.year; 139: } 140: 141: /** 142: * Returns the first millisecond of the year. This will be determined 143: * relative to the time zone specified in the constructor, or in the 144: * calendar instance passed in the most recent call to the 145: * {@link #peg(Calendar)} method. 146: * 147: * @return The first millisecond of the year. 148: * 149: * @see #getLastMillisecond() 150: */ 151: public long getFirstMillisecond() { 152: return this.firstMillisecond; 153: } 154: 155: /** 156: * Returns the last millisecond of the year. This will be 157: * determined relative to the time zone specified in the constructor, or 158: * in the calendar instance passed in the most recent call to the 159: * {@link #peg(Calendar)} method. 160: * 161: * @return The last millisecond of the year. 162: * 163: * @see #getFirstMillisecond() 164: */ 165: public long getLastMillisecond() { 166: return this.lastMillisecond; 167: } 168: 169: /** 170: * Recalculates the start date/time and end date/time for this time period 171: * relative to the supplied calendar (which incorporates a time zone). 172: * 173: * @param calendar the calendar (<code>null</code> not permitted). 174: * 175: * @since 1.0.3 176: */ 177: public void peg(Calendar calendar) { 178: this.firstMillisecond = getFirstMillisecond(calendar); 179: this.lastMillisecond = getLastMillisecond(calendar); 180: } 181: 182: /** 183: * Returns the year preceding this one. 184: * 185: * @return The year preceding this one (or <code>null</code> if the 186: * current year is 1900). 187: */ 188: public RegularTimePeriod previous() { 189: if (this.year > SerialDate.MINIMUM_YEAR_SUPPORTED) { 190: return new Year(this.year - 1); 191: } 192: else { 193: return null; 194: } 195: } 196: 197: /** 198: * Returns the year following this one. 199: * 200: * @return The year following this one (or <code>null</code> if the current 201: * year is 9999). 202: */ 203: public RegularTimePeriod next() { 204: if (this.year < SerialDate.MAXIMUM_YEAR_SUPPORTED) { 205: return new Year(this.year + 1); 206: } 207: else { 208: return null; 209: } 210: } 211: 212: /** 213: * Returns a serial index number for the year. 214: * <P> 215: * The implementation simply returns the year number (e.g. 2002). 216: * 217: * @return The serial index number. 218: */ 219: public long getSerialIndex() { 220: return this.year; 221: } 222: 223: /** 224: * Returns the first millisecond of the year, evaluated using the supplied 225: * calendar (which determines the time zone). 226: * 227: * @param calendar the calendar (<code>null</code> not permitted). 228: * 229: * @return The first millisecond of the year. 230: * 231: * @throws NullPointerException if <code>calendar</code> is 232: * <code>null</code>. 233: */ 234: public long getFirstMillisecond(Calendar calendar) { 235: calendar.set(this.year, Calendar.JANUARY, 1, 0, 0, 0); 236: calendar.set(Calendar.MILLISECOND, 0); 237: // in the following line, we'd rather call calendar.getTimeInMillis() 238: // to avoid object creation, but that isn't supported in Java 1.3.1 239: return calendar.getTime().getTime(); 240: } 241: 242: /** 243: * Returns the last millisecond of the year, evaluated using the supplied 244: * calendar (which determines the time zone). 245: * 246: * @param calendar the calendar (<code>null</code> not permitted). 247: * 248: * @return The last millisecond of the year. 249: * 250: * @throws NullPointerException if <code>calendar</code> is 251: * <code>null</code>. 252: */ 253: public long getLastMillisecond(Calendar calendar) { 254: calendar.set(this.year, Calendar.DECEMBER, 31, 23, 59, 59); 255: calendar.set(Calendar.MILLISECOND, 999); 256: // in the following line, we'd rather call calendar.getTimeInMillis() 257: // to avoid object creation, but that isn't supported in Java 1.3.1 258: return calendar.getTime().getTime(); 259: } 260: 261: /** 262: * Tests the equality of this <code>Year</code> object to an arbitrary 263: * object. Returns <code>true</code> if the target is a <code>Year</code> 264: * instance representing the same year as this object. In all other cases, 265: * returns <code>false</code>. 266: * 267: * @param object the object (<code>null</code> permitted). 268: * 269: * @return <code>true</code> if the year of this and the object are the 270: * same. 271: */ 272: public boolean equals(Object object) { 273: if (object != null) { 274: if (object instanceof Year) { 275: Year target = (Year) object; 276: return (this.year == target.getYear()); 277: } 278: else { 279: return false; 280: } 281: } 282: else { 283: return false; 284: } 285: } 286: 287: /** 288: * Returns a hash code for this object instance. The approach described by 289: * Joshua Bloch in "Effective Java" has been used here: 290: * <p> 291: * <code>http://developer.java.sun.com/developer/Books/effectivejava 292: * /Chapter3.pdf</code> 293: * 294: * @return A hash code. 295: */ 296: public int hashCode() { 297: int result = 17; 298: int c = this.year; 299: result = 37 * result + c; 300: return result; 301: } 302: 303: /** 304: * Returns an integer indicating the order of this <code>Year</code> object 305: * relative to the specified object: 306: * 307: * negative == before, zero == same, positive == after. 308: * 309: * @param o1 the object to compare. 310: * 311: * @return negative == before, zero == same, positive == after. 312: */ 313: public int compareTo(Object o1) { 314: 315: int result; 316: 317: // CASE 1 : Comparing to another Year object 318: // ----------------------------------------- 319: if (o1 instanceof Year) { 320: Year y = (Year) o1; 321: result = this.year - y.getYear(); 322: } 323: 324: // CASE 2 : Comparing to another TimePeriod object 325: // ----------------------------------------------- 326: else if (o1 instanceof RegularTimePeriod) { 327: // more difficult case - evaluate later... 328: result = 0; 329: } 330: 331: // CASE 3 : Comparing to a non-TimePeriod object 332: // --------------------------------------------- 333: else { 334: // consider time periods to be ordered after general objects 335: result = 1; 336: } 337: 338: return result; 339: 340: } 341: 342: /** 343: * Returns a string representing the year.. 344: * 345: * @return A string representing the year. 346: */ 347: public String toString() { 348: return Integer.toString(this.year); 349: } 350: 351: /** 352: * Parses the string argument as a year. 353: * <P> 354: * The string format is YYYY. 355: * 356: * @param s a string representing the year. 357: * 358: * @return <code>null</code> if the string is not parseable, the year 359: * otherwise. 360: */ 361: public static Year parseYear(String s) { 362: 363: // parse the string... 364: int y; 365: try { 366: y = Integer.parseInt(s.trim()); 367: } 368: catch (NumberFormatException e) { 369: throw new TimePeriodFormatException("Cannot parse string."); 370: } 371: 372: // create the year... 373: try { 374: return new Year(y); 375: } 376: catch (IllegalArgumentException e) { 377: throw new TimePeriodFormatException("Year outside valid range."); 378: } 379: } 380: 381: }