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