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