Home | History | Annotate | Download | only in calendar
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  * Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved.
      4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      5  *
      6  * This code is free software; you can redistribute it and/or modify it
      7  * under the terms of the GNU General Public License version 2 only, as
      8  * published by the Free Software Foundation.  Oracle designates this
      9  * particular file as subject to the "Classpath" exception as provided
     10  * by Oracle in the LICENSE file that accompanied this code.
     11  *
     12  * This code is distributed in the hope that it will be useful, but WITHOUT
     13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     15  * version 2 for more details (a copy is included in the LICENSE file that
     16  * accompanied this code).
     17  *
     18  * You should have received a copy of the GNU General Public License version
     19  * 2 along with this work; if not, write to the Free Software Foundation,
     20  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
     21  *
     22  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
     23  * or visit www.oracle.com if you need additional information or have any
     24  * questions.
     25  */
     26 
     27 package sun.util.calendar;
     28 
     29 import java.lang.reflect.Field;
     30 import java.util.HashMap;
     31 import java.util.Locale;
     32 import java.util.Map;
     33 import java.util.MissingResourceException;
     34 import java.util.ResourceBundle;
     35 import java.util.Set;
     36 import java.util.TimeZone;
     37 import java.util.concurrent.ConcurrentHashMap;
     38 import java.util.concurrent.ConcurrentMap;
     39 
     40 /**
     41  * <code>CalendarSystem</code> is an abstract class that defines the
     42  * programming interface to deal with calendar date and time.
     43  *
     44  * <p><code>CalendarSystem</code> instances are singletons. For
     45  * example, there exists only one Gregorian calendar instance in the
     46  * Java runtime environment. A singleton instance can be obtained
     47  * calling one of the static factory methods.
     48  *
     49  * <h4>CalendarDate</h4>
     50  *
     51  * <p>For the methods in a <code>CalendarSystem</code> that manipulate
     52  * a <code>CalendarDate</code>, <code>CalendarDate</code>s that have
     53  * been created by the <code>CalendarSystem</code> must be
     54  * specified. Otherwise, the methods throw an exception. This is
     55  * because, for example, a Chinese calendar date can't be understood
     56  * by the Hebrew calendar system.
     57  *
     58  * <h4>Calendar names</h4>
     59  *
     60  * Each calendar system has a unique name to be identified. The Java
     61  * runtime in this release supports the following calendar systems.
     62  *
     63  * <pre>
     64  *  Name          Calendar System
     65  *  ---------------------------------------
     66  *  gregorian     Gregorian Calendar
     67  *  julian        Julian Calendar
     68  *  japanese      Japanese Imperial Calendar
     69  * </pre>
     70  *
     71  * @see CalendarDate
     72  * @author Masayoshi Okutsu
     73  * @since 1.5
     74  */
     75 
     76 public abstract class CalendarSystem {
     77 
     78     /////////////////////// Calendar Factory Methods /////////////////////////
     79 
     80     // Map of calendar names and calendar classes;
     81     private static final Map<String, Class<?>> names;
     82 
     83     // Android changed : Don't use reflection for Class.forName every time.
     84 
     85     static {
     86         names = new HashMap<>();
     87         names.put("gregorian", Gregorian.class);
     88         names.put("japanese", LocalGregorianCalendar.class);
     89         names.put("julian", JulianCalendar.class);
     90         // names.put("hebrew", "HebrewCalendar");
     91         // names.put("iso8601", "ISOCalendar");
     92         // names.put("taiwanese", "LocalGregorianCalendar");
     93         // names.put("thaibuddhist", "LocalGregorianCalendar");
     94     }
     95 
     96     // Map of calendar names and CalendarSystem instances
     97     private static final ConcurrentMap<String, CalendarSystem> calendars =
     98             new ConcurrentHashMap<>();
     99 
    100     private final static Gregorian GREGORIAN_INSTANCE = new Gregorian();
    101 
    102     /**
    103      * Returns the singleton instance of the <code>Gregorian</code>
    104      * calendar system.
    105      *
    106      * @return the <code>Gregorian</code> instance
    107      */
    108     public static Gregorian getGregorianCalendar() {
    109         return GREGORIAN_INSTANCE;
    110     }
    111 
    112     /**
    113      * Returns a <code>CalendarSystem</code> specified by the calendar
    114      * name. The calendar name has to be one of the supported calendar
    115      * names.
    116      *
    117      * @param calendarName the calendar name
    118      * @return the <code>CalendarSystem</code> specified by
    119      * <code>calendarName</code>, or null if there is no
    120      * <code>CalendarSystem</code> associated with the given calendar name.
    121      */
    122     public static CalendarSystem forName(String calendarName) {
    123         if ("gregorian".equals(calendarName)) {
    124             return GREGORIAN_INSTANCE;
    125         }
    126 
    127         CalendarSystem cal = calendars.get(calendarName);
    128         if (cal != null) {
    129             return cal;
    130         }
    131 
    132         Class<?> calendarClass = names.get(calendarName);
    133         if (calendarClass == null) {
    134             return null; // Unknown calendar name
    135         }
    136 
    137         if (calendarClass.isAssignableFrom(LocalGregorianCalendar.class)) {
    138             // Create the specific kind of local Gregorian calendar system
    139             cal = LocalGregorianCalendar.getLocalGregorianCalendar(calendarName);
    140         } else {
    141             try {
    142                 cal = (CalendarSystem) calendarClass.newInstance();
    143             } catch (Exception e) {
    144                 throw new RuntimeException("internal error", e);
    145             }
    146         }
    147         if (cal == null) {
    148             return null;
    149         }
    150 
    151         CalendarSystem cs =  calendars.putIfAbsent(calendarName, cal);
    152         return (cs == null) ? cal : cs;
    153     }
    154 
    155     //////////////////////////////// Calendar API //////////////////////////////////
    156 
    157     /**
    158      * Returns the name of this calendar system.
    159      */
    160     public abstract String getName();
    161 
    162     public abstract CalendarDate getCalendarDate();
    163 
    164     /**
    165      * Calculates calendar fields from the specified number of
    166      * milliseconds since the Epoch, January 1, 1970 00:00:00 UTC
    167      * (Gregorian). This method doesn't check overflow or underflow
    168      * when adjusting the millisecond value (representing UTC) with
    169      * the time zone offsets (i.e., the GMT offset and amount of
    170      * daylight saving).
    171      *
    172      * @param millis the offset value in milliseconds from January 1,
    173      * 1970 00:00:00 UTC (Gregorian).
    174      * @return a <code>CalendarDate</code> instance that contains the
    175      * calculated calendar field values.
    176      */
    177     public abstract CalendarDate getCalendarDate(long millis);
    178 
    179     public abstract CalendarDate getCalendarDate(long millis, CalendarDate date);
    180 
    181     public abstract CalendarDate getCalendarDate(long millis, TimeZone zone);
    182 
    183     /**
    184      * Constructs a <code>CalendarDate</code> that is specific to this
    185      * calendar system. All calendar fields have their initial
    186      * values. The {@link TimeZone#getDefault() default time zone} is
    187      * set to the instance.
    188      *
    189      * @return a <code>CalendarDate</code> instance that contains the initial
    190      * calendar field values.
    191      */
    192     public abstract CalendarDate newCalendarDate();
    193 
    194     public abstract CalendarDate newCalendarDate(TimeZone zone);
    195 
    196     /**
    197      * Returns the number of milliseconds since the Epoch, January 1,
    198      * 1970 00:00:00 UTC (Gregorian), represented by the specified
    199      * <code>CalendarDate</code>.
    200      *
    201      * @param date the <code>CalendarDate</code> from which the time
    202      * value is calculated
    203      * @return the number of milliseconds since the Epoch.
    204      */
    205     public abstract long getTime(CalendarDate date);
    206 
    207     /**
    208      * Returns the length in days of the specified year by
    209      * <code>date</code>. This method does not perform the
    210      * normalization with the specified <code>CalendarDate</code>. The
    211      * <code>CalendarDate</code> must be normalized to get a correct
    212      * value.
    213      */
    214     public abstract int getYearLength(CalendarDate date);
    215 
    216     /**
    217      * Returns the number of months of the specified year. This method
    218      * does not perform the normalization with the specified
    219      * <code>CalendarDate</code>. The <code>CalendarDate</code> must
    220      * be normalized to get a correct value.
    221      */
    222     public abstract int getYearLengthInMonths(CalendarDate date);
    223 
    224     /**
    225      * Returns the length in days of the month specified by the calendar
    226      * date. This method does not perform the normalization with the
    227      * specified calendar date. The <code>CalendarDate</code> must
    228      * be normalized to get a correct value.
    229      *
    230      * @param date the date from which the month value is obtained
    231      * @return the number of days in the month
    232      * @exception IllegalArgumentException if the specified calendar date
    233      * doesn't have a valid month value in this calendar system.
    234      */
    235     public abstract int getMonthLength(CalendarDate date); // no setter
    236 
    237     /**
    238      * Returns the length in days of a week in this calendar
    239      * system. If this calendar system has multiple radix weeks, this
    240      * method returns only one of them.
    241      */
    242     public abstract int getWeekLength();
    243 
    244     /**
    245      * Returns the <code>Era</code> designated by the era name that
    246      * has to be known to this calendar system. If no Era is
    247      * applicable to this calendar system, null is returned.
    248      *
    249      * @param eraName the name of the era
    250      * @return the <code>Era</code> designated by
    251      * <code>eraName</code>, or <code>null</code> if no Era is
    252      * applicable to this calendar system or the specified era name is
    253      * not known to this calendar system.
    254      */
    255     public abstract Era getEra(String eraName);
    256 
    257     /**
    258      * Returns valid <code>Era</code>s of this calendar system. The
    259      * return value is sorted in the descendant order. (i.e., the first
    260      * element of the returned array is the oldest era.) If no era is
    261      * applicable to this calendar system, <code>null</code> is returned.
    262      *
    263      * @return an array of valid <code>Era</code>s, or
    264      * <code>null</code> if no era is applicable to this calendar
    265      * system.
    266      */
    267     public abstract Era[] getEras();
    268 
    269     /**
    270      * @throws IllegalArgumentException if the specified era name is
    271      * unknown to this calendar system.
    272      * @see Era
    273      */
    274     public abstract void setEra(CalendarDate date, String eraName);
    275 
    276     /**
    277      * Returns a <code>CalendarDate</code> of the n-th day of week
    278      * which is on, after or before the specified date. For example, the
    279      * first Sunday in April 2002 (Gregorian) can be obtained as
    280      * below:
    281      *
    282      * <pre><code>
    283      * Gregorian cal = CalendarSystem.getGregorianCalendar();
    284      * CalendarDate date = cal.newCalendarDate();
    285      * date.setDate(2004, cal.APRIL, 1);
    286      * CalendarDate firstSun = cal.getNthDayOfWeek(1, cal.SUNDAY, date);
    287      * // firstSun represents April 4, 2004.
    288      * </code></pre>
    289      *
    290      * This method returns a new <code>CalendarDate</code> instance
    291      * and doesn't modify the original date.
    292      *
    293      * @param nth specifies the n-th one. A positive number specifies
    294      * <em>on or after</em> the <code>date</code>. A non-positive number
    295      * specifies <em>on or before</em> the <code>date</code>.
    296      * @param dayOfWeek the day of week
    297      * @param date the date
    298      * @return the date of the nth <code>dayOfWeek</code> after
    299      * or before the specified <code>CalendarDate</code>
    300      */
    301     public abstract CalendarDate getNthDayOfWeek(int nth, int dayOfWeek,
    302                                                  CalendarDate date);
    303 
    304     public abstract CalendarDate setTimeOfDay(CalendarDate date, int timeOfDay);
    305 
    306     /**
    307      * Checks whether the calendar fields specified by <code>date</code>
    308      * represents a valid date and time in this calendar system. If the
    309      * given date is valid, <code>date</code> is marked as <em>normalized</em>.
    310      *
    311      * @param date the <code>CalendarDate</code> to be validated
    312      * @return <code>true</code> if all the calendar fields are consistent,
    313      * otherwise, <code>false</code> is returned.
    314      * @exception NullPointerException if the specified
    315      * <code>date</code> is <code>null</code>
    316      */
    317     public abstract boolean validate(CalendarDate date);
    318 
    319     /**
    320      * Normalizes calendar fields in the specified
    321      * <code>date</code>. Also all {@link CalendarDate#FIELD_UNDEFINED
    322      * undefined} fields are set to correct values. The actual
    323      * normalization process is calendar system dependent.
    324      *
    325      * @param date the calendar date to be validated
    326      * @return <code>true</code> if all fields have been normalized;
    327      * <code>false</code> otherwise.
    328      * @exception NullPointerException if the specified
    329      * <code>date</code> is <code>null</code>
    330      */
    331     public abstract boolean normalize(CalendarDate date);
    332 }
    333