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     * Millisecond.java
029     * ----------------
030     * (C) Copyright 2001-2005, 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.1 2005/10/25 21:35:24 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     *
050     */
051    
052    package org.jfree.data.time;
053    
054    import java.io.Serializable;
055    import java.util.Calendar;
056    import java.util.Date;
057    import java.util.TimeZone;
058    
059    /**
060     * Represents a millisecond.  This class is immutable, which is a requirement 
061     * for all {@link RegularTimePeriod} subclasses.
062     */
063    public class Millisecond extends RegularTimePeriod implements Serializable {
064    
065        /** For serialization. */
066        static final long serialVersionUID = -5316836467277638485L;
067        
068        /** A constant for the first millisecond in a second. */
069        public static final int FIRST_MILLISECOND_IN_SECOND = 0;
070    
071        /** A constant for the last millisecond in a second. */
072        public static final int LAST_MILLISECOND_IN_SECOND = 999;
073    
074        /** The millisecond. */
075        private int millisecond;
076    
077        /** The second. */
078        private Second second;
079    
080        /**
081         * Constructs a millisecond based on the current system time.
082         */
083        public Millisecond() {
084            this(new Date());
085        }
086    
087        /**
088         * Constructs a millisecond.
089         *
090         * @param millisecond  the millisecond (0-999).
091         * @param second  the second.
092         */
093        public Millisecond(int millisecond, Second second) {
094            this.millisecond = millisecond;
095            this.second = second;
096        }
097    
098        /**
099         * Creates a new millisecond.
100         * 
101         * @param millisecond  the millisecond (0-999).
102         * @param second  the second (0-59).
103         * @param minute  the minute (0-59).
104         * @param hour  the hour (0-23).
105         * @param day  the day (1-31).
106         * @param month  the month (1-12).
107         * @param year  the year (1900-9999).
108         */    
109        public Millisecond(int millisecond, int second, int minute, int hour,
110                           int day, int month, int year) {
111                               
112            this(millisecond, new Second(second, minute, hour, day, month, year));
113        
114        }
115    
116        /**
117         * Constructs a millisecond.
118         *
119         * @param time  the time.
120         */
121        public Millisecond(Date time) {
122            this(time, RegularTimePeriod.DEFAULT_TIME_ZONE);
123        }
124    
125        /**
126         * Creates a millisecond.
127         *
128         * @param time  the instant in time.
129         * @param zone  the time zone.
130         */
131        public Millisecond(Date time, TimeZone zone) {
132    
133            this.second = new Second(time, zone);
134            Calendar calendar = Calendar.getInstance(zone);
135            calendar.setTime(time);
136            this.millisecond = calendar.get(Calendar.MILLISECOND);
137    
138        }
139    
140        /**
141         * Returns the second.
142         *
143         * @return The second.
144         */
145        public Second getSecond() {
146            return this.second;
147        }
148    
149        /**
150         * Returns the millisecond.
151         *
152         * @return The millisecond.
153         */
154        public long getMillisecond() {
155            return this.millisecond;
156        }
157    
158        /**
159         * Returns the millisecond preceding this one.
160         *
161         * @return The millisecond preceding this one.
162         */
163        public RegularTimePeriod previous() {
164    
165            RegularTimePeriod result = null;
166    
167            if (this.millisecond != FIRST_MILLISECOND_IN_SECOND) {
168                result = new Millisecond(this.millisecond - 1, this.second);
169            }
170            else {
171                Second previous = (Second) this.second.previous();
172                if (previous != null) {
173                    result = new Millisecond(LAST_MILLISECOND_IN_SECOND, previous);
174                }
175            }
176            return result;
177    
178        }
179    
180        /**
181         * Returns the millisecond following this one.
182         *
183         * @return The millisecond following this one.
184         */
185        public RegularTimePeriod next() {
186    
187            RegularTimePeriod result = null;
188            if (this.millisecond != LAST_MILLISECOND_IN_SECOND) {
189                result = new Millisecond(this.millisecond + 1, this.second);
190            }
191            else {
192                Second next = (Second) this.second.next();
193                if (next != null) {
194                    result = new Millisecond(FIRST_MILLISECOND_IN_SECOND, next);
195                }
196            }
197            return result;
198    
199        }
200    
201        /**
202         * Returns a serial index number for the millisecond.
203         *
204         * @return The serial index number.
205         */
206        public long getSerialIndex() {
207            return this.second.getSerialIndex() * 1000L + this.millisecond;
208        }
209    
210        /**
211         * Tests the equality of this object against an arbitrary Object.
212         * <P>
213         * This method will return true ONLY if the object is a Millisecond object
214         * representing the same millisecond as this instance.
215         *
216         * @param obj  the object to compare
217         *
218         * @return <code>true</code> if milliseconds and seconds of this and object
219         *      are the same.
220         */
221        public boolean equals(Object obj) {
222    
223            if (obj instanceof Millisecond) {
224                Millisecond m = (Millisecond) obj;
225                return ((this.millisecond == m.getMillisecond())
226                        && (this.second.equals(m.getSecond())));
227            }
228            else {
229                return false;
230            }
231    
232        }
233    
234        /**
235         * Returns a hash code for this object instance.  The approach described by 
236         * Joshua Bloch in "Effective Java" has been used here:
237         * <p>
238         * <code>http://developer.java.sun.com/developer/Books/effectivejava
239         * /Chapter3.pdf</code>
240         * 
241         * @return A hashcode.
242         */
243        public int hashCode() {
244            int result = 17;
245            result = 37 * result + this.millisecond;
246            result = 37 * result + this.second.hashCode();
247            return result;
248        }
249    
250        /**
251         * Returns an integer indicating the order of this Millisecond object
252         * relative to the specified object:
253         *
254         * negative == before, zero == same, positive == after.
255         *
256         * @param obj  the object to compare
257         *
258         * @return negative == before, zero == same, positive == after.
259         */
260        public int compareTo(Object obj) {
261    
262            int result;
263            long difference;
264    
265            // CASE 1 : Comparing to another Second object
266            // -------------------------------------------
267            if (obj instanceof Millisecond) {
268                Millisecond ms = (Millisecond) obj;
269                difference = getFirstMillisecond() - ms.getFirstMillisecond();
270                if (difference > 0) {
271                    result = 1;
272                }
273                else {
274                    if (difference < 0) {
275                        result = -1;
276                    }
277                    else {
278                        result = 0;
279                    }
280                }
281            }
282    
283            // CASE 2 : Comparing to another TimePeriod object
284            // -----------------------------------------------
285            else if (obj instanceof RegularTimePeriod) {
286                // more difficult case - evaluate later...
287                result = 0;
288            }
289    
290            // CASE 3 : Comparing to a non-TimePeriod object
291            // ---------------------------------------------
292            else {
293                // consider time periods to be ordered after general objects
294                result = 1;
295            }
296    
297            return result;
298    
299        }
300    
301        /**
302         * Returns the first millisecond of the time period.
303         *
304         * @return The first millisecond of the time period.
305         */
306        public long getFirstMillisecond() {
307            return this.second.getFirstMillisecond() + this.millisecond;
308        }
309    
310        /**
311         * Returns the first millisecond of the time period.
312         *
313         * @param calendar  the calendar.
314         *
315         * @return The first millisecond of the time period.
316         */
317        public long getFirstMillisecond(Calendar calendar) {
318            return this.second.getFirstMillisecond(calendar) + this.millisecond;
319        }
320    
321        /**
322         * Returns the last millisecond of the time period.
323         *
324         * @return The last millisecond of the time period.
325         */
326        public long getLastMillisecond() {
327            return this.second.getFirstMillisecond() + this.millisecond;
328        }
329    
330        /**
331         * Returns the last millisecond of the time period.
332         *
333         * @param calendar  the calendar.
334         *
335         * @return The last millisecond of the time period.
336         */
337        public long getLastMillisecond(Calendar calendar) {
338            return this.second.getFirstMillisecond(calendar) + this.millisecond;
339        }
340    
341    }