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