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 * Minute.java 029 * ----------- 030 * (C) Copyright 2001-2004, by Object Refinery Limited. 031 * 032 * Original Author: David Gilbert (for Object Refinery Limited); 033 * Contributor(s): -; 034 * 035 * $Id: Minute.java,v 1.5.2.1 2005/10/25 21:35:24 mungady Exp $ 036 * 037 * Changes 038 * ------- 039 * 11-Oct-2001 : Version 1 (DG); 040 * 18-Dec-2001 : Changed order of parameters in constructor (DG); 041 * 19-Dec-2001 : Added a new constructor as suggested by Paul English (DG); 042 * 14-Feb-2002 : Fixed bug in Minute(Date) constructor, and changed the range 043 * to start from zero instead of one (DG); 044 * 26-Feb-2002 : Changed getStart(), getMiddle() and getEnd() methods to 045 * evaluate with reference to a particular time zone (DG); 046 * 13-Mar-2002 : Added parseMinute() method (DG); 047 * 19-Mar-2002 : Changed API, the minute is now defined in relation to an 048 * Hour (DG); 049 * 10-Sep-2002 : Added getSerialIndex() method (DG); 050 * 07-Oct-2002 : Fixed errors reported by Checkstyle (DG); 051 * 10-Jan-2003 : Changed base class and method names (DG); 052 * 13-Mar-2003 : Moved to com.jrefinery.data.time package and implemented 053 * Serializable (DG); 054 * 21-Oct-2003 : Added hashCode() method, and new constructor for 055 * convenience (DG); 056 * 30-Sep-2004 : Replaced getTime().getTime() with getTimeInMillis() (DG); 057 * 04-Nov-2004 : Reverted change of 30-Sep-2004, because it won't work for 058 * JDK 1.3 (DG); 059 * 060 */ 061 062 package org.jfree.data.time; 063 064 import java.io.Serializable; 065 import java.util.Calendar; 066 import java.util.Date; 067 import java.util.TimeZone; 068 069 /** 070 * Represents a minute. This class is immutable, which is a requirement for 071 * all {@link RegularTimePeriod} subclasses. 072 */ 073 public class Minute extends RegularTimePeriod implements Serializable { 074 075 /** For serialization. */ 076 private static final long serialVersionUID = 2144572840034842871L; 077 078 /** Useful constant for the first minute in a day. */ 079 public static final int FIRST_MINUTE_IN_HOUR = 0; 080 081 /** Useful constant for the last minute in a day. */ 082 public static final int LAST_MINUTE_IN_HOUR = 59; 083 084 /** The hour in which the minute falls. */ 085 private Hour hour; 086 087 /** The minute. */ 088 private int minute; 089 090 /** 091 * Constructs a new Minute, based on the system date/time. 092 */ 093 public Minute() { 094 this(new Date()); 095 } 096 097 /** 098 * Constructs a new Minute. 099 * 100 * @param minute the minute (0 to 59). 101 * @param hour the hour (<code>null</code> not permitted). 102 */ 103 public Minute(int minute, Hour hour) { 104 if (hour == null) { 105 throw new IllegalArgumentException("Null 'hour' argument."); 106 } 107 this.minute = minute; 108 this.hour = hour; 109 } 110 111 /** 112 * Constructs a new Minute, based on the supplied date/time. 113 * 114 * @param time the time (<code>null</code> not permitted). 115 */ 116 public Minute(Date time) { 117 // defer argument checking 118 this(time, RegularTimePeriod.DEFAULT_TIME_ZONE); 119 } 120 121 /** 122 * Constructs a new Minute, based on the supplied date/time and timezone. 123 * 124 * @param time the time (<code>null</code> not permitted). 125 * @param zone the time zone (<code>null</code> not permitted). 126 */ 127 public Minute(Date time, TimeZone zone) { 128 129 if (time == null) { 130 throw new IllegalArgumentException("Null 'time' argument."); 131 } 132 if (zone == null) { 133 throw new IllegalArgumentException("Null 'zone' argument."); 134 } 135 Calendar calendar = Calendar.getInstance(zone); 136 calendar.setTime(time); 137 int min = calendar.get(Calendar.MINUTE); 138 this.minute = min; 139 this.hour = new Hour(time, zone); 140 141 } 142 143 /** 144 * Creates a new minute. 145 * 146 * @param minute the minute (0-59). 147 * @param hour the hour (0-23). 148 * @param day the day (1-31). 149 * @param month the month (1-12). 150 * @param year the year (1900-9999). 151 */ 152 public Minute(int minute, 153 int hour, 154 int day, 155 int month, 156 int year) { 157 this(minute, new Hour(hour, new Day(day, month, year))); 158 } 159 160 /** 161 * Returns the hour. 162 * 163 * @return The hour (never <code>null</code>). 164 */ 165 public Hour getHour() { 166 return this.hour; 167 } 168 169 /** 170 * Returns the minute. 171 * 172 * @return The minute. 173 */ 174 public int getMinute() { 175 return this.minute; 176 } 177 178 /** 179 * Returns the minute preceding this one. 180 * 181 * @return The minute preceding this one. 182 */ 183 public RegularTimePeriod previous() { 184 185 Minute result; 186 if (this.minute != FIRST_MINUTE_IN_HOUR) { 187 result = new Minute(this.minute - 1, this.hour); 188 } 189 else { // we are at the first minute in the hour... 190 Hour prevHour = (Hour) this.hour.previous(); 191 if (prevHour != null) { 192 result = new Minute(LAST_MINUTE_IN_HOUR, prevHour); 193 } 194 else { 195 result = null; 196 } 197 } 198 return result; 199 200 } 201 202 /** 203 * Returns the minute following this one. 204 * 205 * @return The minute following this one. 206 */ 207 public RegularTimePeriod next() { 208 209 Minute result; 210 if (this.minute != LAST_MINUTE_IN_HOUR) { 211 result = new Minute(this.minute + 1, this.hour); 212 } 213 else { // we are at the last minute in the hour... 214 Hour nextHour = (Hour) this.hour.next(); 215 if (nextHour != null) { 216 result = new Minute(FIRST_MINUTE_IN_HOUR, nextHour); 217 } 218 else { 219 result = null; 220 } 221 } 222 return result; 223 224 } 225 226 /** 227 * Returns a serial index number for the minute. 228 * 229 * @return The serial index number. 230 */ 231 public long getSerialIndex() { 232 return this.hour.getSerialIndex() * 60L + this.minute; 233 } 234 235 /** 236 * Returns the first millisecond of the minute. 237 * 238 * @param calendar the calendar (which defines the timezone). 239 * 240 * @return The first millisecond. 241 */ 242 public long getFirstMillisecond(Calendar calendar) { 243 244 int year = this.hour.getDay().getYear(); 245 int month = this.hour.getDay().getMonth() - 1; 246 int day = this.hour.getDay().getDayOfMonth(); 247 248 calendar.clear(); 249 calendar.set(year, month, day, this.hour.getHour(), this.minute, 0); 250 calendar.set(Calendar.MILLISECOND, 0); 251 252 //return calendar.getTimeInMillis(); // this won't work for JDK 1.3 253 return calendar.getTime().getTime(); 254 255 } 256 257 /** 258 * Returns the last millisecond of the minute. 259 * 260 * @param calendar the calendar and timezone. 261 * 262 * @return The last millisecond. 263 */ 264 public long getLastMillisecond(Calendar calendar) { 265 266 int year = this.hour.getDay().getYear(); 267 int month = this.hour.getDay().getMonth() - 1; 268 int day = this.hour.getDay().getDayOfMonth(); 269 270 calendar.clear(); 271 calendar.set(year, month, day, this.hour.getHour(), this.minute, 59); 272 calendar.set(Calendar.MILLISECOND, 999); 273 274 //return calendar.getTimeInMillis(); // this won't work for JDK 1.3 275 return calendar.getTime().getTime(); 276 277 } 278 279 /** 280 * Tests the equality of this object against an arbitrary Object. 281 * <P> 282 * This method will return true ONLY if the object is a Minute object 283 * representing the same minute as this instance. 284 * 285 * @param obj the object to compare (<code>null</code> permitted). 286 * 287 * @return <code>true</code> if the minute and hour value of this and the 288 * object are the same. 289 */ 290 public boolean equals(Object obj) { 291 if (obj == this) { 292 return true; 293 } 294 if (!(obj instanceof Minute)) { 295 return false; 296 } 297 Minute that = (Minute) obj; 298 if (this.minute != that.minute) { 299 return false; 300 } 301 if (!this.hour.equals(that.hour)) { 302 return false; 303 } 304 return true; 305 } 306 307 /** 308 * Returns a hash code for this object instance. The approach described 309 * by Joshua Bloch in "Effective Java" has been used here: 310 * <p> 311 * <code>http://developer.java.sun.com/developer/Books/effectivejava 312 * /Chapter3.pdf</code> 313 * 314 * @return A hash code. 315 */ 316 public int hashCode() { 317 int result = 17; 318 result = 37 * result + this.minute; 319 result = 37 * result + this.hour.hashCode(); 320 return result; 321 } 322 323 /** 324 * Returns an integer indicating the order of this Minute object relative 325 * to the specified object: 326 * 327 * negative == before, zero == same, positive == after. 328 * 329 * @param o1 object to compare. 330 * 331 * @return negative == before, zero == same, positive == after. 332 */ 333 public int compareTo(Object o1) { 334 335 int result; 336 337 // CASE 1 : Comparing to another Minute object 338 // ------------------------------------------- 339 if (o1 instanceof Minute) { 340 Minute m = (Minute) o1; 341 result = getHour().compareTo(m.getHour()); 342 if (result == 0) { 343 result = this.minute - m.getMinute(); 344 } 345 } 346 347 // CASE 2 : Comparing to another TimePeriod object 348 // ----------------------------------------------- 349 else if (o1 instanceof RegularTimePeriod) { 350 // more difficult case - evaluate later... 351 result = 0; 352 } 353 354 // CASE 3 : Comparing to a non-TimePeriod object 355 // --------------------------------------------- 356 else { 357 // consider time periods to be ordered after general objects 358 result = 1; 359 } 360 361 return result; 362 363 } 364 365 /** 366 * Creates a Minute instance by parsing a string. The string is assumed to 367 * be in the format "YYYY-MM-DD HH:MM", perhaps with leading or trailing 368 * whitespace. 369 * 370 * @param s the minute string to parse. 371 * 372 * @return <code>null</code>, if the string is not parseable, the minute 373 * otherwise. 374 */ 375 public static Minute parseMinute(String s) { 376 377 Minute result = null; 378 s = s.trim(); 379 380 String daystr = s.substring(0, Math.min(10, s.length())); 381 Day day = Day.parseDay(daystr); 382 if (day != null) { 383 String hmstr = s.substring( 384 Math.min(daystr.length() + 1, s.length()), s.length() 385 ); 386 hmstr = hmstr.trim(); 387 388 String hourstr = hmstr.substring(0, Math.min(2, hmstr.length())); 389 int hour = Integer.parseInt(hourstr); 390 391 if ((hour >= 0) && (hour <= 23)) { 392 String minstr = hmstr.substring( 393 Math.min(hourstr.length() + 1, hmstr.length()), 394 hmstr.length() 395 ); 396 int minute = Integer.parseInt(minstr); 397 if ((minute >= 0) && (minute <= 59)) { 398 result = new Minute(minute, new Hour(hour, day)); 399 } 400 } 401 } 402 403 return result; 404 405 } 406 407 }