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