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