    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     * RegularTimePeriod.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     * Changes
    036     * -------
    037     * 11-Oct-2001 : Version 1 (DG);
    038     * 26-Feb-2002 : Changed getStart(), getMiddle() and getEnd() methods to
    039     *               evaluate with reference to a particular time zone (DG);
    040     * 29-May-2002 : Implemented MonthConstants interface, so that these constants
    041     *               are conveniently available (DG);
    042     * 10-Sep-2002 : Added getSerialIndex() method (DG);
    043     * 10-Jan-2003 : Renamed TimePeriod --> RegularTimePeriod (DG);
    044     * 13-Mar-2003 : Moved to com.jrefinery.data.time package (DG);
    045     * 29-Apr-2004 : Changed getMiddleMillisecond() methods to fix bug 943985 (DG);
    046     * 25-Nov-2004 : Added utility methods (DG);
    047     * ------------- JFREECHART 1.0.x ---------------------------------------------
    048     * 06-Oct-2006 : Deprecated the WORKING_CALENDAR field and several methods,
    049     *               added new peg() method (DG);
    050     *
    051     */
    052
    053    package org.jfree.data.time;
    054
    055    import java.lang.reflect.Constructor;
    056    import java.util.Calendar;
    057    import java.util.Date;
    058    import java.util.TimeZone;
    059
    060    import org.jfree.date.MonthConstants;
    061
    062    /**
    063     * An abstract class representing a unit of time.  Convenient methods are
    064     * provided for calculating the next and previous time periods.  Conversion
    065     * methods are defined that return the first and last milliseconds of the time
    066     * period.  The results from these methods are timezone dependent.
    067     * <P>
    068     * This class is immutable, and all subclasses should be immutable also.
    069     */
    070    public abstract class RegularTimePeriod implements TimePeriod, Comparable,
    071                                                       MonthConstants {
    072
    073        /**
    074         * Creates a time period that includes the specified millisecond, assuming
    075         * the given time zone.
    076         *
    077         * @param c  the time period class.
    078         * @param millisecond  the time.
    079         * @param zone  the time zone.
    080         *
    081         * @return The time period.
    082         */
    083        public static RegularTimePeriod createInstance(Class c, Date millisecond,
    084                                                       TimeZone zone) {
    085            RegularTimePeriod result = null;
    086            try {
    087                Constructor constructor = c.getDeclaredConstructor(
    088                        new Class[] {Date.class, TimeZone.class});
    089                result = (RegularTimePeriod) constructor.newInstance(
    090                        new Object[] {millisecond, zone});
    091            }
    092            catch (Exception e) {
    093                // do nothing, so null is returned
    094            }
    095            return result;
    096        }
    097
    098        /**
    099         * Returns a subclass of {@link RegularTimePeriod} that is smaller than
    100         * the specified class.
    101         *
    102         * @param c  a subclass of {@link RegularTimePeriod}.
    103         *
    104         * @return A class.
    105         */
    106        public static Class downsize(Class c) {
    107            if (c.equals(Year.class)) {
    108                return Quarter.class;
    109            }
    110            else if (c.equals(Quarter.class)) {
    111                return Month.class;
    112            }
    113            else if (c.equals(Month.class)) {
    114                return Day.class;
    115            }
    116            else if (c.equals(Day.class)) {
    117                return Hour.class;
    118            }
    119            else if (c.equals(Hour.class)) {
    120                return Minute.class;
    121            }
    122            else if (c.equals(Minute.class)) {
    123                return Second.class;
    124            }
    125            else if (c.equals(Second.class)) {
    126                return Millisecond.class;
    127            }
    128            else {
    129                return Millisecond.class;
    130            }
    131        }
    132
    133        /**
    134         * Returns the time period preceding this one, or <code>null</code> if some
    135         * lower limit has been reached.
    136         *
    137         * @return The previous time period (possibly <code>null</code>).
    138         */
    139        public abstract RegularTimePeriod previous();
    140
    141        /**
    142         * Returns the time period following this one, or <code>null</code> if some
    143         * limit has been reached.
    144         *
    145         * @return The next time period (possibly <code>null</code>).
    146         */
    147        public abstract RegularTimePeriod next();
    148
    149        /**
    150         * Returns a serial index number for the time unit.
    151         *
    152         * @return The serial index number.
    153         */
    154        public abstract long getSerialIndex();
    155
    156        //////////////////////////////////////////////////////////////////////////
    157
    158        /**
    159         * The default time zone.
    160         */
    161        public static final TimeZone DEFAULT_TIME_ZONE = TimeZone.getDefault();
    162
    163        /**
    164         * A working calendar (recycle to avoid unnecessary object creation).
    165         *
    166         * @deprecated This was a bad idea, don't use it!
    167         */
    168        public static final Calendar WORKING_CALENDAR
    169            = Calendar.getInstance(DEFAULT_TIME_ZONE);
    170
    171        /**
    172         * Recalculates the start date/time and end date/time for this time period
    173         * relative to the supplied calendar (which incorporates a time zone).
    174         *
    175         * @param calendar  the calendar (<code>null</code> not permitted).
    176         *
    177         * @since 1.0.3
    178         */
    179        public abstract void peg(Calendar calendar);
    180
    181        /**
    182         * Returns the date/time that marks the start of the time period.  This
    183         * method returns a new <code>Date</code> instance every time it is called.
    184         *
    185         * @return The start date/time.
    186         *
    187         * @see #getFirstMillisecond()
    188         */
    189        public Date getStart() {
    190            return new Date(getFirstMillisecond());
    191        }
    192
    193        /**
    194         * Returns the date/time that marks the end of the time period.  This
    195         * method returns a new <code>Date</code> instance every time it is called.
    196         *
    197         * @return The end date/time.
    198         *
    199         * @see #getLastMillisecond()
    200         */
    201        public Date getEnd() {
    202            return new Date(getLastMillisecond());
    203        }
    204
    205        /**
    206         * Returns the first millisecond of the time period.  This will be
    207         * determined relative to the time zone specified in the constructor, or
    208         * in the calendar instance passed in the most recent call to the
    209         * {@link #peg(Calendar)} method.
    210         *
    211         * @return The first millisecond of the time period.
    212         *
    213         * @see #getLastMillisecond()
    214         */
    215        public abstract long getFirstMillisecond();
    216
    217        /**
    218         * Returns the first millisecond of the time period, evaluated within a
    219         * specific time zone.
    220         *
    221         * @param zone  the time zone (<code>null</code> not permitted).
    222         *
    223         * @return The first millisecond of the time period.
    224         *
    225         * @deprecated As of 1.0.3, you should avoid using this method (it creates
    226         *     a new Calendar instance every time it is called).  You are advised
    227         *     to call {@link #getFirstMillisecond(Calendar)} instead.
    228         *
    229         * @see #getLastMillisecond(TimeZone)
    230         */
    231        public long getFirstMillisecond(TimeZone zone) {
    232            Calendar calendar = Calendar.getInstance(zone);
    233            return getFirstMillisecond(calendar);
    234        }
    235
    236        /**
    237         * Returns the first millisecond of the time period, evaluated using the
    238         * supplied calendar (which incorporates a timezone).
    239         *
    240         * @param calendar  the calendar (<code>null</code> not permitted).
    241         *
    242         * @return The first millisecond of the time period.
    243         *
    244         * @throws NullPointerException if <code>calendar,/code> is
    245         *     </code>null</code>.
    246         *
    247         * @see #getLastMillisecond(Calendar)
    248         */
    249        public abstract long getFirstMillisecond(Calendar calendar);
    250
    251        /**
    252         * Returns the last millisecond of the time period.  This will be
    253         * determined relative to the time zone specified in the constructor, or
    254         * in the calendar instance passed in the most recent call to the
    255         * {@link #peg(Calendar)} method.
    256         *
    257         * @return The last millisecond of the time period.
    258         *
    259         * @see #getFirstMillisecond()
    260         */
    261        public abstract long getLastMillisecond();
    262
    263        /**
    264         * Returns the last millisecond of the time period, evaluated within a
    265         * specific time zone.
    266         *
    267         * @param zone  the time zone (<code>null</code> not permitted).
    268         *
    269         * @return The last millisecond of the time period.
    270         *
    271         * @deprecated As of 1.0.3, you should avoid using this method (it creates
    272         *     a new Calendar instance every time it is called).  You are advised
    273         *     to call {@link #getLastMillisecond(Calendar)} instead.
    274         *
    275         * @see #getFirstMillisecond(TimeZone)
    276         */
    277        public long getLastMillisecond(TimeZone zone) {
    278            Calendar calendar = Calendar.getInstance(zone);
    279            return getLastMillisecond(calendar);
    280        }
    281
    282        /**
    283         * Returns the last millisecond of the time period, evaluated using the
    284         * supplied calendar (which incorporates a timezone).
    285         *
    286         * @param calendar  the calendar (<code>null</code> not permitted).
    287         *
    288         * @return The last millisecond of the time period.
    289         *
    290         * @see #getFirstMillisecond(Calendar)
    291         */
    292        public abstract long getLastMillisecond(Calendar calendar);
    293
    294        /**
    295         * Returns the millisecond closest to the middle of the time period.
    296         *
    297         * @return The middle millisecond.
    298         */
    299        public long getMiddleMillisecond() {
    300            long m1 = getFirstMillisecond();
    301            long m2 = getLastMillisecond();
    302            return m1 + (m2 - m1) / 2;
    303        }
    304
    305        /**
    306         * Returns the millisecond closest to the middle of the time period,
    307         * evaluated within a specific time zone.
    308         *
    309         * @param zone  the time zone (<code>null</code> not permitted).
    310         *
    311         * @return The middle millisecond.
    312         *
    313         * @deprecated As of 1.0.3, you should avoid using this method (it creates
    314         *     a new Calendar instance every time it is called).  You are advised
    315         *     to call {@link #getMiddleMillisecond(Calendar)} instead.
    316         */
    317        public long getMiddleMillisecond(TimeZone zone) {
    318            Calendar calendar = Calendar.getInstance(zone);
    319            long m1 = getFirstMillisecond(calendar);
    320            long m2 = getLastMillisecond(calendar);
    321            return m1 + (m2 - m1) / 2;
    322        }
    323
    324        /**
    325         * Returns the millisecond closest to the middle of the time period,
    326         * evaluated using the supplied calendar (which incorporates a timezone).
    327         *
    328         * @param calendar  the calendar.
    329         *
    330         * @return The middle millisecond.
    331         */
    332        public long getMiddleMillisecond(Calendar calendar) {
    333            long m1 = getFirstMillisecond(calendar);
    334            long m2 = getLastMillisecond(calendar);
    335            return m1 + (m2 - m1) / 2;
    336        }
    337
    338        /**
    339         * Returns a string representation of the time period.
    340         *
    341         * @return The string.
    342         */
    343        public String toString() {
    344            return String.valueOf(getStart());
    345        }
    346
    347    }