1. /*
  2. * @(#)DateFormat.java 1.38 00/01/19
  3. *
  4. * Copyright 1996-2000 Sun Microsystems, Inc. All Rights Reserved.
  5. *
  6. * This software is the proprietary information of Sun Microsystems, Inc.
  7. * Use is subject to license terms.
  8. *
  9. */
  10. /*
  11. * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
  12. * (C) Copyright IBM Corp. 1996 - All Rights Reserved
  13. *
  14. * The original version of this source code and documentation is copyrighted
  15. * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
  16. * materials are provided under terms of a License Agreement between Taligent
  17. * and Sun. This technology is protected by multiple US and International
  18. * patents. This notice and attribution to Taligent may not be removed.
  19. * Taligent is a registered trademark of Taligent, Inc.
  20. *
  21. */
  22. package java.text;
  23. import java.util.Locale;
  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 java.text.resources.*;
  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 loacle 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 numbers, 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 < a.length; ++i) {
  61. * output.println(df.format(myDate[i]) + "; ");
  62. * }
  63. * </pre>
  64. * <p>To format a number for a different Locale, specify it in the
  65. * call to getDateInstance().
  66. * <pre>
  67. * DateFormat df = DateFormat.getDateInstance(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. * @see Format
  104. * @see NumberFormat
  105. * @see SimpleDateFormat
  106. * @see java.util.Calendar
  107. * @see java.util.GregorianCalendar
  108. * @see java.util.TimeZone
  109. * @version 1.38 01/19/00
  110. * @author Mark Davis, Chen-Lieh Huang, Alan Liu
  111. */
  112. public abstract class DateFormat extends Format {
  113. /**
  114. * The calendar that <code>DateFormat</code> uses to produce the time field
  115. * values needed to implement date and time formatting. Subclasses should
  116. * initialize this to a calendar appropriate for the locale associated with
  117. * this <code>DateFormat</code>.
  118. * @serial
  119. */
  120. protected Calendar calendar;
  121. /**
  122. * The number formatter that <code>DateFormat</code> uses to format numbers
  123. * in dates and times. Subclasses should initialize this to a number format
  124. * appropriate for the locale associated with this <code>DateFormat</code>.
  125. * @serial
  126. */
  127. protected NumberFormat numberFormat;
  128. /**
  129. * Useful constant for ERA field alignment.
  130. * Used in FieldPosition of date/time formatting.
  131. */
  132. public final static int ERA_FIELD = 0;
  133. /**
  134. * Useful constant for YEAR field alignment.
  135. * Used in FieldPosition of date/time formatting.
  136. */
  137. public final static int YEAR_FIELD = 1;
  138. /**
  139. * Useful constant for MONTH field alignment.
  140. * Used in FieldPosition of date/time formatting.
  141. */
  142. public final static int MONTH_FIELD = 2;
  143. /**
  144. * Useful constant for DATE field alignment.
  145. * Used in FieldPosition of date/time formatting.
  146. */
  147. public final static int DATE_FIELD = 3;
  148. /**
  149. * Useful constant for one-based HOUR_OF_DAY field alignment.
  150. * Used in FieldPosition of date/time formatting.
  151. * HOUR_OF_DAY1_FIELD is used for the one-based 24-hour clock.
  152. * For example, 23:59 + 01:00 results in 24:59.
  153. */
  154. public final static int HOUR_OF_DAY1_FIELD = 4;
  155. /**
  156. * Useful constant for zero-based HOUR_OF_DAY field alignment.
  157. * Used in FieldPosition of date/time formatting.
  158. * HOUR_OF_DAY0_FIELD is used for the zero-based 24-hour clock.
  159. * For example, 23:59 + 01:00 results in 00:59.
  160. */
  161. public final static int HOUR_OF_DAY0_FIELD = 5;
  162. /**
  163. * Useful constant for MINUTE field alignment.
  164. * Used in FieldPosition of date/time formatting.
  165. */
  166. public final static int MINUTE_FIELD = 6;
  167. /**
  168. * Useful constant for SECOND field alignment.
  169. * Used in FieldPosition of date/time formatting.
  170. */
  171. public final static int SECOND_FIELD = 7;
  172. /**
  173. * Useful constant for MILLISECOND field alignment.
  174. * Used in FieldPosition of date/time formatting.
  175. */
  176. public final static int MILLISECOND_FIELD = 8;
  177. /**
  178. * Useful constant for DAY_OF_WEEK field alignment.
  179. * Used in FieldPosition of date/time formatting.
  180. */
  181. public final static int DAY_OF_WEEK_FIELD = 9;
  182. /**
  183. * Useful constant for DAY_OF_YEAR field alignment.
  184. * Used in FieldPosition of date/time formatting.
  185. */
  186. public final static int DAY_OF_YEAR_FIELD = 10;
  187. /**
  188. * Useful constant for DAY_OF_WEEK_IN_MONTH field alignment.
  189. * Used in FieldPosition of date/time formatting.
  190. */
  191. public final static int DAY_OF_WEEK_IN_MONTH_FIELD = 11;
  192. /**
  193. * Useful constant for WEEK_OF_YEAR field alignment.
  194. * Used in FieldPosition of date/time formatting.
  195. */
  196. public final static int WEEK_OF_YEAR_FIELD = 12;
  197. /**
  198. * Useful constant for WEEK_OF_MONTH field alignment.
  199. * Used in FieldPosition of date/time formatting.
  200. */
  201. public final static int WEEK_OF_MONTH_FIELD = 13;
  202. /**
  203. * Useful constant for AM_PM field alignment.
  204. * Used in FieldPosition of date/time formatting.
  205. */
  206. public final static int AM_PM_FIELD = 14;
  207. /**
  208. * Useful constant for one-based HOUR field alignment.
  209. * Used in FieldPosition of date/time formatting.
  210. * HOUR1_FIELD is used for the one-based 12-hour clock.
  211. * For example, 11:30 PM + 1 hour results in 12:30 AM.
  212. */
  213. public final static int HOUR1_FIELD = 15;
  214. /**
  215. * Useful constant for zero-based HOUR field alignment.
  216. * Used in FieldPosition of date/time formatting.
  217. * HOUR0_FIELD is used for the zero-based 12-hour clock.
  218. * For example, 11:30 PM + 1 hour results in 00:30 AM.
  219. */
  220. public final static int HOUR0_FIELD = 16;
  221. /**
  222. * Useful constant for TIMEZONE field alignment.
  223. * Used in FieldPosition of date/time formatting.
  224. */
  225. public final static int TIMEZONE_FIELD = 17;
  226. // Proclaim serial compatibility with 1.1 FCS
  227. private static final long serialVersionUID = 7218322306649953788L;
  228. /**
  229. * Overrides Format.
  230. * Formats a time object into a time string. Examples of time objects
  231. * are a time value expressed in milliseconds and a Date object.
  232. * @param obj must be a Number or a Date.
  233. * @param toAppendTo the string buffer for the returning time string.
  234. * @return the formatted time string.
  235. * @param fieldPosition keeps track of the position of the field
  236. * within the returned string.
  237. * On input: an alignment field,
  238. * if desired. On output: the offsets of the alignment field. For
  239. * example, given a time text "1996.07.10 AD at 15:08:56 PDT",
  240. * if the given fieldPosition is DateFormat.YEAR_FIELD, the
  241. * begin index and end index of fieldPosition will be set to
  242. * 0 and 4, respectively.
  243. * Notice that if the same time field appears
  244. * more than once in a pattern, the fieldPosition will be set for the first
  245. * occurence of that time field. For instance, formatting a Date to
  246. * the time string "1 PM PDT (Pacific Daylight Time)" using the pattern
  247. * "h a z (zzzz)" and the alignment field DateFormat.TIMEZONE_FIELD,
  248. * the begin index and end index of fieldPosition will be set to
  249. * 5 and 8, respectively, for the first occurence of the timezone
  250. * pattern character 'z'.
  251. * @see java.text.Format
  252. */
  253. public final StringBuffer format(Object obj, StringBuffer toAppendTo,
  254. FieldPosition fieldPosition)
  255. {
  256. if (obj instanceof Date)
  257. return format( (Date)obj, toAppendTo, fieldPosition );
  258. else if (obj instanceof Number)
  259. return format( new Date(((Number)obj).longValue()),
  260. toAppendTo, fieldPosition );
  261. else
  262. throw new IllegalArgumentException("Cannot format given Object as a Date");
  263. }
  264. /**
  265. * Formats a Date into a date/time string.
  266. * @param date a Date to be formatted into a date/time string.
  267. * @param toAppendTo the string buffer for the returning date/time string.
  268. * @param fieldPosition keeps track of the position of the field
  269. * within the returned string.
  270. * On input: an alignment field,
  271. * if desired. On output: the offsets of the alignment field. For
  272. * example, given a time text "1996.07.10 AD at 15:08:56 PDT",
  273. * if the given fieldPosition is DateFormat.YEAR_FIELD, the
  274. * begin index and end index of fieldPosition will be set to
  275. * 0 and 4, respectively.
  276. * Notice that if the same time field appears
  277. * more than once in a pattern, the fieldPosition will be set for the first
  278. * occurence of that time field. For instance, formatting a Date to
  279. * the time string "1 PM PDT (Pacific Daylight Time)" using the pattern
  280. * "h a z (zzzz)" and the alignment field DateFormat.TIMEZONE_FIELD,
  281. * the begin index and end index of fieldPosition will be set to
  282. * 5 and 8, respectively, for the first occurence of the timezone
  283. * pattern character 'z'.
  284. * @return the formatted date/time string.
  285. */
  286. public abstract StringBuffer format(Date date, StringBuffer toAppendTo,
  287. FieldPosition fieldPosition);
  288. /**
  289. * Formats a Date into a date/time string.
  290. * @param date the time value to be formatted into a time string.
  291. * @return the formatted time string.
  292. */
  293. public final String format(Date date)
  294. {
  295. return format(date, new StringBuffer(),new FieldPosition(0)).toString();
  296. }
  297. /**
  298. * Parse a date/time string.
  299. *
  300. * @param text The date/time string to be parsed
  301. *
  302. * @return A Date, or null if the input could not be parsed
  303. *
  304. * @exception ParseException If the given string cannot be parsed as a date.
  305. *
  306. * @see #parse(String, ParsePosition)
  307. */
  308. public Date parse(String text) throws ParseException
  309. {
  310. ParsePosition pos = new ParsePosition(0);
  311. Date result = parse(text, pos);
  312. if (pos.index == 0)
  313. throw new ParseException("Unparseable date: \"" + text + "\"" ,
  314. pos.errorIndex);
  315. return result;
  316. }
  317. /**
  318. * Parse a date/time string according to the given parse position. For
  319. * example, a time text "07/10/96 4:5 PM, PDT" will be parsed into a Date
  320. * that is equivalent to Date(837039928046).
  321. *
  322. * <p> By default, parsing is lenient: If the input is not in the form used
  323. * by this object's format method but can still be parsed as a date, then
  324. * the parse succeeds. Clients may insist on strict adherence to the
  325. * format by calling setLenient(false).
  326. *
  327. * @see java.text.DateFormat#setLenient(boolean)
  328. *
  329. * @param text The date/time string to be parsed
  330. *
  331. * @param pos On input, the position at which to start parsing; on
  332. * output, the position at which parsing terminated, or the
  333. * start position if the parse failed.
  334. *
  335. * @return A Date, or null if the input could not be parsed
  336. */
  337. public abstract Date parse(String text, ParsePosition pos);
  338. /**
  339. * Parse a date/time string into an Object. This convenience method simply
  340. * calls parse(String, ParsePosition).
  341. *
  342. * @see #parse(String, ParsePosition)
  343. */
  344. public Object parseObject (String source, ParsePosition pos)
  345. {
  346. return parse(source, pos);
  347. }
  348. /**
  349. * Constant for full style pattern.
  350. */
  351. public static final int FULL = 0;
  352. /**
  353. * Constant for long style pattern.
  354. */
  355. public static final int LONG = 1;
  356. /**
  357. * Constant for medium style pattern.
  358. */
  359. public static final int MEDIUM = 2;
  360. /**
  361. * Constant for short style pattern.
  362. */
  363. public static final int SHORT = 3;
  364. /**
  365. * Constant for default style pattern. Its value is MEDIUM.
  366. */
  367. public static final int DEFAULT = MEDIUM;
  368. /**
  369. * Gets the time formatter with the default formatting style
  370. * for the default locale.
  371. * @return a time formatter.
  372. */
  373. public final static DateFormat getTimeInstance()
  374. {
  375. return get(DEFAULT, 0, 1, Locale.getDefault());
  376. }
  377. /**
  378. * Gets the time formatter with the given formatting style
  379. * for the default locale.
  380. * @param style the given formatting style. For example,
  381. * SHORT for "h:mm a" in the US locale.
  382. * @return a time formatter.
  383. */
  384. public final static DateFormat getTimeInstance(int style)
  385. {
  386. return get(style, 0, 1, Locale.getDefault());
  387. }
  388. /**
  389. * Gets the time formatter with the given formatting style
  390. * for the given locale.
  391. * @param style the given formatting style. For example,
  392. * SHORT for "h:mm a" in the US locale.
  393. * @param aLocale the given locale.
  394. * @return a time formatter.
  395. */
  396. public final static DateFormat getTimeInstance(int style,
  397. Locale aLocale)
  398. {
  399. return get(style, 0, 1, aLocale);
  400. }
  401. /**
  402. * Gets the date formatter with the default formatting style
  403. * for the default locale.
  404. * @return a date formatter.
  405. */
  406. public final static DateFormat getDateInstance()
  407. {
  408. return get(0, DEFAULT, 2, Locale.getDefault());
  409. }
  410. /**
  411. * Gets the date formatter with the given formatting style
  412. * for the default locale.
  413. * @param style the given formatting style. For example,
  414. * SHORT for "M/d/yy" in the US locale.
  415. * @return a date formatter.
  416. */
  417. public final static DateFormat getDateInstance(int style)
  418. {
  419. return get(0, style, 2, Locale.getDefault());
  420. }
  421. /**
  422. * Gets the date formatter with the given formatting style
  423. * for the given locale.
  424. * @param style the given formatting style. For example,
  425. * SHORT for "M/d/yy" in the US locale.
  426. * @param aLocale the given locale.
  427. * @return a date formatter.
  428. */
  429. public final static DateFormat getDateInstance(int style,
  430. Locale aLocale)
  431. {
  432. return get(0, style, 2, aLocale);
  433. }
  434. /**
  435. * Gets the date/time formatter with the default formatting style
  436. * for the default locale.
  437. * @return a date/time formatter.
  438. */
  439. public final static DateFormat getDateTimeInstance()
  440. {
  441. return get(DEFAULT, DEFAULT, 3, Locale.getDefault());
  442. }
  443. /**
  444. * Gets the date/time formatter with the given date and time
  445. * formatting styles for the default locale.
  446. * @param dateStyle the given date formatting style. For example,
  447. * SHORT for "M/d/yy" in the US locale.
  448. * @param timeStyle the given time formatting style. For example,
  449. * SHORT for "h:mm a" in the US locale.
  450. * @return a date/time formatter.
  451. */
  452. public final static DateFormat getDateTimeInstance(int dateStyle,
  453. int timeStyle)
  454. {
  455. return get(timeStyle, dateStyle, 3, Locale.getDefault());
  456. }
  457. /**
  458. * Gets the date/time formatter with the given formatting styles
  459. * for the given locale.
  460. * @param dateStyle the given date formatting style.
  461. * @param timeStyle the given time formatting style.
  462. * @param aLocale the given locale.
  463. * @return a date/time formatter.
  464. */
  465. public final static DateFormat
  466. getDateTimeInstance(int dateStyle, int timeStyle, Locale aLocale)
  467. {
  468. return get(timeStyle, dateStyle, 3, aLocale);
  469. }
  470. /**
  471. * Get a default date/time formatter that uses the SHORT style for both the
  472. * date and the time.
  473. */
  474. public final static DateFormat getInstance() {
  475. return getDateTimeInstance(SHORT, SHORT);
  476. }
  477. /**
  478. * Gets the set of locales for which DateFormats are installed.
  479. * @return the set of locales for which DateFormats are installed.
  480. */
  481. public static Locale[] getAvailableLocales()
  482. {
  483. return LocaleData.getAvailableLocales("DateTimePatterns");
  484. }
  485. /**
  486. * Set the calendar to be used by this date format. Initially, the default
  487. * calendar for the specified or default locale is used.
  488. * @param newCalendar the new Calendar to be used by the date format
  489. */
  490. public void setCalendar(Calendar newCalendar)
  491. {
  492. this.calendar = newCalendar;
  493. }
  494. /**
  495. * Gets the calendar associated with this date/time formatter.
  496. * @return the calendar associated with this date/time formatter.
  497. */
  498. public Calendar getCalendar()
  499. {
  500. return calendar;
  501. }
  502. /**
  503. * Allows you to set the number formatter.
  504. * @param newNumberFormat the given new NumberFormat.
  505. */
  506. public void setNumberFormat(NumberFormat newNumberFormat)
  507. {
  508. this.numberFormat = newNumberFormat;
  509. }
  510. /**
  511. * Gets the number formatter which this date/time formatter uses to
  512. * format and parse a time.
  513. * @return the number formatter which this date/time formatter uses.
  514. */
  515. public NumberFormat getNumberFormat()
  516. {
  517. return numberFormat;
  518. }
  519. /**
  520. * Sets the time zone for the calendar of this DateFormat object.
  521. * @param zone the given new time zone.
  522. */
  523. public void setTimeZone(TimeZone zone)
  524. {
  525. calendar.setTimeZone(zone);
  526. }
  527. /**
  528. * Gets the time zone.
  529. * @return the time zone associated with the calendar of DateFormat.
  530. */
  531. public TimeZone getTimeZone()
  532. {
  533. return calendar.getTimeZone();
  534. }
  535. /**
  536. * Specify whether or not date/time parsing is to be lenient. With
  537. * lenient parsing, the parser may use heuristics to interpret inputs that
  538. * do not precisely match this object's format. With strict parsing,
  539. * inputs must match this object's format.
  540. * @param lenient when true, parsing is lenient
  541. * @see java.util.Calendar#setLenient
  542. */
  543. public void setLenient(boolean lenient)
  544. {
  545. calendar.setLenient(lenient);
  546. }
  547. /**
  548. * Tell whether date/time parsing is to be lenient.
  549. */
  550. public boolean isLenient()
  551. {
  552. return calendar.isLenient();
  553. }
  554. /**
  555. * Overrides hashCode
  556. */
  557. public int hashCode() {
  558. return numberFormat.hashCode();
  559. // just enough fields for a reasonable distribution
  560. }
  561. /**
  562. * Overrides equals
  563. */
  564. public boolean equals(Object obj) {
  565. if (this == obj) return true;
  566. if (obj == null || getClass() != obj.getClass()) return false;
  567. DateFormat other = (DateFormat) obj;
  568. return (// calendar.equivalentTo(other.calendar) // THIS API DOESN'T EXIST YET!
  569. calendar.getFirstDayOfWeek() == other.calendar.getFirstDayOfWeek() &&
  570. calendar.getMinimalDaysInFirstWeek() == other.calendar.getMinimalDaysInFirstWeek() &&
  571. calendar.isLenient() == other.calendar.isLenient() &&
  572. calendar.getTimeZone().equals(other.calendar.getTimeZone()) &&
  573. numberFormat.equals(other.numberFormat));
  574. }
  575. /**
  576. * Overrides Cloneable
  577. */
  578. public Object clone()
  579. {
  580. DateFormat other = (DateFormat) super.clone();
  581. other.calendar = (Calendar) calendar.clone();
  582. other.numberFormat = (NumberFormat) numberFormat.clone();
  583. return other;
  584. }
  585. /**
  586. * Creates a DateFormat with the given time and/or date style in the given
  587. * locale.
  588. * @param timeStyle a value from 0 to 3 indicating the time format,
  589. * ignored if flags is 2
  590. * @param dateStyle a value from 0 to 3 indicating the time format,
  591. * ignored if flags is 1
  592. * @param flags either 1 for a time format, 2 for a date format,
  593. * or 3 for a date/time format
  594. * @param loc the locale for the format
  595. */
  596. private static DateFormat get(int timeStyle, int dateStyle,
  597. int flags, Locale loc) {
  598. if ((flags & 1) != 0) {
  599. if (timeStyle < 0 || timeStyle > 3) {
  600. throw new IllegalArgumentException("Illegal time style " + timeStyle);
  601. }
  602. } else {
  603. timeStyle = -1;
  604. }
  605. if ((flags & 2) != 0) {
  606. if (dateStyle < 0 || dateStyle > 3) {
  607. throw new IllegalArgumentException("Illegal date style " + dateStyle);
  608. }
  609. } else {
  610. dateStyle = -1;
  611. }
  612. try {
  613. return new SimpleDateFormat(timeStyle, dateStyle, loc);
  614. } catch (MissingResourceException e) {
  615. return new SimpleDateFormat("M/d/yy h:mm a");
  616. }
  617. }
  618. /**
  619. * Create a new date format.
  620. */
  621. protected DateFormat() {}
  622. }