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 Class<?> cl = Class.forName(className); 161 cal = (CalendarSystem) cl.newInstance(); 162 } catch (Exception e) { 163 throw new InternalError(e); 164 } 165 } 166 if (cal == null) { 167 return null; 168 } 169 CalendarSystem cs = calendars.putIfAbsent(calendarName, cal); 170 return (cs == null) ? cal : cs; 171 } 172 173 //////////////////////////////// Calendar API ////////////////////////////////// 174 175 /** 176 * Returns the name of this calendar system. 177 */ 178 public abstract String getName(); 179 180 public abstract CalendarDate getCalendarDate(); 181 182 /** 183 * Calculates calendar fields from the specified number of 184 * milliseconds since the Epoch, January 1, 1970 00:00:00 UTC 185 * (Gregorian). This method doesn't check overflow or underflow 186 * when adjusting the millisecond value (representing UTC) with 187 * the time zone offsets (i.e., the GMT offset and amount of 188 * daylight saving). 189 * 190 * @param millis the offset value in milliseconds from January 1, 191 * 1970 00:00:00 UTC (Gregorian). 192 * @return a <code>CalendarDate</code> instance that contains the 193 * calculated calendar field values. 194 */ 195 public abstract CalendarDate getCalendarDate(long millis); 196 197 public abstract CalendarDate getCalendarDate(long millis, CalendarDate date); 198 199 public abstract CalendarDate getCalendarDate(long millis, TimeZone zone); 200 201 /** 202 * Constructs a <code>CalendarDate</code> that is specific to this 203 * calendar system. All calendar fields have their initial 204 * values. The {@link TimeZone#getDefault() default time zone} is 205 * set to the instance. 206 * 207 * @return a <code>CalendarDate</code> instance that contains the initial 208 * calendar field values. 209 */ 210 public abstract CalendarDate newCalendarDate(); 211 212 public abstract CalendarDate newCalendarDate(TimeZone zone); 213 214 /** 215 * Returns the number of milliseconds since the Epoch, January 1, 216 * 1970 00:00:00 UTC (Gregorian), represented by the specified 217 * <code>CalendarDate</code>. 218 * 219 * @param date the <code>CalendarDate</code> from which the time 220 * value is calculated 221 * @return the number of milliseconds since the Epoch. 222 */ 223 public abstract long getTime(CalendarDate date); 224 225 /** 226 * Returns the length in days of the specified year by 227 * <code>date</code>. This method does not perform the 228 * normalization with the specified <code>CalendarDate</code>. The 229 * <code>CalendarDate</code> must be normalized to get a correct 230 * value. 231 */ 232 public abstract int getYearLength(CalendarDate date); 233 234 /** 235 * Returns the number of months of the specified year. This method 236 * does not perform the normalization with the specified 237 * <code>CalendarDate</code>. The <code>CalendarDate</code> must 238 * be normalized to get a correct value. 239 */ 240 public abstract int getYearLengthInMonths(CalendarDate date); 241 242 /** 243 * Returns the length in days of the month specified by the calendar 244 * date. This method does not perform the normalization with the 245 * specified calendar date. The <code>CalendarDate</code> must 246 * be normalized to get a correct value. 247 * 248 * @param date the date from which the month value is obtained 249 * @return the number of days in the month 250 * @exception IllegalArgumentException if the specified calendar date 251 * doesn't have a valid month value in this calendar system. 252 */ 253 public abstract int getMonthLength(CalendarDate date); // no setter 254 255 /** 256 * Returns the length in days of a week in this calendar 257 * system. If this calendar system has multiple radix weeks, this 258 * method returns only one of them. 259 */ 260 public abstract int getWeekLength(); 261 262 /** 263 * Returns the <code>Era</code> designated by the era name that 264 * has to be known to this calendar system. If no Era is 265 * applicable to this calendar system, null is returned. 266 * 267 * @param eraName the name of the era 268 * @return the <code>Era</code> designated by 269 * <code>eraName</code>, or <code>null</code> if no Era is 270 * applicable to this calendar system or the specified era name is 271 * not known to this calendar system. 272 */ 273 public abstract Era getEra(String eraName); 274 275 /** 276 * Returns valid <code>Era</code>s of this calendar system. The 277 * return value is sorted in the descendant order. (i.e., the first 278 * element of the returned array is the oldest era.) If no era is 279 * applicable to this calendar system, <code>null</code> is returned. 280 * 281 * @return an array of valid <code>Era</code>s, or 282 * <code>null</code> if no era is applicable to this calendar 283 * system. 284 */ 285 public abstract Era[] getEras(); 286 287 /** 288 * @throws IllegalArgumentException if the specified era name is 289 * unknown to this calendar system. 290 * @see Era 291 */ 292 public abstract void setEra(CalendarDate date, String eraName); 293 294 /** 295 * Returns a <code>CalendarDate</code> of the n-th day of week 296 * which is on, after or before the specified date. For example, the 297 * first Sunday in April 2002 (Gregorian) can be obtained as 298 * below: 299 * 300 * <pre><code> 301 * Gregorian cal = CalendarSystem.getGregorianCalendar(); 302 * CalendarDate date = cal.newCalendarDate(); 303 * date.setDate(2004, cal.APRIL, 1); 304 * CalendarDate firstSun = cal.getNthDayOfWeek(1, cal.SUNDAY, date); 305 * // firstSun represents April 4, 2004. 306 * </code></pre> 307 * 308 * This method returns a new <code>CalendarDate</code> instance 309 * and doesn't modify the original date. 310 * 311 * @param nth specifies the n-th one. A positive number specifies 312 * <em>on or after</em> the <code>date</code>. A non-positive number 313 * specifies <em>on or before</em> the <code>date</code>. 314 * @param dayOfWeek the day of week 315 * @param date the date 316 * @return the date of the nth <code>dayOfWeek</code> after 317 * or before the specified <code>CalendarDate</code> 318 */ 319 public abstract CalendarDate getNthDayOfWeek(int nth, int dayOfWeek, 320 CalendarDate date); 321 322 public abstract CalendarDate setTimeOfDay(CalendarDate date, int timeOfDay); 323 324 /** 325 * Checks whether the calendar fields specified by <code>date</code> 326 * represents a valid date and time in this calendar system. If the 327 * given date is valid, <code>date</code> is marked as <em>normalized</em>. 328 * 329 * @param date the <code>CalendarDate</code> to be validated 330 * @return <code>true</code> if all the calendar fields are consistent, 331 * otherwise, <code>false</code> is returned. 332 * @exception NullPointerException if the specified 333 * <code>date</code> is <code>null</code> 334 */ 335 public abstract boolean validate(CalendarDate date); 336 337 /** 338 * Normalizes calendar fields in the specified 339 * <code>date</code>. Also all {@link CalendarDate#FIELD_UNDEFINED 340 * undefined} fields are set to correct values. The actual 341 * normalization process is calendar system dependent. 342 * 343 * @param date the calendar date to be validated 344 * @return <code>true</code> if all fields have been normalized; 345 * <code>false</code> otherwise. 346 * @exception NullPointerException if the specified 347 * <code>date</code> is <code>null</code> 348 */ 349 public abstract boolean normalize(CalendarDate date); 350 }