1 /*********************************************************************
\r
2 * Copyright (C) 2000-2010, International Business Machines Corporation and
\r
3 * others. All Rights Reserved.
\r
4 *********************************************************************
\r
6 package com.ibm.icu.text;
\r
8 import java.io.InvalidObjectException;
\r
9 import java.text.FieldPosition;
\r
10 import java.text.ParsePosition;
\r
11 import java.util.Locale;
\r
13 import com.ibm.icu.impl.Utility;
\r
14 import com.ibm.icu.util.Calendar;
\r
15 import com.ibm.icu.util.ChineseCalendar;
\r
16 import com.ibm.icu.util.TimeZone;
\r
17 import com.ibm.icu.util.ULocale;
\r
20 * A concrete {@link DateFormat} for {@link com.ibm.icu.util.ChineseCalendar}.
\r
21 * This class handles a <code>ChineseCalendar</code>-specific field,
\r
22 * <code>ChineseCalendar.IS_LEAP_MONTH</code>. It also redefines the
\r
23 * handling of two fields, <code>ERA</code> and <code>YEAR</code>. The
\r
24 * former is displayed numerically, instead of symbolically, since it is
\r
25 * the numeric cycle number in <code>ChineseCalendar</code>. The latter is
\r
26 * numeric, as before, but has no special 2-digit Y2K behavior.
\r
28 * <p>With regard to <code>ChineseCalendar.IS_LEAP_MONTH</code>, this
\r
29 * class handles parsing specially. If no string symbol is found at all,
\r
30 * this is taken as equivalent to an <code>IS_LEAP_MONTH</code> value of
\r
31 * zero. This allows formats to display a special string (e.g., "*") for
\r
32 * leap months, but no string for normal months.
\r
34 * <p>Summary of field changes vs. {@link SimpleDateFormat}:<pre>
\r
35 * Symbol Meaning Presentation Example
\r
36 * ------ ------- ------------ -------
\r
37 * G cycle (Number) 78
\r
38 * y year of cycle (1..60) (Number) 17
\r
39 * l is leap month (Text) 4637
\r
42 * @see com.ibm.icu.util.ChineseCalendar
\r
43 * @see ChineseDateFormatSymbols
\r
47 public class ChineseDateFormat extends SimpleDateFormat {
\r
48 // Generated by serialver from JDK 1.4.1_01
\r
49 static final long serialVersionUID = -4610300753104099899L;
\r
51 // TODO Finish the constructors
\r
54 * Construct a ChineseDateFormat from a date format pattern and locale
\r
55 * @param pattern the pattern
\r
56 * @param locale the locale
\r
59 public ChineseDateFormat(String pattern, Locale locale) {
\r
60 this(pattern, ULocale.forLocale(locale));
\r
64 * Construct a ChineseDateFormat from a date format pattern and locale
\r
65 * @param pattern the pattern
\r
66 * @param locale the locale
\r
69 public ChineseDateFormat(String pattern, ULocale locale) {
\r
70 this(pattern, null, locale);
\r
74 * Construct a ChineseDateFormat from a date format pattern, numbering system override and locale
\r
75 * @param pattern the pattern
\r
76 * @param override The override string. A numbering system override string can take one of the following forms:
\r
77 * 1). If just a numbering system name is specified, it applies to all numeric fields in the date format pattern.
\r
78 * 2). To specify an alternate numbering system on a field by field basis, use the field letters from the pattern
\r
79 * followed by an = sign, followed by the numbering system name. For example, to specify that just the year
\r
80 * be formatted using Hebrew digits, use the override "y=hebr". Multiple overrides can be specified in a single
\r
81 * string by separating them with a semi-colon. For example, the override string "m=thai;y=deva" would format using
\r
82 * Thai digits for the month and Devanagari digits for the year.
\r
83 * @param locale the locale
\r
86 public ChineseDateFormat(String pattern, String override, ULocale locale) {
\r
87 super(pattern, new ChineseDateFormatSymbols(locale),
\r
88 new ChineseCalendar(TimeZone.getDefault(), locale), locale, true, override);
\r
91 // NOTE: This API still exists; we just inherit it from SimpleDateFormat
\r
94 // * @stable ICU 2.0
\r
96 // protected String subFormat(char ch, int count, int beginOffset,
\r
97 // FieldPosition pos, DateFormatSymbols formatData,
\r
100 // case 'G': // 'G' - ERA
\r
101 // return zeroPaddingNumber(cal.get(Calendar.ERA), 1, 9);
\r
102 // case 'l': // 'l' - IS_LEAP_MONTH
\r
104 // ChineseDateFormatSymbols symbols =
\r
105 // (ChineseDateFormatSymbols) formatData;
\r
106 // return symbols.getLeapMonth(cal.get(
\r
107 // ChineseCalendar.IS_LEAP_MONTH));
\r
110 // return super.subFormat(ch, count, beginOffset, pos, formatData, cal);
\r
117 * @deprecated This API is ICU internal only.
\r
119 protected void subFormat(StringBuffer buf,
\r
120 char ch, int count, int beginOffset,
\r
125 case 'G': // 'G' - ERA
\r
126 zeroPaddingNumber(numberFormat,buf, cal.get(Calendar.ERA), 1, 9);
\r
128 case 'l': // 'l' - IS_LEAP_MONTH
\r
129 buf.append(((ChineseDateFormatSymbols) getSymbols()).
\r
130 getLeapMonth(cal.get(ChineseCalendar.IS_LEAP_MONTH)));
\r
133 super.subFormat(buf, ch, count, beginOffset, pos, cal);
\r
137 // TODO: add code to set FieldPosition for 'G' and 'l' fields. This
\r
138 // is a DESIGN FLAW -- subclasses shouldn't have to duplicate the
\r
139 // code that handles this at the end of SimpleDateFormat.subFormat.
\r
140 // The logic should be moved up into SimpleDateFormat.format.
\r
148 protected int subParse(String text, int start, char ch, int count, boolean obeyCount, boolean allowNegative,
\r
149 boolean[] ambiguousYear, Calendar cal) {
\r
150 if (ch != 'G' && ch != 'l' && ch != 'y') {
\r
151 return super.subParse(text, start, ch, count, obeyCount, allowNegative, ambiguousYear, cal);
\r
155 start = Utility.skipWhitespace(text, start);
\r
157 ParsePosition pos = new ParsePosition(start);
\r
160 case 'G': // 'G' - ERA
\r
161 case 'y': // 'y' - YEAR, but without the 2-digit Y2K adjustment
\r
163 Number number = null;
\r
165 if ((start + count) > text.length()) {
\r
168 number = numberFormat.parse(text.substring(0, start + count), pos);
\r
170 number = numberFormat.parse(text, pos);
\r
172 if (number == null) {
\r
175 int value = number.intValue();
\r
176 cal.set(ch == 'G' ? Calendar.ERA : Calendar.YEAR, value);
\r
177 return pos.getIndex();
\r
179 case 'l': // 'l' - IS_LEAP_MONTH
\r
181 ChineseDateFormatSymbols symbols = (ChineseDateFormatSymbols) getSymbols();
\r
182 int result = matchString(text, start, ChineseCalendar.IS_LEAP_MONTH, symbols.isLeapMonth, cal);
\r
183 // Treat the absence of any matching string as setting
\r
184 // IS_LEAP_MONTH to false.
\r
186 cal.set(ChineseCalendar.IS_LEAP_MONTH, 0);
\r
193 return 0; // This can never happen
\r
203 protected DateFormat.Field patternCharToDateFormatField(char ch) {
\r
205 return ChineseDateFormat.Field.IS_LEAP_MONTH;
\r
207 return super.patternCharToDateFormatField(ch);
\r
211 * The instances of this inner class are used as attribute keys and values
\r
212 * in AttributedCharacterIterator that
\r
213 * ChineseDateFormat.formatToCharacterIterator() method returns.
\r
215 * There is no public constructor to this class, the only instances are the
\r
216 * constants defined here.
\r
220 public static class Field extends DateFormat.Field {
\r
222 private static final long serialVersionUID = -5102130532751400330L;
\r
225 * Constant identifying the leap month marker.
\r
228 public static final Field IS_LEAP_MONTH = new Field("is leap month", ChineseCalendar.IS_LEAP_MONTH);
\r
231 * Constructs a <code>ChineseDateFormat.Field</code> with the given name and
\r
232 * the <code>ChineseCalendar</code> field which this attribute represents.
\r
233 * Use -1 for <code>calendarField</code> if this field does not have a
\r
234 * corresponding <code>ChineseCalendar</code> field.
\r
236 * @param name Name of the attribute
\r
237 * @param calendarField <code>Calendar</code> field constant
\r
241 protected Field(String name, int calendarField) {
\r
242 super(name, calendarField);
\r
246 * Returns the <code>Field</code> constant that corresponds to the <code>
\r
247 * ChineseCalendar</code> field <code>calendarField</code>. If there is no
\r
248 * corresponding <code>Field</code> is available, null is returned.
\r
250 * @param calendarField <code>ChineseCalendar</code> field constant
\r
251 * @return <code>Field</code> associated with the <code>calendarField</code>,
\r
252 * or null if no associated <code>Field</code> is available.
\r
253 * @throws IllegalArgumentException if <code>calendarField</code> is not
\r
254 * a valid <code>Calendar</code> field constant.
\r
258 public static DateFormat.Field ofCalendarField(int calendarField) {
\r
259 if (calendarField == ChineseCalendar.IS_LEAP_MONTH) {
\r
260 return IS_LEAP_MONTH;
\r
262 return DateFormat.Field.ofCalendarField(calendarField);
\r
271 protected Object readResolve() throws InvalidObjectException {
\r
272 if (this.getClass() != ChineseDateFormat.Field.class) {
\r
273 throw new InvalidObjectException("A subclass of ChineseDateFormat.Field must implement readResolve.");
\r
275 if (this.getName().equals(IS_LEAP_MONTH.getName())) {
\r
276 return IS_LEAP_MONTH;
\r
278 throw new InvalidObjectException("Unknown attribute name.");
\r