1. /*
  2. * @(#)DateFormat.java 1.51 04/04/12
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. /*
  8. * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
  9. * (C) Copyright IBM Corp. 1996 - All Rights Reserved
  10. *
  11. * The original version of this source code and documentation is copyrighted
  12. * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
  13. * materials are provided under terms of a License Agreement between Taligent
  14. * and Sun. This technology is protected by multiple US and International
  15. * patents. This notice and attribution to Taligent may not be removed.
  16. * Taligent is a registered trademark of Taligent, Inc.
  17. *
  18. */
  19. package java.text;
  20. import java.io.InvalidObjectException;
  21. import java.util.HashMap;
  22. import java.util.Locale;
  23. import java.util.Map;
  24. import java.util.ResourceBundle;
  25. import java.util.MissingResourceException;
  26. import java.util.TimeZone;
  27. import java.util.Calendar;
  28. import java.util.GregorianCalendar;
  29. import java.util.Date;
  30. import sun.text.resources.LocaleData;
  31. /**
  32. * DateFormat is an abstract class for date/time formatting subclasses which
  33. * formats and parses dates or time in a language-independent manner.
  34. * The date/time formatting subclass, such as SimpleDateFormat, allows for
  35. * formatting (i.e., date -> text), parsing (text -> date), and
  36. * normalization. The date is represented as a <code>Date</code> object or
  37. * as the milliseconds since January 1, 1970, 00:00:00 GMT.
  38. *
  39. * <p>DateFormat provides many class methods for obtaining default date/time
  40. * formatters based on the default or a given locale and a number of formatting
  41. * styles. The formatting styles include FULL, LONG, MEDIUM, and SHORT. More
  42. * detail and examples of using these styles are provided in the method
  43. * descriptions.
  44. *
  45. * <p>DateFormat helps you to format and parse dates for any locale.
  46. * Your code can be completely independent of the locale conventions for
  47. * months, days of the week, or even the calendar format: lunar vs. solar.
  48. *
  49. * <p>To format a date for the current Locale, use one of the
  50. * static factory methods:
  51. * <pre>
  52. * myString = DateFormat.getDateInstance().format(myDate);
  53. * </pre>
  54. * <p>If you are formatting multiple dates, it is
  55. * more efficient to get the format and use it multiple times so that
  56. * the system doesn't have to fetch the information about the local
  57. * language and country conventions multiple times.
  58. * <pre>
  59. * DateFormat df = DateFormat.getDateInstance();
  60. * for (int i = 0; i < myDate.length; ++i) {
  61. * output.println(df.format(myDate[i]) + "; ");
  62. * }
  63. * </pre>
  64. * <p>To format a date for a different Locale, specify it in the
  65. * call to getDateInstance().
  66. * <pre>
  67. * DateFormat df = DateFormat.getDateInstance(DateFormat.LONG, Locale.FRANCE);
  68. * </pre>
  69. * <p>You can use a DateFormat to parse also.
  70. * <pre>
  71. * myDate = df.parse(myString);
  72. * </pre>
  73. * <p>Use getDateInstance to get the normal date format for that country.
  74. * There are other static factory methods available.
  75. * Use getTimeInstance to get the time format for that country.
  76. * Use getDateTimeInstance to get a date and time format. You can pass in
  77. * different options to these factory methods to control the length of the
  78. * result; from SHORT to MEDIUM to LONG to FULL. The exact result depends
  79. * on the locale, but generally:
  80. * <ul><li>SHORT is completely numeric, such as 12.13.52 or 3:30pm
  81. * <li>MEDIUM is longer, such as Jan 12, 1952
  82. * <li>LONG is longer, such as January 12, 1952 or 3:30:32pm
  83. * <li>FULL is pretty completely specified, such as
  84. * Tuesday, April 12, 1952 AD or 3:30:42pm PST.
  85. * </ul>
  86. *
  87. * <p>You can also set the time zone on the format if you wish.
  88. * If you want even more control over the format or parsing,
  89. * (or want to give your users more control),
  90. * you can try casting the DateFormat you get from the factory methods
  91. * to a SimpleDateFormat. This will work for the majority
  92. * of countries; just remember to put it in a try block in case you
  93. * encounter an unusual one.
  94. *
  95. * <p>You can also use forms of the parse and format methods with
  96. * ParsePosition and FieldPosition to
  97. * allow you to
  98. * <ul><li>progressively parse through pieces of a string.
  99. * <li>align any particular field, or find out where it is for selection
  100. * on the screen.
  101. * </ul>
  102. *
  103. * <h4><a name="synchronization">Synchronization</a></h4>
  104. *
  105. * <p>
  106. * Date formats are not synchronized.
  107. * It is recommended to create separate format instances for each thread.
  108. * If multiple threads access a format concurrently, it must be synchronized
  109. * externally.
  110. *
  111. * @see Format
  112. * @see NumberFormat
  113. * @see SimpleDateFormat
  114. * @see java.util.Calendar
  115. * @see java.util.GregorianCalendar
  116. * @see java.util.TimeZone
  117. * @version 1.51 04/12/04
  118. * @author Mark Davis, Chen-Lieh Huang, Alan Liu
  119. */
  120. public abstract class DateFormat extends Format {
  121. /**
  122. * The calendar that <code>DateFormat</code> uses to produce the time field
  123. * values needed to implement date and time formatting. Subclasses should
  124. * initialize this to a calendar appropriate for the locale associated with
  125. * this <code>DateFormat</code>.
  126. * @serial
  127. */
  128. protected Calendar calendar;
  129. /**
  130. * The number formatter that <code>DateFormat</code> uses to format numbers
  131. * in dates and times. Subclasses should initialize this to a number format
  132. * appropriate for the locale associated with this <code>DateFormat</code>.
  133. * @serial
  134. */
  135. protected NumberFormat numberFormat;
  136. /**
  137. * Useful constant for ERA field alignment.
  138. * Used in FieldPosition of date/time formatting.
  139. */
  140. public final static int ERA_FIELD = 0;
  141. /**
  142. * Useful constant for YEAR field alignment.
  143. * Used in FieldPosition of date/time formatting.
  144. */
  145. public final static int YEAR_FIELD = 1;
  146. /**
  147. * Useful constant for MONTH field alignment.
  148. * Used in FieldPosition of date/time formatting.
  149. */
  150. public final static int MONTH_FIELD = 2;
  151. /**
  152. * Useful constant for DATE field alignment.
  153. * Used in FieldPosition of date/time formatting.
  154. */
  155. public final static int DATE_FIELD = 3;
  156. /**
  157. * Useful constant for one-based HOUR_OF_DAY field alignment.
  158. * Used in FieldPosition of date/time formatting.
  159. * HOUR_OF_DAY1_FIELD is used for the one-based 24-hour clock.
  160. * For example, 23:59 + 01:00 results in 24:59.
  161. */
  162. public final static int HOUR_OF_DAY1_FIELD = 4;
  163. /**
  164. * Useful constant for zero-based HOUR_OF_DAY field alignment.
  165. * Used in FieldPosition of date/time formatting.
  166. * HOUR_OF_DAY0_FIELD is used for the zero-based 24-hour clock.
  167. * For example, 23:59 + 01:00 results in 00:59.
  168. */
  169. public final static int HOUR_OF_DAY0_FIELD = 5;
  170. /**
  171. * Useful constant for MINUTE field alignment.
  172. * Used in FieldPosition of date/time formatting.
  173. */
  174. public final static int MINUTE_FIELD = 6;
  175. /**
  176. * Useful constant for SECOND field alignment.
  177. * Used in FieldPosition of date/time formatting.
  178. */
  179. public final static int SECOND_FIELD = 7;
  180. /**
  181. * Useful constant for MILLISECOND field alignment.
  182. * Used in FieldPosition of date/time formatting.
  183. */
  184. public final static int MILLISECOND_FIELD = 8;
  185. /**
  186. * Useful constant for DAY_OF_WEEK field alignment.
  187. * Used in FieldPosition of date/time formatting.
  188. */
  189. public final static int DAY_OF_WEEK_FIELD = 9;
  190. /**
  191. * Useful constant for DAY_OF_YEAR field alignment.
  192. * Used in FieldPosition of date/time formatting.
  193. */
  194. public final static int DAY_OF_YEAR_FIELD = 10;
  195. /**
  196. * Useful constant for DAY_OF_WEEK_IN_MONTH field alignment.
  197. * Used in FieldPosition of date/time formatting.
  198. */
  199. public final static int DAY_OF_WEEK_IN_MONTH_FIELD = 11;
  200. /**
  201. * Useful constant for WEEK_OF_YEAR field alignment.
  202. * Used in FieldPosition of date/time formatting.
  203. */
  204. public final static int WEEK_OF_YEAR_FIELD = 12;
  205. /**
  206. * Useful constant for WEEK_OF_MONTH field alignment.
  207. * Used in FieldPosition of date/time formatting.
  208. */
  209. public final static int WEEK_OF_MONTH_FIELD = 13;
  210. /**
  211. * Useful constant for AM_PM field alignment.
  212. * Used in FieldPosition of date/time formatting.
  213. */
  214. public final static int AM_PM_FIELD = 14;
  215. /**
  216. * Useful constant for one-based HOUR field alignment.
  217. * Used in FieldPosition of date/time formatting.
  218. * HOUR1_FIELD is used for the one-based 12-hour clock.
  219. * For example, 11:30 PM + 1 hour results in 12:30 AM.
  220. */
  221. public final static int HOUR1_FIELD = 15;
  222. /**
  223. * Useful constant for zero-based HOUR field alignment.
  224. * Used in FieldPosition of date/time formatting.
  225. * HOUR0_FIELD is used for the zero-based 12-hour clock.
  226. * For example, 11:30 PM + 1 hour results in 00:30 AM.
  227. */
  228. public final static int HOUR0_FIELD = 16;
  229. /**
  230. * Useful constant for TIMEZONE field alignment.
  231. * Used in FieldPosition of date/time formatting.
  232. */
  233. public final static int TIMEZONE_FIELD = 17;
  234. // Proclaim serial compatibility with 1.1 FCS
  235. private static final long serialVersionUID = 7218322306649953788L;
  236. /**
  237. * Overrides Format.
  238. * Formats a time object into a time string. Examples of time objects
  239. * are a time value expressed in milliseconds and a Date object.
  240. * @param obj must be a Number or a Date.
  241. * @param toAppendTo the string buffer for the returning time string.
  242. * @return the formatted time string.
  243. * @param fieldPosition keeps track of the position of the field
  244. * within the returned string.
  245. * On input: an alignment field,
  246. * if desired. On output: the offsets of the alignment field. For
  247. * example, given a time text "1996.07.10 AD at 15:08:56 PDT",
  248. * if the given fieldPosition is DateFormat.YEAR_FIELD, the
  249. * begin index and end index of fieldPosition will be set to
  250. * 0 and 4, respectively.
  251. * Notice that if the same time field appears
  252. * more than once in a pattern, the fieldPosition will be set for the first
  253. * occurrence of that time field. For instance, formatting a Date to
  254. * the time string "1 PM PDT (Pacific Daylight Time)" using the pattern
  255. * "h a z (zzzz)" and the alignment field DateFormat.TIMEZONE_FIELD,
  256. * the begin index and end index of fieldPosition will be set to
  257. * 5 and 8, respectively, for the first occurrence of the timezone
  258. * pattern character 'z'.
  259. * @see java.text.Format
  260. */
  261. public final StringBuffer format(Object obj, StringBuffer toAppendTo,
  262. FieldPosition fieldPosition)
  263. {
  264. if (obj instanceof Date)
  265. return format( (Date)obj, toAppendTo, fieldPosition );
  266. else if (obj instanceof Number)
  267. return format( new Date(((Number)obj).longValue()),
  268. toAppendTo, fieldPosition );
  269. else
  270. throw new IllegalArgumentException("Cannot format given Object as a Date");
  271. }
  272. /**
  273. * Formats a Date into a date/time string.
  274. * @param date a Date to be formatted into a date/time string.
  275. * @param toAppendTo the string buffer for the returning date/time string.
  276. * @param fieldPosition keeps track of the position of the field
  277. * within the returned string.
  278. * On input: an alignment field,
  279. * if desired. On output: the offsets of the alignment field. For
  280. * example, given a time text "1996.07.10 AD at 15:08:56 PDT",
  281. * if the given fieldPosition is DateFormat.YEAR_FIELD, the
  282. * begin index and end index of fieldPosition will be set to
  283. * 0 and 4, respectively.
  284. * Notice that if the same time field appears
  285. * more than once in a pattern, the fieldPosition will be set for the first
  286. * occurrence of that time field. For instance, formatting a Date to
  287. * the time string "1 PM PDT (Pacific Daylight Time)" using the pattern
  288. * "h a z (zzzz)" and the alignment field DateFormat.TIMEZONE_FIELD,
  289. * the begin index and end index of fieldPosition will be set to
  290. * 5 and 8, respectively, for the first occurrence of the timezone
  291. * pattern character 'z'.
  292. * @return the formatted date/time string.
  293. */
  294. public abstract StringBuffer format(Date date, StringBuffer toAppendTo,
  295. FieldPosition fieldPosition);
  296. /**
  297. * Formats a Date into a date/time string.
  298. * @param date the time value to be formatted into a time string.
  299. * @return the formatted time string.
  300. */
  301. public final String format(Date date)
  302. {
  303. return format(date, new StringBuffer(),
  304. DontCareFieldPosition.INSTANCE).toString();
  305. }
  306. /**
  307. * Parses text from the beginning of the given string to produce a date.
  308. * The method may not use the entire text of the given string.
  309. * <p>
  310. * See the {@link #parse(String, ParsePosition)} method for more information
  311. * on date parsing.
  312. *
  313. * @param source A <code>String</code> whose beginning should be parsed.
  314. * @return A <code>Date</code> parsed from the string.
  315. * @exception ParseException if the beginning of the specified string
  316. * cannot be parsed.
  317. */
  318. public Date parse(String source) throws ParseException
  319. {
  320. ParsePosition pos = new ParsePosition(0);
  321. Date result = parse(source, pos);
  322. if (pos.index == 0)
  323. throw new ParseException("Unparseable date: \"" + source + "\"" ,
  324. pos.errorIndex);
  325. return result;
  326. }
  327. /**
  328. * Parse a date/time string according to the given parse position. For
  329. * example, a time text "07/10/96 4:5 PM, PDT" will be parsed into a Date
  330. * that is equivalent to Date(837039928046).
  331. *
  332. * <p> By default, parsing is lenient: If the input is not in the form used
  333. * by this object's format method but can still be parsed as a date, then
  334. * the parse succeeds. Clients may insist on strict adherence to the
  335. * format by calling setLenient(false).
  336. *
  337. * @see java.text.DateFormat#setLenient(boolean)
  338. *
  339. * @param source The date/time string to be parsed
  340. *
  341. * @param pos On input, the position at which to start parsing; on
  342. * output, the position at which parsing terminated, or the
  343. * start position if the parse failed.
  344. *
  345. * @return A Date, or null if the input could not be parsed
  346. */
  347. public abstract Date parse(String source, ParsePosition pos);
  348. /**
  349. * Parses text from a string to produce a <code>Date</code>.
  350. * <p>
  351. * The method attempts to parse text starting at the index given by
  352. * <code>pos</code>.
  353. * If parsing succeeds, then the index of <code>pos</code> is updated
  354. * to the index after the last character used (parsing does not necessarily
  355. * use all characters up to the end of the string), and the parsed
  356. * date is returned. The updated <code>pos</code> can be used to
  357. * indicate the starting point for the next call to this method.
  358. * If an error occurs, then the index of <code>pos</code> is not
  359. * changed, the error index of <code>pos</code> is set to the index of
  360. * the character where the error occurred, and null is returned.
  361. * <p>
  362. * See the {@link #parse(String, ParsePosition)} method for more information
  363. * on date parsing.
  364. *
  365. * @param source A <code>String</code>, part of which should be parsed.
  366. * @param pos A <code>ParsePosition</code> object with index and error
  367. * index information as described above.
  368. * @return A <code>Date</code> parsed from the string. In case of
  369. * error, returns null.
  370. * @exception NullPointerException if <code>pos</code> is null.
  371. */
  372. public Object parseObject(String source, ParsePosition pos) {
  373. return parse(source, pos);
  374. }
  375. /**
  376. * Constant for full style pattern.
  377. */
  378. public static final int FULL = 0;
  379. /**
  380. * Constant for long style pattern.
  381. */
  382. public static final int LONG = 1;
  383. /**
  384. * Constant for medium style pattern.
  385. */
  386. public static final int MEDIUM = 2;
  387. /**
  388. * Constant for short style pattern.
  389. */
  390. public static final int SHORT = 3;
  391. /**
  392. * Constant for default style pattern. Its value is MEDIUM.
  393. */
  394. public static final int DEFAULT = MEDIUM;
  395. /**
  396. * Gets the time formatter with the default formatting style
  397. * for the default locale.
  398. * @return a time formatter.
  399. */
  400. public final static DateFormat getTimeInstance()
  401. {
  402. return get(DEFAULT, 0, 1, Locale.getDefault());
  403. }
  404. /**
  405. * Gets the time formatter with the given formatting style
  406. * for the default locale.
  407. * @param style the given formatting style. For example,
  408. * SHORT for "h:mm a" in the US locale.
  409. * @return a time formatter.
  410. */
  411. public final static DateFormat getTimeInstance(int style)
  412. {
  413. return get(style, 0, 1, Locale.getDefault());
  414. }
  415. /**
  416. * Gets the time formatter with the given formatting style
  417. * for the given locale.
  418. * @param style the given formatting style. For example,
  419. * SHORT for "h:mm a" in the US locale.
  420. * @param aLocale the given locale.
  421. * @return a time formatter.
  422. */
  423. public final static DateFormat getTimeInstance(int style,
  424. Locale aLocale)
  425. {
  426. return get(style, 0, 1, aLocale);
  427. }
  428. /**
  429. * Gets the date formatter with the default formatting style
  430. * for the default locale.
  431. * @return a date formatter.
  432. */
  433. public final static DateFormat getDateInstance()
  434. {
  435. return get(0, DEFAULT, 2, Locale.getDefault());
  436. }
  437. /**
  438. * Gets the date formatter with the given formatting style
  439. * for the default locale.
  440. * @param style the given formatting style. For example,
  441. * SHORT for "M/d/yy" in the US locale.
  442. * @return a date formatter.
  443. */
  444. public final static DateFormat getDateInstance(int style)
  445. {
  446. return get(0, style, 2, Locale.getDefault());
  447. }
  448. /**
  449. * Gets the date formatter with the given formatting style
  450. * for the given locale.
  451. * @param style the given formatting style. For example,
  452. * SHORT for "M/d/yy" in the US locale.
  453. * @param aLocale the given locale.
  454. * @return a date formatter.
  455. */
  456. public final static DateFormat getDateInstance(int style,
  457. Locale aLocale)
  458. {
  459. return get(0, style, 2, aLocale);
  460. }
  461. /**
  462. * Gets the date/time formatter with the default formatting style
  463. * for the default locale.
  464. * @return a date/time formatter.
  465. */
  466. public final static DateFormat getDateTimeInstance()
  467. {
  468. return get(DEFAULT, DEFAULT, 3, Locale.getDefault());
  469. }
  470. /**
  471. * Gets the date/time formatter with the given date and time
  472. * formatting styles for the default locale.
  473. * @param dateStyle the given date formatting style. For example,
  474. * SHORT for "M/d/yy" in the US locale.
  475. * @param timeStyle the given time formatting style. For example,
  476. * SHORT for "h:mm a" in the US locale.
  477. * @return a date/time formatter.
  478. */
  479. public final static DateFormat getDateTimeInstance(int dateStyle,
  480. int timeStyle)
  481. {
  482. return get(timeStyle, dateStyle, 3, Locale.getDefault());
  483. }
  484. /**
  485. * Gets the date/time formatter with the given formatting styles
  486. * for the given locale.
  487. * @param dateStyle the given date formatting style.
  488. * @param timeStyle the given time formatting style.
  489. * @param aLocale the given locale.
  490. * @return a date/time formatter.
  491. */
  492. public final static DateFormat
  493. getDateTimeInstance(int dateStyle, int timeStyle, Locale aLocale)
  494. {
  495. return get(timeStyle, dateStyle, 3, aLocale);
  496. }
  497. /**
  498. * Get a default date/time formatter that uses the SHORT style for both the
  499. * date and the time.
  500. */
  501. public final static DateFormat getInstance() {
  502. return getDateTimeInstance(SHORT, SHORT);
  503. }
  504. /**
  505. * Returns an array of all locales for which the
  506. * <code>get*Instance</code> methods of this class can return
  507. * localized instances.
  508. * The array returned must contain at least a <code>Locale</code>
  509. * instance equal to {@link java.util.Locale#US Locale.US}.
  510. *
  511. * @return An array of locales for which localized
  512. * <code>DateFormat</code> instances are available.
  513. */
  514. public static Locale[] getAvailableLocales()
  515. {
  516. return LocaleData.getAvailableLocales("DateTimePatterns");
  517. }
  518. /**
  519. * Set the calendar to be used by this date format. Initially, the default
  520. * calendar for the specified or default locale is used.
  521. * @param newCalendar the new Calendar to be used by the date format
  522. */
  523. public void setCalendar(Calendar newCalendar)
  524. {
  525. this.calendar = newCalendar;
  526. }
  527. /**
  528. * Gets the calendar associated with this date/time formatter.
  529. * @return the calendar associated with this date/time formatter.
  530. */
  531. public Calendar getCalendar()
  532. {
  533. return calendar;
  534. }
  535. /**
  536. * Allows you to set the number formatter.
  537. * @param newNumberFormat the given new NumberFormat.
  538. */
  539. public void setNumberFormat(NumberFormat newNumberFormat)
  540. {
  541. this.numberFormat = newNumberFormat;
  542. }
  543. /**
  544. * Gets the number formatter which this date/time formatter uses to
  545. * format and parse a time.
  546. * @return the number formatter which this date/time formatter uses.
  547. */
  548. public NumberFormat getNumberFormat()
  549. {
  550. return numberFormat;
  551. }
  552. /**
  553. * Sets the time zone for the calendar of this DateFormat object.
  554. * @param zone the given new time zone.
  555. */
  556. public void setTimeZone(TimeZone zone)
  557. {
  558. calendar.setTimeZone(zone);
  559. }
  560. /**
  561. * Gets the time zone.
  562. * @return the time zone associated with the calendar of DateFormat.
  563. */
  564. public TimeZone getTimeZone()
  565. {
  566. return calendar.getTimeZone();
  567. }
  568. /**
  569. * Specify whether or not date/time parsing is to be lenient. With
  570. * lenient parsing, the parser may use heuristics to interpret inputs that
  571. * do not precisely match this object's format. With strict parsing,
  572. * inputs must match this object's format.
  573. * @param lenient when true, parsing is lenient
  574. * @see java.util.Calendar#setLenient
  575. */
  576. public void setLenient(boolean lenient)
  577. {
  578. calendar.setLenient(lenient);
  579. }
  580. /**
  581. * Tell whether date/time parsing is to be lenient.
  582. */
  583. public boolean isLenient()
  584. {
  585. return calendar.isLenient();
  586. }
  587. /**
  588. * Overrides hashCode
  589. */
  590. public int hashCode() {
  591. return numberFormat.hashCode();
  592. // just enough fields for a reasonable distribution
  593. }
  594. /**
  595. * Overrides equals
  596. */
  597. public boolean equals(Object obj) {
  598. if (this == obj) return true;
  599. if (obj == null || getClass() != obj.getClass()) return false;
  600. DateFormat other = (DateFormat) obj;
  601. return (// calendar.equivalentTo(other.calendar) // THIS API DOESN'T EXIST YET!
  602. calendar.getFirstDayOfWeek() == other.calendar.getFirstDayOfWeek() &&
  603. calendar.getMinimalDaysInFirstWeek() == other.calendar.getMinimalDaysInFirstWeek() &&
  604. calendar.isLenient() == other.calendar.isLenient() &&
  605. calendar.getTimeZone().equals(other.calendar.getTimeZone()) &&
  606. numberFormat.equals(other.numberFormat));
  607. }
  608. /**
  609. * Overrides Cloneable
  610. */
  611. public Object clone()
  612. {
  613. DateFormat other = (DateFormat) super.clone();
  614. other.calendar = (Calendar) calendar.clone();
  615. other.numberFormat = (NumberFormat) numberFormat.clone();
  616. return other;
  617. }
  618. /**
  619. * Creates a DateFormat with the given time and/or date style in the given
  620. * locale.
  621. * @param timeStyle a value from 0 to 3 indicating the time format,
  622. * ignored if flags is 2
  623. * @param dateStyle a value from 0 to 3 indicating the time format,
  624. * ignored if flags is 1
  625. * @param flags either 1 for a time format, 2 for a date format,
  626. * or 3 for a date/time format
  627. * @param loc the locale for the format
  628. */
  629. private static DateFormat get(int timeStyle, int dateStyle,
  630. int flags, Locale loc) {
  631. if ((flags & 1) != 0) {
  632. if (timeStyle < 0 || timeStyle > 3) {
  633. throw new IllegalArgumentException("Illegal time style " + timeStyle);
  634. }
  635. } else {
  636. timeStyle = -1;
  637. }
  638. if ((flags & 2) != 0) {
  639. if (dateStyle < 0 || dateStyle > 3) {
  640. throw new IllegalArgumentException("Illegal date style " + dateStyle);
  641. }
  642. } else {
  643. dateStyle = -1;
  644. }
  645. try {
  646. return new SimpleDateFormat(timeStyle, dateStyle, loc);
  647. } catch (MissingResourceException e) {
  648. return new SimpleDateFormat("M/d/yy h:mm a");
  649. }
  650. }
  651. /**
  652. * Create a new date format.
  653. */
  654. protected DateFormat() {}
  655. /**
  656. * Defines constants that are used as attribute keys in the
  657. * <code>AttributedCharacterIterator</code> returned
  658. * from <code>DateFormat.formatToCharacterIterator</code> and as
  659. * field identifiers in <code>FieldPosition</code>.
  660. * <p>
  661. * The class also provides two methods to map
  662. * between its constants and the corresponding Calendar constants.
  663. *
  664. * @since 1.4
  665. * @see java.util.Calendar
  666. */
  667. public static class Field extends Format.Field {
  668. // Proclaim serial compatibility with 1.4 FCS
  669. private static final long serialVersionUID = 7441350119349544720L;
  670. // table of all instances in this class, used by readResolve
  671. private static final Map instanceMap = new HashMap(18);
  672. // Maps from Calendar constant (such as Calendar.ERA) to Field
  673. // constant (such as Field.ERA).
  674. private static final Field[] calendarToFieldMapping =
  675. new Field[Calendar.FIELD_COUNT];
  676. /** Calendar field. */
  677. private int calendarField;
  678. /**
  679. * Returns the <code>Field</code> constant that corresponds to
  680. * the <code>Calendar</code> constant <code>calendarField</code>.
  681. * If there is no direct mapping between the <code>Calendar</code>
  682. * constant and a <code>Field</code>, null is returned.
  683. *
  684. * @throws IllegalArgumentException if <code>calendarField</code> is
  685. * not the value of a <code>Calendar</code> field constant.
  686. * @param calendarField Calendar field constant
  687. * @return Field instance representing calendarField.
  688. * @see java.util.Calendar
  689. */
  690. public static Field ofCalendarField(int calendarField) {
  691. if (calendarField < 0 || calendarField >=
  692. calendarToFieldMapping.length) {
  693. throw new IllegalArgumentException("Unknown Calendar constant "
  694. + calendarField);
  695. }
  696. return calendarToFieldMapping[calendarField];
  697. }
  698. /**
  699. * Creates a Field with the specified name.
  700. * calendarField is used to identify the <code>Calendar</code>
  701. * field this attribute represents. Use -1 if this field does
  702. * not have a corresponding <code>Calendar</code> value.
  703. *
  704. * @param name Name of the attribute
  705. * @param calendarField Calendar constant
  706. */
  707. protected Field(String name, int calendarField) {
  708. super(name);
  709. this.calendarField = calendarField;
  710. if (this.getClass() == DateFormat.Field.class) {
  711. instanceMap.put(name, this);
  712. if (calendarField >= 0) {
  713. // assert(calendarField < Calendar.FIELD_COUNT);
  714. calendarToFieldMapping[calendarField] = this;
  715. }
  716. }
  717. }
  718. /**
  719. * Returns the <code>Calendar</code> field associated with this
  720. * attribute. For example, if this represents the hours field of
  721. * a <code>Calendar</code>, this would return
  722. * <code>Calendar.HOUR</code>. If there is no corresponding
  723. * <code>Calendar</code> constant, this will return -1.
  724. *
  725. * @return Calendar constant for this field
  726. * @see java.util.Calendar
  727. */
  728. public int getCalendarField() {
  729. return calendarField;
  730. }
  731. /**
  732. * Resolves instances being deserialized to the predefined constants.
  733. *
  734. * @throws InvalidObjectException if the constant could not be
  735. * resolved.
  736. * @return resolved DateFormat.Field constant
  737. */
  738. protected Object readResolve() throws InvalidObjectException {
  739. if (this.getClass() != DateFormat.Field.class) {
  740. throw new InvalidObjectException("subclass didn't correctly implement readResolve");
  741. }
  742. Object instance = instanceMap.get(getName());
  743. if (instance != null) {
  744. return instance;
  745. } else {
  746. throw new InvalidObjectException("unknown attribute name");
  747. }
  748. }
  749. //
  750. // The constants
  751. //
  752. /**
  753. * Constant identifying the era field.
  754. */
  755. public final static Field ERA = new Field("era", Calendar.ERA);
  756. /**
  757. * Constant identifying the year field.
  758. */
  759. public final static Field YEAR = new Field("year", Calendar.YEAR);
  760. /**
  761. * Constant identifying the month field.
  762. */
  763. public final static Field MONTH = new Field("month", Calendar.MONTH);
  764. /**
  765. * Constant identifying the day of month field.
  766. */
  767. public final static Field DAY_OF_MONTH = new
  768. Field("day of month", Calendar.DAY_OF_MONTH);
  769. /**
  770. * Constant identifying the hour of day field, where the legal values
  771. * are 1 to 24.
  772. */
  773. public final static Field HOUR_OF_DAY1 = new Field("hour of day 1",-1);
  774. /**
  775. * Constant identifying the hour of day field, where the legal values
  776. * are 0 to 23.
  777. */
  778. public final static Field HOUR_OF_DAY0 = new
  779. Field("hour of day", Calendar.HOUR_OF_DAY);
  780. /**
  781. * Constant identifying the minute field.
  782. */
  783. public final static Field MINUTE =new Field("minute", Calendar.MINUTE);
  784. /**
  785. * Constant identifying the second field.
  786. */
  787. public final static Field SECOND =new Field("second", Calendar.SECOND);
  788. /**
  789. * Constant identifying the millisecond field.
  790. */
  791. public final static Field MILLISECOND = new
  792. Field("millisecond", Calendar.MILLISECOND);
  793. /**
  794. * Constant identifying the day of week field.
  795. */
  796. public final static Field DAY_OF_WEEK = new
  797. Field("day of week", Calendar.DAY_OF_WEEK);
  798. /**
  799. * Constant identifying the day of year field.
  800. */
  801. public final static Field DAY_OF_YEAR = new
  802. Field("day of year", Calendar.DAY_OF_YEAR);
  803. /**
  804. * Constant identifying the day of week field.
  805. */
  806. public final static Field DAY_OF_WEEK_IN_MONTH =
  807. new Field("day of week in month",
  808. Calendar.DAY_OF_WEEK_IN_MONTH);
  809. /**
  810. * Constant identifying the week of year field.
  811. */
  812. public final static Field WEEK_OF_YEAR = new
  813. Field("week of year", Calendar.WEEK_OF_YEAR);
  814. /**
  815. * Constant identifying the week of month field.
  816. */
  817. public final static Field WEEK_OF_MONTH = new
  818. Field("week of month", Calendar.WEEK_OF_MONTH);
  819. /**
  820. * Constant identifying the time of day indicator
  821. * (e.g. "a.m." or "p.m.") field.
  822. */
  823. public final static Field AM_PM = new
  824. Field("am pm", Calendar.AM_PM);
  825. /**
  826. * Constant identifying the hour field, where the legal values are
  827. * 1 to 12.
  828. */
  829. public final static Field HOUR1 = new Field("hour 1", -1);
  830. /**
  831. * Constant identifying the hour field, where the legal values are
  832. * 0 to 11.
  833. */
  834. public final static Field HOUR0 = new
  835. Field("hour", Calendar.HOUR);
  836. /**
  837. * Constant identifying the time zone field.
  838. */
  839. public final static Field TIME_ZONE = new Field("time zone", -1);
  840. }
  841. }