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