1 /* 2 * Copyright (c) 2000, 2010, 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; 27 28 import java.io.IOException; 29 import java.io.ObjectInputStream; 30 import java.util.Calendar; 31 import java.util.GregorianCalendar; 32 import java.util.HashMap; 33 import java.util.Locale; 34 import java.util.Map; 35 import java.util.ResourceBundle; 36 import java.util.TimeZone; 37 import sun.util.resources.LocaleData; 38 39 public class BuddhistCalendar extends GregorianCalendar { 40 41 ////////////////// 42 // Class Variables 43 ////////////////// 44 45 private static final long serialVersionUID = -8527488697350388578L; 46 47 private static final int BUDDHIST_YEAR_OFFSET = 543; 48 49 /////////////// 50 // Constructors 51 /////////////// 52 53 /** 54 * Constructs a default BuddhistCalendar using the current time 55 * in the default time zone with the default locale. 56 */ 57 public BuddhistCalendar() { 58 super(); 59 } 60 61 /** 62 * Constructs a BuddhistCalendar based on the current time 63 * in the given time zone with the default locale. 64 * @param zone the given time zone. 65 */ 66 public BuddhistCalendar(TimeZone zone) { 67 super(zone); 68 } 69 70 /** 71 * Constructs a BuddhistCalendar based on the current time 72 * in the default time zone with the given locale. 73 * @param aLocale the given locale. 74 */ 75 public BuddhistCalendar(Locale aLocale) { 76 super(aLocale); 77 } 78 79 /** 80 * Constructs a BuddhistCalendar based on the current time 81 * in the given time zone with the given locale. 82 * @param zone the given time zone. 83 * @param aLocale the given locale. 84 */ 85 public BuddhistCalendar(TimeZone zone, Locale aLocale) { 86 super(zone, aLocale); 87 } 88 89 ///////////////// 90 // Public methods 91 ///////////////// 92 93 /** 94 * Compares this BuddhistCalendar to an object reference. 95 * @param obj the object reference with which to compare 96 * @return true if this object is equal to <code>obj</code>; false otherwise 97 */ 98 public boolean equals(Object obj) { 99 return obj instanceof BuddhistCalendar 100 && super.equals(obj); 101 } 102 103 /** 104 * Override hashCode. 105 * Generates the hash code for the BuddhistCalendar object 106 */ 107 public int hashCode() { 108 return super.hashCode() ^ BUDDHIST_YEAR_OFFSET; 109 } 110 111 /** 112 * Gets the value for a given time field. 113 * @param field the given time field. 114 * @return the value for the given time field. 115 */ 116 public int get(int field) 117 { 118 if (field == YEAR) { 119 return super.get(field) + yearOffset; 120 } 121 return super.get(field); 122 } 123 124 /** 125 * Sets the time field with the given value. 126 * @param field the given time field. 127 * @param value the value to be set for the given time field. 128 */ 129 public void set(int field, int value) 130 { 131 if (field == YEAR) { 132 super.set(field, value - yearOffset); 133 } else { 134 super.set(field, value); 135 } 136 } 137 138 /** 139 * Adds the specified (signed) amount of time to the given time field. 140 * @param field the time field. 141 * @param amount the amount of date or time to be added to the field. 142 */ 143 public void add(int field, int amount) 144 { 145 int savedYearOffset = yearOffset; 146 // To let the superclass calculate date-time values correctly, 147 // temporarily make this GregorianCalendar. 148 yearOffset = 0; 149 try { 150 super.add(field, amount); 151 } finally { 152 yearOffset = savedYearOffset; 153 } 154 } 155 156 /** 157 * Add to field a signed amount without changing larger fields. 158 * A negative roll amount means to subtract from field without changing 159 * larger fields. 160 * @param field the time field. 161 * @param amount the signed amount to add to <code>field</code>. 162 */ 163 public void roll(int field, int amount) 164 { 165 int savedYearOffset = yearOffset; 166 // To let the superclass calculate date-time values correctly, 167 // temporarily make this GregorianCalendar. 168 yearOffset = 0; 169 try { 170 super.roll(field, amount); 171 } finally { 172 yearOffset = savedYearOffset; 173 } 174 } 175 176 public String getDisplayName(int field, int style, Locale locale) { 177 if (field != ERA) { 178 return super.getDisplayName(field, style, locale); 179 } 180 181 // Handle Thai BuddhistCalendar specific era names 182 if (field < 0 || field >= fields.length || 183 style < SHORT || style > LONG) { 184 throw new IllegalArgumentException(); 185 } 186 if (locale == null) { 187 throw new NullPointerException(); 188 } 189 ResourceBundle rb = LocaleData.getDateFormatData(locale); 190 String[] eras = rb.getStringArray(getKey(style)); 191 return eras[get(field)]; 192 } 193 194 public Map<String,Integer> getDisplayNames(int field, int style, Locale locale) { 195 if (field != ERA) { 196 return super.getDisplayNames(field, style, locale); 197 } 198 199 // Handle Thai BuddhistCalendar specific era names 200 if (field < 0 || field >= fields.length || 201 style < ALL_STYLES || style > LONG) { 202 throw new IllegalArgumentException(); 203 } 204 if (locale == null) { 205 throw new NullPointerException(); 206 } 207 // ALL_STYLES 208 if (style == ALL_STYLES) { 209 Map<String,Integer> shortNames = getDisplayNamesImpl(field, SHORT, locale); 210 Map<String,Integer> longNames = getDisplayNamesImpl(field, LONG, locale); 211 if (shortNames == null) { 212 return longNames; 213 } 214 if (longNames != null) { 215 shortNames.putAll(longNames); 216 } 217 return shortNames; 218 } 219 220 // SHORT or LONG 221 return getDisplayNamesImpl(field, style, locale); 222 } 223 224 private Map<String,Integer> getDisplayNamesImpl(int field, int style, Locale locale) { 225 ResourceBundle rb = LocaleData.getDateFormatData(locale); 226 String[] eras = rb.getStringArray(getKey(style)); 227 Map<String,Integer> map = new HashMap<String,Integer>(4); 228 for (int i = 0; i < eras.length; i++) { 229 map.put(eras[i], i); 230 } 231 return map; 232 } 233 234 private String getKey(int style) { 235 StringBuilder key = new StringBuilder(); 236 key.append(BuddhistCalendar.class.getName()); 237 if (style == SHORT) { 238 key.append(".short"); 239 } 240 key.append(".Eras"); 241 return key.toString(); 242 } 243 244 /** 245 * Returns the maximum value that this field could have, given the 246 * current date. For example, with the date "Feb 3, 2540" and the 247 * <code>DAY_OF_MONTH</code> field, the actual maximum is 28; for 248 * "Feb 3, 2539" it is 29. 249 * 250 * @param field the field to determine the maximum of 251 * @return the maximum of the given field for the current date of this Calendar 252 */ 253 public int getActualMaximum(int field) { 254 int savedYearOffset = yearOffset; 255 // To let the superclass calculate date-time values correctly, 256 // temporarily make this GregorianCalendar. 257 yearOffset = 0; 258 try { 259 return super.getActualMaximum(field); 260 } finally { 261 yearOffset = savedYearOffset; 262 } 263 } 264 265 public String toString() { 266 // The super class produces a String with the Gregorian year 267 // value (or '?') 268 String s = super.toString(); 269 // If the YEAR field is UNSET, then return the Gregorian string. 270 if (!isSet(YEAR)) { 271 return s; 272 } 273 274 final String yearField = "YEAR="; 275 int p = s.indexOf(yearField); 276 // If the string doesn't include the year value for some 277 // reason, then return the Gregorian string. 278 if (p == -1) { 279 return s; 280 } 281 p += yearField.length(); 282 StringBuilder sb = new StringBuilder(s.substring(0, p)); 283 // Skip the year number 284 while (Character.isDigit(s.charAt(p++))) 285 ; 286 int year = internalGet(YEAR) + BUDDHIST_YEAR_OFFSET; 287 sb.append(year).append(s.substring(p - 1)); 288 return sb.toString(); 289 } 290 291 private transient int yearOffset = BUDDHIST_YEAR_OFFSET; 292 293 private void readObject(ObjectInputStream stream) 294 throws IOException, ClassNotFoundException { 295 stream.defaultReadObject(); 296 yearOffset = BUDDHIST_YEAR_OFFSET; 297 } 298 }