1. /*
  2. * @(#)DateFormat.java 1.33 01/11/29
  3. *
  4. * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. /*
  8. * @(#)DateFormat.java 1.33 01/11/29
  9. *
  10. * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
  11. * (C) Copyright IBM Corp. 1996 - All Rights Reserved
  12. *
  13. * Portions copyright (c) 1996-1998 Sun Microsystems, Inc. All Rights Reserved.
  14. *
  15. * The original version of this source code and documentation is copyrighted
  16. * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
  17. * materials are provided under terms of a License Agreement between Taligent
  18. * and Sun. This technology is protected by multiple US and International
  19. * patents. This notice and attribution to Taligent may not be removed.
  20. * Taligent is a registered trademark of Taligent, Inc.
  21. *
  22. * Permission to use, copy, modify, and distribute this software
  23. * and its documentation for NON-COMMERCIAL purposes and without
  24. * fee is hereby granted provided that this copyright notice
  25. * appears in all copies. Please refer to the file "copyright.html"
  26. * for further important copyright and licensing information.
  27. *
  28. * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
  29. * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
  30. * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  31. * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
  32. * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
  33. * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
  34. *
  35. */
  36. package java.text;
  37. import java.util.Locale;
  38. import java.util.ResourceBundle;
  39. import java.util.MissingResourceException;
  40. import java.util.TimeZone;
  41. import java.util.Calendar;
  42. import java.util.GregorianCalendar;
  43. import java.util.Date;
  44. import java.text.resources.*;
  45. /**
  46. * DateFormat is an abstract class for date/time formatting subclasses which
  47. * formats and parses dates or time in a language-independent manner.
  48. * The date/time formatting subclass, such as SimpleDateFormat, allows for
  49. * formatting (i.e., date -> text), parsing (text -> date), and
  50. * normalization. The date is represented as a <code>Date</code> object or
  51. * as the milliseconds since January 1, 1970, 00:00:00 GMT.
  52. *
  53. * <p>DateFormat provides many class methods for obtaining default date/time
  54. * formatters based on the default or a given loacle and a number of formatting
  55. * styles. The formatting styles include FULL, LONG, MEDIUM, and SHORT. More
  56. * detail and examples of using these styles are provided in the method
  57. * descriptions.
  58. *
  59. * <p>DateFormat helps you to format and parse dates for any locale.
  60. * Your code can be completely independent of the locale conventions for
  61. * months, days of the week, or even the calendar format: lunar vs. solar.
  62. *
  63. * <p>To format a date for the current Locale, use one of the
  64. * static factory methods:
  65. * <pre>
  66. * myString = DateFormat.getDateInstance().format(myDate);
  67. * </pre>
  68. * <p>If you are formatting multiple numbers, it is
  69. * more efficient to get the format and use it multiple times so that
  70. * the system doesn't have to fetch the information about the local
  71. * language and country conventions multiple times.
  72. * <pre>
  73. * DateFormat df = DateFormat.getDateInstance();
  74. * for (int i = 0; i < a.length; ++i) {
  75. * output.println(df.format(myDate[i]) + "; ");
  76. * }
  77. * </pre>
  78. * <p>To format a number for a different Locale, specify it in the
  79. * call to getDateInstance().
  80. * <pre>
  81. * DateFormat df = DateFormat.getDateInstance(Locale.FRANCE);
  82. * </pre>
  83. * <p>You can use a DateFormat to parse also.
  84. * <pre>
  85. * myDate = df.parse(myString);
  86. * </pre>
  87. * <p>Use getDate to get the normal date format for that country.
  88. * There are other static factory methods available.
  89. * Use getTime to get the time format for that country.
  90. * Use getDateTime to get a date and time format. You can pass in different
  91. * options to these factory methods to control the length of the
  92. * result; from SHORT to MEDIUM to LONG to FULL. The exact result depends
  93. * on the locale, but generally:
  94. * <ul><li>SHORT is completely numeric, such as 12.13.52 or 3:30pm
  95. * <li>MEDIUM is longer, such as Jan 12, 1952
  96. * <li>LONG is longer, such as January 12, 1952 or 3:30:32pm
  97. * <li>FULL is pretty completely specified, such as
  98. * Tuesday, April 12, 1952 AD or 3:30:42pm PST.
  99. * </ul>
  100. *
  101. * <p>You can also set the time zone on the format if you wish.
  102. * If you want even more control over the format or parsing,
  103. * (or want to give your users more control),
  104. * you can try casting the DateFormat you get from the factory methods
  105. * to a SimpleDateFormat. This will work for the majority
  106. * of countries; just remember to put it in a try block in case you
  107. * encounter an unusual one.
  108. *
  109. * <p>You can also use forms of the parse and format methods with
  110. * ParsePosition and FieldPosition to
  111. * allow you to
  112. * <ul><li>progressively parse through pieces of a string.
  113. * <li>align any particular field, or find out where it is for selection
  114. * on the screen.
  115. * </ul>
  116. *
  117. * @see Format
  118. * @see NumberFormat
  119. * @see SimpleDateFormat
  120. * @see java.util.Calendar
  121. * @see java.util.GregorianCalendar
  122. * @see java.util.TimeZone
  123. * @version 1.33 11/29/01
  124. * @author Mark Davis, Chen-Lieh Huang, Alan Liu
  125. */
  126. public abstract class DateFormat extends Format {
  127. /**
  128. * The calendar that <code>DateFormat</code> uses to produce the time field
  129. * values needed to implement date and time formatting. Subclasses should
  130. * initialize this to a calendar appropriate for the locale associated with
  131. * this <code>DateFormat</code>.
  132. * @serial
  133. */
  134. protected Calendar calendar;
  135. /**
  136. * The number formatter that <code>DateFormat</code> uses to format numbers
  137. * in dates and times. Subclasses should initialize this to a number format
  138. * appropriate for the locale associated with this <code>DateFormat</code>.
  139. * @serial
  140. */
  141. protected NumberFormat numberFormat;
  142. /**
  143. * Useful constant for ERA field alignment.
  144. * Used in FieldPosition of date/time formatting.
  145. */
  146. public final static int ERA_FIELD = 0;
  147. /**
  148. * Useful constant for YEAR field alignment.
  149. * Used in FieldPosition of date/time formatting.
  150. */
  151. public final static int YEAR_FIELD = 1;
  152. /**
  153. * Useful constant for MONTH field alignment.
  154. * Used in FieldPosition of date/time formatting.
  155. */
  156. public final static int MONTH_FIELD = 2;
  157. /**
  158. * Useful constant for DATE field alignment.
  159. * Used in FieldPosition of date/time formatting.
  160. */
  161. public final static int DATE_FIELD = 3;
  162. /**
  163. * Useful constant for one-based HOUR_OF_DAY field alignment.
  164. * Used in FieldPosition of date/time formatting.
  165. * HOUR_OF_DAY1_FIELD is used for the one-based 24-hour clock.
  166. * For example, 23:59 + 01:00 results in 24:59.
  167. */
  168. public final static int HOUR_OF_DAY1_FIELD = 4;
  169. /**
  170. * Useful constant for zero-based HOUR_OF_DAY field alignment.
  171. * Used in FieldPosition of date/time formatting.
  172. * HOUR_OF_DAY0_FIELD is used for the zero-based 24-hour clock.
  173. * For example, 23:59 + 01:00 results in 00:59.
  174. */
  175. public final static int HOUR_OF_DAY0_FIELD = 5;
  176. /**
  177. * Useful constant for MINUTE field alignment.
  178. * Used in FieldPosition of date/time formatting.
  179. */
  180. public final static int MINUTE_FIELD = 6;
  181. /**
  182. * Useful constant for SECOND field alignment.
  183. * Used in FieldPosition of date/time formatting.
  184. */
  185. public final static int SECOND_FIELD = 7;
  186. /**
  187. * Useful constant for MILLISECOND field alignment.
  188. * Used in FieldPosition of date/time formatting.
  189. */
  190. public final static int MILLISECOND_FIELD = 8;
  191. /**
  192. * Useful constant for DAY_OF_WEEK field alignment.
  193. * Used in FieldPosition of date/time formatting.
  194. */
  195. public final static int DAY_OF_WEEK_FIELD = 9;
  196. /**
  197. * Useful constant for DAY_OF_YEAR field alignment.
  198. * Used in FieldPosition of date/time formatting.
  199. */
  200. public final static int DAY_OF_YEAR_FIELD = 10;
  201. /**
  202. * Useful constant for DAY_OF_WEEK_IN_MONTH field alignment.
  203. * Used in FieldPosition of date/time formatting.
  204. */
  205. public final static int DAY_OF_WEEK_IN_MONTH_FIELD = 11;
  206. /**
  207. * Useful constant for WEEK_OF_YEAR field alignment.
  208. * Used in FieldPosition of date/time formatting.
  209. */
  210. public final static int WEEK_OF_YEAR_FIELD = 12;
  211. /**
  212. * Useful constant for WEEK_OF_MONTH field alignment.
  213. * Used in FieldPosition of date/time formatting.
  214. */
  215. public final static int WEEK_OF_MONTH_FIELD = 13;
  216. /**
  217. * Useful constant for AM_PM field alignment.
  218. * Used in FieldPosition of date/time formatting.
  219. */
  220. public final static int AM_PM_FIELD = 14;
  221. /**
  222. * Useful constant for one-based HOUR field alignment.
  223. * Used in FieldPosition of date/time formatting.
  224. * HOUR1_FIELD is used for the one-based 12-hour clock.
  225. * For example, 11:30 PM + 1 hour results in 12:30 AM.
  226. */
  227. public final static int HOUR1_FIELD = 15;
  228. /**
  229. * Useful constant for zero-based HOUR field alignment.
  230. * Used in FieldPosition of date/time formatting.
  231. * HOUR0_FIELD is used for the zero-based 12-hour clock.
  232. * For example, 11:30 PM + 1 hour results in 00:30 AM.
  233. */
  234. public final static int HOUR0_FIELD = 16;
  235. /**
  236. * Useful constant for TIMEZONE field alignment.
  237. * Used in FieldPosition of date/time formatting.
  238. */
  239. public final static int TIMEZONE_FIELD = 17;
  240. // Proclaim serial compatibility with 1.1 FCS
  241. private static final long serialVersionUID = 7218322306649953788L;
  242. /**
  243. * Overrides Format.
  244. * Formats a time object into a time string. Examples of time objects
  245. * are a time value expressed in milliseconds and a Date object.
  246. * @param obj must be a Number or a Date.
  247. * @param toAppendTo the string buffer for the returning time string.
  248. * @return the formatted time string.
  249. * @param fieldPosition keeps track of the position of the field
  250. * within the returned string.
  251. * On input: an alignment field,
  252. * if desired. On output: the offsets of the alignment field. For
  253. * example, given a time text "1996.07.10 AD at 15:08:56 PDT",
  254. * if the given fieldPosition is DateFormat.YEAR_FIELD, the
  255. * begin index and end index of fieldPosition will be set to
  256. * 0 and 4, respectively.
  257. * Notice that if the same time field appears
  258. * more than once in a pattern, the fieldPosition will be set for the first
  259. * occurence of that time field. For instance, formatting a Date to
  260. * the time string "1 PM PDT (Pacific Daylight Time)" using the pattern
  261. * "h a z (zzzz)" and the alignment field DateFormat.TIMEZONE_FIELD,
  262. * the begin index and end index of fieldPosition will be set to
  263. * 5 and 8, respectively, for the first occurence of the timezone
  264. * pattern character 'z'.
  265. * @see java.text.Format
  266. */
  267. public final StringBuffer format(Object obj, StringBuffer toAppendTo,
  268. FieldPosition fieldPosition)
  269. {
  270. if (obj instanceof Date)
  271. return format( (Date)obj, toAppendTo, fieldPosition );
  272. else if (obj instanceof Number)
  273. return format( new Date(((Number)obj).longValue()),
  274. toAppendTo, fieldPosition );
  275. else
  276. throw new IllegalArgumentException("Cannot format given Object as a Date");
  277. }
  278. /**
  279. * Formats a Date into a date/time string.
  280. * @param date a Date to be formatted into a date/time string.
  281. * @param toAppendTo the string buffer for the returning date/time string.
  282. * @param fieldPosition keeps track of the position of the field
  283. * within the returned string.
  284. * On input: an alignment field,
  285. * if desired. On output: the offsets of the alignment field. For
  286. * example, given a time text "1996.07.10 AD at 15:08:56 PDT",
  287. * if the given fieldPosition is DateFormat.YEAR_FIELD, the
  288. * begin index and end index of fieldPosition will be set to
  289. * 0 and 4, respectively.
  290. * Notice that if the same time field appears
  291. * more than once in a pattern, the fieldPosition will be set for the first
  292. * occurence of that time field. For instance, formatting a Date to
  293. * the time string "1 PM PDT (Pacific Daylight Time)" using the pattern
  294. * "h a z (zzzz)" and the alignment field DateFormat.TIMEZONE_FIELD,
  295. * the begin index and end index of fieldPosition will be set to
  296. * 5 and 8, respectively, for the first occurence of the timezone
  297. * pattern character 'z'.
  298. * @return the formatted date/time string.
  299. */
  300. public abstract StringBuffer format(Date date, StringBuffer toAppendTo,
  301. FieldPosition fieldPosition);
  302. /**
  303. * Formats a Date into a date/time string.
  304. * @param date the time value to be formatted into a time string.
  305. * @return the formatted time string.
  306. */
  307. public final String format(Date date)
  308. {
  309. return format(date, new StringBuffer(),new FieldPosition(0)).toString();
  310. }
  311. /**
  312. * Parse a date/time string.
  313. *
  314. * @param text The date/time string to be parsed
  315. *
  316. * @return A Date, or null if the input could not be parsed
  317. *
  318. * @exception ParseException If the given string cannot be parsed as a date.
  319. *
  320. * @see #parse(String, ParsePosition)
  321. */
  322. public Date parse(String text) throws ParseException
  323. {
  324. ParsePosition pos = new ParsePosition(0);
  325. Date result = parse(text, pos);
  326. if (pos.index == 0)
  327. throw new ParseException("Unparseable date: \"" + text + "\"" ,
  328. pos.errorIndex);
  329. return result;
  330. }
  331. /**
  332. * Parse a date/time string according to the given parse position. For
  333. * example, a time text "07/10/96 4:5 PM, PDT" will be parsed into a Date
  334. * that is equivalent to Date(837039928046).
  335. *
  336. * <p> By default, parsing is lenient: If the input is not in the form used
  337. * by this object's format method but can still be parsed as a date, then
  338. * the parse succeeds. Clients may insist on strict adherence to the
  339. * format by calling setLenient(false).
  340. *
  341. * @see java.text.DateFormat#setLenient(boolean)
  342. *
  343. * @param text The date/time string to be parsed
  344. *
  345. * @param pos On input, the position at which to start parsing; on
  346. * output, the position at which parsing terminated, or the
  347. * start position if the parse failed.
  348. *
  349. * @return A Date, or null if the input could not be parsed
  350. */
  351. public abstract Date parse(String text, ParsePosition pos);
  352. /**
  353. * Parse a date/time string into an Object. This convenience method simply
  354. * calls parse(String, ParsePosition).
  355. *
  356. * @see #parse(String, ParsePosition)
  357. */
  358. public Object parseObject (String source, ParsePosition pos)
  359. {
  360. return parse(source, pos);
  361. }
  362. /**
  363. * Constant for full style pattern.
  364. */
  365. public static final int FULL = 0;
  366. /**
  367. * Constant for long style pattern.
  368. */
  369. public static final int LONG = 1;
  370. /**
  371. * Constant for medium style pattern.
  372. */
  373. public static final int MEDIUM = 2;
  374. /**
  375. * Constant for short style pattern.
  376. */
  377. public static final int SHORT = 3;
  378. /**
  379. * Constant for default style pattern.
  380. */
  381. public static final int DEFAULT = MEDIUM;
  382. /**
  383. * Gets the time formatter with the default formatting style
  384. * for the default locale.
  385. * @return a time formatter.
  386. */
  387. public final static DateFormat getTimeInstance()
  388. {
  389. return get(DEFAULT, -1, Locale.getDefault());
  390. }
  391. /**
  392. * Gets the time formatter with the given formatting style
  393. * for the default locale.
  394. * @param style the given formatting style. For example,
  395. * SHORT for "h:mm a" in the US locale.
  396. * @return a time formatter.
  397. */
  398. public final static DateFormat getTimeInstance(int style)
  399. {
  400. return get(style, -1, Locale.getDefault());
  401. }
  402. /**
  403. * Gets the time formatter with the given formatting style
  404. * for the given locale.
  405. * @param style the given formatting style. For example,
  406. * SHORT for "h:mm a" in the US locale.
  407. * @param aLocale the given locale.
  408. * @return a time formatter.
  409. */
  410. public final static DateFormat getTimeInstance(int style,
  411. Locale aLocale)
  412. {
  413. return get(style, -1, aLocale);
  414. }
  415. /**
  416. * Gets the date formatter with the default formatting style
  417. * for the default locale.
  418. * @return a date formatter.
  419. */
  420. public final static DateFormat getDateInstance()
  421. {
  422. // +4 to set the correct index for getting data out of
  423. // LocaleElements.
  424. return get(-1, DEFAULT + 4, Locale.getDefault());
  425. }
  426. /**
  427. * Gets the date formatter with the given formatting style
  428. * for the default locale.
  429. * @param style the given formatting style. For example,
  430. * SHORT for "M/d/yy" in the US locale.
  431. * @return a date formatter.
  432. */
  433. public final static DateFormat getDateInstance(int style)
  434. {
  435. return get(-1, style + 4, Locale.getDefault());
  436. }
  437. /**
  438. * Gets the date formatter with the given formatting style
  439. * for the given locale.
  440. * @param style the given formatting style. For example,
  441. * SHORT for "M/d/yy" in the US locale.
  442. * @param aLocale the given locale.
  443. * @return a date formatter.
  444. */
  445. public final static DateFormat getDateInstance(int style,
  446. Locale aLocale)
  447. {
  448. return get(-1, style + 4, aLocale);
  449. }
  450. /**
  451. * Gets the date/time formatter with the default formatting style
  452. * for the default locale.
  453. * @return a date/time formatter.
  454. */
  455. public final static DateFormat getDateTimeInstance()
  456. {
  457. return get(DEFAULT, DEFAULT + 4, Locale.getDefault());
  458. }
  459. /**
  460. * Gets the date/time formatter with the given date and time
  461. * formatting styles for the default locale.
  462. * @param dateStyle the given date formatting style. For example,
  463. * SHORT for "M/d/yy" in the US locale.
  464. * @param timeStyle the given time formatting style. For example,
  465. * SHORT for "h:mm a" in the US locale.
  466. * @return a date/time formatter.
  467. */
  468. public final static DateFormat getDateTimeInstance(int dateStyle,
  469. int timeStyle)
  470. {
  471. return get(timeStyle, dateStyle + 4, Locale.getDefault());
  472. }
  473. /**
  474. * Gets the date/time formatter with the given formatting styles
  475. * for the given locale.
  476. * @param dateStyle the given date formatting style.
  477. * @param timeStyle the given time formatting style.
  478. * @param aLocale the given locale.
  479. * @return a date/time formatter.
  480. */
  481. public final static DateFormat
  482. getDateTimeInstance(int dateStyle, int timeStyle, Locale aLocale)
  483. {
  484. return get(timeStyle, dateStyle + 4, aLocale);
  485. }
  486. /**
  487. * Get a default date/time formatter that uses the SHORT style for both the
  488. * date and the time.
  489. */
  490. public final static DateFormat getInstance() {
  491. return getDateTimeInstance(SHORT, SHORT);
  492. }
  493. /**
  494. * Gets the set of locales for which DateFormats are installed.
  495. * @return the set of locales for which DateFormats are installed.
  496. */
  497. public static Locale[] getAvailableLocales()
  498. {
  499. return LocaleData.getAvailableLocales("DateTimePatterns");
  500. }
  501. /**
  502. * Set the calendar to be used by this date format. Initially, the default
  503. * calendar for the specified or default locale is used.
  504. * @param newCalendar the new Calendar to be used by the date format
  505. */
  506. public void setCalendar(Calendar newCalendar)
  507. {
  508. this.calendar = newCalendar;
  509. }
  510. /**
  511. * Gets the calendar associated with this date/time formatter.
  512. * @return the calendar associated with this date/time formatter.
  513. */
  514. public Calendar getCalendar()
  515. {
  516. return calendar;
  517. }
  518. /**
  519. * Allows you to set the number formatter.
  520. * @param newNumberFormat the given new NumberFormat.
  521. */
  522. public void setNumberFormat(NumberFormat newNumberFormat)
  523. {
  524. this.numberFormat = newNumberFormat;
  525. }
  526. /**
  527. * Gets the number formatter which this date/time formatter uses to
  528. * format and parse a time.
  529. * @return the number formatter which this date/time formatter uses.
  530. */
  531. public NumberFormat getNumberFormat()
  532. {
  533. return numberFormat;
  534. }
  535. /**
  536. * Sets the time zone for the calendar of this DateFormat object.
  537. * @param zone the given new time zone.
  538. */
  539. public void setTimeZone(TimeZone zone)
  540. {
  541. calendar.setTimeZone(zone);
  542. }
  543. /**
  544. * Gets the time zone.
  545. * @return the time zone associated with the calendar of DateFormat.
  546. */
  547. public TimeZone getTimeZone()
  548. {
  549. return calendar.getTimeZone();
  550. }
  551. /**
  552. * Specify whether or not date/time parsing is to be lenient. With
  553. * lenient parsing, the parser may use heuristics to interpret inputs that
  554. * do not precisely match this object's format. With strict parsing,
  555. * inputs must match this object's format.
  556. * @param lenient when true, parsing is lenient
  557. * @see java.util.Calendar#setLenient
  558. */
  559. public void setLenient(boolean lenient)
  560. {
  561. calendar.setLenient(lenient);
  562. }
  563. /**
  564. * Tell whether date/time parsing is to be lenient.
  565. */
  566. public boolean isLenient()
  567. {
  568. return calendar.isLenient();
  569. }
  570. /**
  571. * Overrides hashCode
  572. */
  573. public int hashCode() {
  574. return numberFormat.hashCode();
  575. // just enough fields for a reasonable distribution
  576. }
  577. /**
  578. * Overrides equals
  579. */
  580. public boolean equals(Object obj) {
  581. if (this == obj) return true;
  582. if (obj == null || getClass() != obj.getClass()) return false;
  583. DateFormat other = (DateFormat) obj;
  584. return (// calendar.equivalentTo(other.calendar) // THIS API DOESN'T EXIST YET!
  585. calendar.getFirstDayOfWeek() == other.calendar.getFirstDayOfWeek() &&
  586. calendar.getMinimalDaysInFirstWeek() == other.calendar.getMinimalDaysInFirstWeek() &&
  587. calendar.isLenient() == other.calendar.isLenient() &&
  588. calendar.getTimeZone().equals(other.calendar.getTimeZone()) &&
  589. numberFormat.equals(other.numberFormat));
  590. }
  591. /**
  592. * Overrides Cloneable
  593. */
  594. public Object clone()
  595. {
  596. DateFormat other = (DateFormat) super.clone();
  597. other.calendar = (Calendar) calendar.clone();
  598. other.numberFormat = (NumberFormat) numberFormat.clone();
  599. return other;
  600. }
  601. private static DateFormat get(int timeStyle, /* -1 for no time */
  602. int dateStyle, /* -1 for no date */
  603. Locale loc) {
  604. try {
  605. return new SimpleDateFormat(timeStyle, dateStyle, loc);
  606. } catch (MissingResourceException e) {
  607. return new SimpleDateFormat("M/d/yy h:mm a");
  608. }
  609. }
  610. /**
  611. * Create a new date format.
  612. */
  613. protected DateFormat() {}
  614. }