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