    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    }