DateFormatSymbols.java revision 8ee76d4d3ee58109f859964e56d5c7f3d8c566d9
1/* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18// BEGIN android-note 19// The icu implementation used was changed from icu4j to icu4jni. 20// END android-note 21 22package java.text; 23 24import java.io.IOException; 25import java.io.ObjectOutputStream; 26import java.io.Serializable; 27import java.util.Arrays; 28import java.util.Locale; 29// BEGIN android-added 30import java.util.ResourceBundle; 31// END android-added 32 33// BEGIN android-added 34import com.ibm.icu4jni.util.LocaleData; 35import com.ibm.icu4jni.util.Resources; 36// END android-added 37/** 38 * Encapsulates localizable date-time formatting data, such as the names of the 39 * months, the names of the days of the week, and the time zone data. 40 * {@code DateFormat} and {@code SimpleDateFormat} both use 41 * {@code DateFormatSymbols} to encapsulate this information. 42 * <p> 43 * Typically you shouldn't use {@code DateFormatSymbols} directly. Rather, you 44 * are encouraged to create a date/time formatter with the {@code DateFormat} 45 * class's factory methods: {@code getTimeInstance}, {@code getDateInstance}, 46 * or {@code getDateTimeInstance}. These methods automatically create a 47 * {@code DateFormatSymbols} for the formatter so that you don't have to. After 48 * the formatter is created, you may modify its format pattern using the 49 * {@code setPattern} method. For more information about creating formatters 50 * using {@code DateFormat}'s factory methods, see {@link DateFormat}. 51 * <p> 52 * If you decide to create a date/time formatter with a specific format pattern 53 * for a specific locale, you can do so with: 54 * <blockquote> 55 * 56 * <pre> 57 * new SimpleDateFormat(aPattern, new DateFormatSymbols(aLocale)). 58 * </pre> 59 * 60 * </blockquote> 61 * <p> 62 * {@code DateFormatSymbols} objects can be cloned. When you obtain a 63 * {@code DateFormatSymbols} object, feel free to modify the date/time 64 * formatting data. For instance, you can replace the localized date/time format 65 * pattern characters with the ones that you feel easy to remember or you can 66 * change the representative cities to your favorite ones. 67 * <p> 68 * New {@code DateFormatSymbols} subclasses may be added to support 69 * {@code SimpleDateFormat} for date/time formatting for additional locales. 70 * 71 * @see DateFormat 72 * @see SimpleDateFormat 73 */ 74public class DateFormatSymbols implements Serializable, Cloneable { 75 76 private static final long serialVersionUID = -5987973545549424702L; 77 78 private String localPatternChars; 79 80 String[] ampms, eras, months, shortMonths, shortWeekdays, weekdays; 81 82 // Localized display names. 83 String[][] zoneStrings; 84 // Has the user called setZoneStrings? 85 transient boolean customZoneStrings; 86 87 // BEGIN android-removed 88 // transient private com.ibm.icu4jni.text.DateFormatSymbols icuSymbols; 89 // END android-removed 90 91// BEGIN android-added 92 /** 93 * Locale, necessary to lazily load time zone strings. We force the time 94 * zone names to load upon serialization, so this will never be needed 95 * post deserialization. 96 */ 97 transient final Locale locale; 98 99 /** 100 * Gets zone strings, initializing them if necessary. Does not create 101 * a defensive copy, so make sure you do so before exposing the returned 102 * arrays to clients. 103 */ 104 synchronized String[][] internalZoneStrings() { 105 if (zoneStrings == null) { 106 zoneStrings = Resources.getDisplayTimeZones(locale.toString()); 107 } 108 return zoneStrings; 109 } 110// END android-added 111 112 /** 113 * Constructs a new {@code DateFormatSymbols} instance containing the 114 * symbols for the default locale. 115 */ 116 public DateFormatSymbols() { 117 this(Locale.getDefault()); 118 } 119 120 /** 121 * Constructs a new {@code DateFormatSymbols} instance containing the 122 * symbols for the specified locale. 123 * 124 * @param locale 125 * the locale. 126 */ 127 public DateFormatSymbols(Locale locale) { 128 this.locale = locale; 129 // BEGIN android-changed 130 this.localPatternChars = SimpleDateFormat.patternChars; 131 LocaleData localeData = com.ibm.icu4jni.util.Resources.getLocaleData(locale); 132 this.ampms = localeData.amPm; 133 this.eras = localeData.eras; 134 this.months = localeData.longMonthNames; 135 this.shortMonths = localeData.shortMonthNames; 136 this.weekdays = localeData.longWeekdayNames; 137 this.shortWeekdays = localeData.shortWeekdayNames; 138 // END android-changed 139 } 140 141 142 private void writeObject(ObjectOutputStream oos) throws IOException { 143 // BEGIN android-changed 144 internalZoneStrings(); 145 // END android-changed 146 oos.defaultWriteObject(); 147 } 148 149 // BEGIN android-removed 150 // DateFormatSymbols(Locale locale, 151 // com.ibm.icu4jni.text.DateFormatSymbols icuSymbols) { 152 // 153 // this.icuSymbols = icuSymbols; 154 // localPatternChars = icuSymbols.getLocalPatternChars(); 155 // ampms = icuSymbols.getAmPmStrings(); 156 // eras = icuSymbols.getEras(); 157 // months = icuSymbols.getMonths(); 158 // shortMonths = icuSymbols.getShortMonths(); 159 // shortWeekdays = icuSymbols.getShortWeekdays(); 160 // weekdays = icuSymbols.getWeekdays(); 161 // } 162 // END android-removed 163 164 @Override 165 public Object clone() { 166 // BEGIN android-changed 167 try { 168 return super.clone(); 169 } catch (CloneNotSupportedException e) { 170 throw new AssertionError(); 171 } 172 // END android-changed 173 } 174 175 /** 176 * Compares this object with the specified object and indicates if they are 177 * equal. 178 * 179 * @param object 180 * the object to compare with this object. 181 * @return {@code true} if {@code object} is an instance of 182 * {@code DateFormatSymbols} and has the same symbols as this 183 * object, {@code false} otherwise. 184 * @see #hashCode 185 */ 186 @Override 187 public boolean equals(Object object) { 188 if (this == object) { 189 return true; 190 } 191 if (!(object instanceof DateFormatSymbols)) { 192 return false; 193 } 194 195 // BEGIN android-removed 196 // if (zoneStrings == null) { 197 // zoneStrings = icuSymbols.getZoneStrings(); 198 // } 199 // END android-removed 200 DateFormatSymbols obj = (DateFormatSymbols) object; 201 // BEGIN android-removed 202 // if (obj.zoneStrings == null) { 203 // obj.zoneStrings = obj.icuSymbols.getZoneStrings(); 204 // } 205 // END android-removed 206 if (!localPatternChars.equals(obj.localPatternChars)) { 207 return false; 208 } 209 if (!Arrays.equals(ampms, obj.ampms)) { 210 return false; 211 } 212 if (!Arrays.equals(eras, obj.eras)) { 213 return false; 214 } 215 if (!Arrays.equals(months, obj.months)) { 216 return false; 217 } 218 if (!Arrays.equals(shortMonths, obj.shortMonths)) { 219 return false; 220 } 221 if (!Arrays.equals(shortWeekdays, obj.shortWeekdays)) { 222 return false; 223 } 224 if (!Arrays.equals(weekdays, obj.weekdays)) { 225 return false; 226 } 227 // BEGIN android-changed 228 // Quick check that may keep us from having to load the zone strings. 229 if (zoneStrings == null && obj.zoneStrings == null 230 && !locale.equals(obj.locale)) { 231 return false; 232 } 233 // Make sure zone strings are loaded. 234 internalZoneStrings(); 235 obj.internalZoneStrings(); 236 // END android-changed 237 if (zoneStrings.length != obj.zoneStrings.length) { 238 return false; 239 } 240 for (String[] element : zoneStrings) { 241 if (element.length != element.length) { 242 return false; 243 } 244 for (int j = 0; j < element.length; j++) { 245 if (element[j] != element[j] 246 && !(element[j].equals(element[j]))) { 247 return false; 248 } 249 } 250 } 251 return true; 252 } 253 254 /** 255 * Returns the array of strings which represent AM and PM. Use the 256 * {@link java.util.Calendar} constants {@code Calendar.AM} and 257 * {@code Calendar.PM} as indices for the array. 258 * 259 * @return an array of strings. 260 */ 261 public String[] getAmPmStrings() { 262 return ampms.clone(); 263 } 264 265 /** 266 * Returns the array of strings which represent BC and AD. Use the 267 * {@link java.util.Calendar} constants {@code GregorianCalendar.BC} and 268 * {@code GregorianCalendar.AD} as indices for the array. 269 * 270 * @return an array of strings. 271 */ 272 public String[] getEras() { 273 return eras.clone(); 274 } 275 276 /** 277 * Returns the pattern characters used by {@link SimpleDateFormat} to 278 * specify date and time fields. 279 * 280 * @return a string containing the pattern characters. 281 */ 282 public String getLocalPatternChars() { 283 return localPatternChars; 284 } 285 286 /** 287 * Returns the array of strings containing the full names of the months. Use 288 * the {@link java.util.Calendar} constants {@code Calendar.JANUARY} etc. as 289 * indices for the array. 290 * 291 * @return an array of strings. 292 */ 293 public String[] getMonths() { 294 return months.clone(); 295 } 296 297 /** 298 * Returns the array of strings containing the abbreviated names of the 299 * months. Use the {@link java.util.Calendar} constants 300 * {@code Calendar.JANUARY} etc. as indices for the array. 301 * 302 * @return an array of strings. 303 */ 304 public String[] getShortMonths() { 305 return shortMonths.clone(); 306 } 307 308 /** 309 * Returns the array of strings containing the abbreviated names of the days 310 * of the week. Use the {@link java.util.Calendar} constants 311 * {@code Calendar.SUNDAY} etc. as indices for the array. 312 * 313 * @return an array of strings. 314 */ 315 public String[] getShortWeekdays() { 316 return shortWeekdays.clone(); 317 } 318 319 /** 320 * Returns the array of strings containing the full names of the days of the 321 * week. Use the {@link java.util.Calendar} constants 322 * {@code Calendar.SUNDAY} etc. as indices for the array. 323 * 324 * @return an array of strings. 325 */ 326 public String[] getWeekdays() { 327 return weekdays.clone(); 328 } 329 330 /** 331 * Returns the two-dimensional array of strings containing the names of the 332 * time zones. Each element in the array is an array of five strings, the 333 * first is a TimeZone ID, the second and third are the full and abbreviated 334 * time zone names for standard time, and the fourth and fifth are the full 335 * and abbreviated names for daylight time. 336 * 337 * @return a two-dimensional array of strings. 338 */ 339 public String[][] getZoneStrings() { 340 // BEGIN android-changed 341 return Resources.clone2dStringArray(internalZoneStrings()); 342 // END android-changed 343 } 344 345 @Override 346 public int hashCode() { 347 // BEGIN android-changed 348 String[][] zoneStrings = internalZoneStrings(); 349 // END android-changed 350 int hashCode; 351 hashCode = localPatternChars.hashCode(); 352 for (String element : ampms) { 353 hashCode += element.hashCode(); 354 } 355 for (String element : eras) { 356 hashCode += element.hashCode(); 357 } 358 for (String element : months) { 359 hashCode += element.hashCode(); 360 } 361 for (String element : shortMonths) { 362 hashCode += element.hashCode(); 363 } 364 for (String element : shortWeekdays) { 365 hashCode += element.hashCode(); 366 } 367 for (String element : weekdays) { 368 hashCode += element.hashCode(); 369 } 370 for (String[] element : zoneStrings) { 371 for (int j = 0; j < element.length; j++) { 372 if (element[j] != null) { 373 hashCode += element[j].hashCode(); 374 } 375 } 376 } 377 return hashCode; 378 } 379 380 /** 381 * Sets the array of strings which represent AM and PM. Use the 382 * {@link java.util.Calendar} constants {@code Calendar.AM} and 383 * {@code Calendar.PM} as indices for the array. 384 * 385 * @param data 386 * the array of strings for AM and PM. 387 */ 388 public void setAmPmStrings(String[] data) { 389 ampms = data.clone(); 390 } 391 392 /** 393 * Sets the array of Strings which represent BC and AD. Use the 394 * {@link java.util.Calendar} constants {@code GregorianCalendar.BC} and 395 * {@code GregorianCalendar.AD} as indices for the array. 396 * 397 * @param data 398 * the array of strings for BC and AD. 399 */ 400 public void setEras(String[] data) { 401 eras = data.clone(); 402 } 403 404 /** 405 * Sets the pattern characters used by {@link SimpleDateFormat} to specify 406 * date and time fields. 407 * 408 * @param data 409 * the string containing the pattern characters. 410 * @throws NullPointerException 411 * if {@code data} is null 412 */ 413 public void setLocalPatternChars(String data) { 414 if (data == null) { 415 throw new NullPointerException(); 416 } 417 localPatternChars = data; 418 } 419 420 /** 421 * Sets the array of strings containing the full names of the months. Use 422 * the {@link java.util.Calendar} constants {@code Calendar.JANUARY} etc. as 423 * indices for the array. 424 * 425 * @param data 426 * the array of strings. 427 */ 428 public void setMonths(String[] data) { 429 months = data.clone(); 430 } 431 432 /** 433 * Sets the array of strings containing the abbreviated names of the months. 434 * Use the {@link java.util.Calendar} constants {@code Calendar.JANUARY} 435 * etc. as indices for the array. 436 * 437 * @param data 438 * the array of strings. 439 */ 440 public void setShortMonths(String[] data) { 441 shortMonths = data.clone(); 442 } 443 444 /** 445 * Sets the array of strings containing the abbreviated names of the days of 446 * the week. Use the {@link java.util.Calendar} constants 447 * {@code Calendar.SUNDAY} etc. as indices for the array. 448 * 449 * @param data 450 * the array of strings. 451 */ 452 public void setShortWeekdays(String[] data) { 453 shortWeekdays = data.clone(); 454 } 455 456 /** 457 * Sets the array of strings containing the full names of the days of the 458 * week. Use the {@link java.util.Calendar} constants 459 * {@code Calendar.SUNDAY} etc. as indices for the array. 460 * 461 * @param data 462 * the array of strings. 463 */ 464 public void setWeekdays(String[] data) { 465 weekdays = data.clone(); 466 } 467 468 /** 469 * Sets the two-dimensional array of strings containing the names of the 470 * time zones. Each element in the array is an array of five strings, the 471 * first is a TimeZone ID, and second and third are the full and abbreviated 472 * time zone names for standard time, and the fourth and fifth are the full 473 * and abbreviated names for daylight time. 474 * 475 * @param data 476 * the two-dimensional array of strings. 477 */ 478 public void setZoneStrings(String[][] data) { 479 zoneStrings = Resources.clone2dStringArray(data); 480 customZoneStrings = true; 481 } 482} 483