]> gitweb.fperrin.net Git - Dictionary.git/blob - jars/icu4j-4_4_2-src/main/classes/localespi/src/com/ibm/icu/impl/jdkadapter/SimpleDateFormatICU.java
go
[Dictionary.git] / jars / icu4j-4_4_2-src / main / classes / localespi / src / com / ibm / icu / impl / jdkadapter / SimpleDateFormatICU.java
1 /*\r
2  *******************************************************************************\r
3  * Copyright (C) 2008, International Business Machines Corporation and         *\r
4  * others. All Rights Reserved.                                                *\r
5  *******************************************************************************\r
6  */\r
7 package com.ibm.icu.impl.jdkadapter;\r
8 \r
9 import java.text.AttributedCharacterIterator;\r
10 import java.text.AttributedString;\r
11 import java.text.CharacterIterator;\r
12 import java.text.DateFormatSymbols;\r
13 import java.text.FieldPosition;\r
14 import java.text.NumberFormat;\r
15 import java.text.ParsePosition;\r
16 import java.util.Calendar;\r
17 import java.util.Date;\r
18 import java.util.GregorianCalendar;\r
19 import java.util.HashMap;\r
20 import java.util.Map;\r
21 import java.util.Set;\r
22 import java.util.TimeZone;\r
23 \r
24 import com.ibm.icu.impl.icuadapter.NumberFormatJDK;\r
25 import com.ibm.icu.impl.icuadapter.TimeZoneJDK;\r
26 import com.ibm.icu.text.DateFormat;\r
27 import com.ibm.icu.text.SimpleDateFormat;\r
28 \r
29 /**\r
30  * SimpleDateFormatICU is an adapter class which wraps ICU4J SimpleDateFormat and\r
31  * implements java.text.SimpleDateFormat APIs.\r
32  */\r
33 public class SimpleDateFormatICU extends java.text.SimpleDateFormat {\r
34 \r
35     private static final long serialVersionUID = -2060890659010258983L;\r
36 \r
37     private SimpleDateFormat fIcuSdf;\r
38 \r
39     private SimpleDateFormatICU(SimpleDateFormat icuSdf) {\r
40         fIcuSdf = icuSdf;\r
41     }\r
42 \r
43     public static java.text.SimpleDateFormat wrap(SimpleDateFormat icuSdf) {\r
44         return new SimpleDateFormatICU(icuSdf);\r
45     }\r
46 \r
47     // Methods overriding java.text.SimpleDateFormat\r
48 \r
49     @Override\r
50     public void applyLocalizedPattern(String pattern) {\r
51         fIcuSdf.applyLocalizedPattern(pattern);\r
52     }\r
53 \r
54     @Override\r
55     public void applyPattern(String pattern) {\r
56         fIcuSdf.applyPattern(pattern);\r
57     }\r
58 \r
59     @Override\r
60     public Object clone() {\r
61         SimpleDateFormatICU other = (SimpleDateFormatICU)super.clone();\r
62         other.fIcuSdf = (SimpleDateFormat)this.fIcuSdf.clone();\r
63         return other;\r
64     }\r
65 \r
66     @Override\r
67     public boolean equals(Object obj) {\r
68         if (obj instanceof SimpleDateFormatICU) {\r
69             return ((SimpleDateFormatICU)obj).fIcuSdf.equals(this.fIcuSdf);\r
70         }\r
71         return false;\r
72     }\r
73 \r
74     @Override\r
75     public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition pos) {\r
76         return fIcuSdf.format(date, toAppendTo, pos);\r
77     }\r
78 \r
79     @Override\r
80     public AttributedCharacterIterator formatToCharacterIterator(Object obj) {\r
81         AttributedCharacterIterator aci = fIcuSdf.formatToCharacterIterator(obj);\r
82 \r
83         // Create a new AttributedString\r
84         StringBuilder sb = new StringBuilder(aci.getEndIndex() - aci.getBeginIndex());\r
85         char c = aci.first();\r
86         while (true) {\r
87             sb.append(c);\r
88             c = aci.next();\r
89             if (c == CharacterIterator.DONE) {\r
90                 break;\r
91             }\r
92         }\r
93         AttributedString resstr = new AttributedString(sb.toString());\r
94 \r
95         // Mapping attributes\r
96         Map<AttributedCharacterIterator.Attribute,Object> attributes = null;\r
97         int index = aci.getBeginIndex();\r
98         int residx = 0;\r
99         while (true) {\r
100             if (aci.setIndex(index) == CharacterIterator.DONE) {\r
101                 break;\r
102             }\r
103             attributes = aci.getAttributes();\r
104             if (attributes != null) {\r
105                 int end = aci.getRunLimit();\r
106                 Map<AttributedCharacterIterator.Attribute,Object> jdkAttributes = \r
107                     new HashMap<AttributedCharacterIterator.Attribute,Object>();\r
108                 Set<AttributedCharacterIterator.Attribute> keys = attributes.keySet();\r
109                 for (AttributedCharacterIterator.Attribute key : keys) {\r
110                     AttributedCharacterIterator.Attribute jdkKey = mapAttribute(key);\r
111                     Object jdkVal = attributes.get(key);\r
112                     if (jdkVal instanceof AttributedCharacterIterator.Attribute) {\r
113                         jdkVal = mapAttribute((AttributedCharacterIterator.Attribute)jdkVal);\r
114                     }\r
115                     jdkAttributes.put(jdkKey, jdkVal);\r
116                 }\r
117                 int resend = residx + (end - index);\r
118                 resstr.addAttributes(jdkAttributes, residx, resend);\r
119 \r
120                 index = end;\r
121                 residx = resend;\r
122             }\r
123         }\r
124         return resstr.getIterator();\r
125     }\r
126 \r
127     @Override\r
128     public Date get2DigitYearStart() {\r
129         return fIcuSdf.get2DigitYearStart();\r
130     }\r
131 \r
132     @Override\r
133     public DateFormatSymbols getDateFormatSymbols() {\r
134         return DateFormatSymbolsICU.wrap(fIcuSdf.getDateFormatSymbols());\r
135     }\r
136 \r
137     @Override\r
138     public int hashCode() {\r
139         return fIcuSdf.hashCode();\r
140     }\r
141 \r
142     @Override\r
143     public Date parse(String text, ParsePosition pos) {\r
144         return fIcuSdf.parse(text, pos);\r
145     }\r
146 \r
147     @Override\r
148     public void set2DigitYearStart(Date startDate) {\r
149         fIcuSdf.set2DigitYearStart(startDate);\r
150     }\r
151 \r
152     @Override\r
153     public void setDateFormatSymbols(DateFormatSymbols newFormatSymbols) {\r
154         com.ibm.icu.text.DateFormatSymbols icuDfs = null;\r
155         if (newFormatSymbols instanceof DateFormatSymbolsICU) {\r
156             icuDfs = ((DateFormatSymbolsICU)newFormatSymbols).unwrap();\r
157         } else if (fIcuSdf.getCalendar() instanceof com.ibm.icu.util.GregorianCalendar) {\r
158             // Java 6 uses DateFormatSymbols exclusively for Gregorian\r
159             // calendar.\r
160 \r
161             String[] newJDK, curICU, newICU;\r
162             icuDfs = fIcuSdf.getDateFormatSymbols();\r
163 \r
164             // Eras\r
165             newJDK = newFormatSymbols.getEras();\r
166             curICU = icuDfs.getEras();\r
167             newICU = copySymbols(newJDK, curICU, true);\r
168 \r
169             // Months\r
170             newJDK = newFormatSymbols.getMonths();\r
171             curICU = icuDfs.getMonths();\r
172             newICU = copySymbols(newJDK, curICU, false);\r
173             icuDfs.setMonths(newICU);\r
174 \r
175             // ShortMonths\r
176             newJDK = newFormatSymbols.getShortMonths();\r
177             curICU = icuDfs.getShortMonths();\r
178             newICU = copySymbols(newJDK, curICU, false);\r
179             icuDfs.setShortMonths(newICU);\r
180 \r
181             // Weekdays\r
182             newJDK = newFormatSymbols.getWeekdays();\r
183             curICU = icuDfs.getWeekdays();\r
184             newICU = copySymbols(newJDK, curICU, false);\r
185             icuDfs.setWeekdays(newICU);\r
186 \r
187             // ShortWeekdays\r
188             newJDK = newFormatSymbols.getShortWeekdays();\r
189             curICU = icuDfs.getShortWeekdays();\r
190             newICU = copySymbols(newJDK, curICU, false);\r
191             icuDfs.setShortWeekdays(newICU);\r
192 \r
193             // AmPm\r
194             newJDK = newFormatSymbols.getAmPmStrings();\r
195             curICU = icuDfs.getAmPmStrings();\r
196             newICU = copySymbols(newJDK, curICU, false);\r
197             icuDfs.setAmPmStrings(newICU);\r
198         } else {\r
199             // For other calendars, JDK's standard DateFormatSymbols\r
200             // cannot be used.\r
201             throw new UnsupportedOperationException("JDK DateFormatSymbols cannot be used for the calendar type.");\r
202         }\r
203         fIcuSdf.setDateFormatSymbols(icuDfs);\r
204     }\r
205 \r
206     @Override\r
207     public String toLocalizedPattern() {\r
208         return fIcuSdf.toLocalizedPattern();\r
209     }\r
210 \r
211     @Override\r
212     public String toPattern() {\r
213         return fIcuSdf.toLocalizedPattern();\r
214     }\r
215 \r
216     // Methods overriding java.text.DateFormat\r
217 \r
218     @Override\r
219     public Calendar getCalendar() {\r
220         return CalendarICU.wrap(fIcuSdf.getCalendar());\r
221     }\r
222 \r
223     @Override\r
224     public NumberFormat getNumberFormat() {\r
225         com.ibm.icu.text.NumberFormat nfmt = fIcuSdf.getNumberFormat();\r
226         if (nfmt instanceof NumberFormatJDK) {\r
227             return ((NumberFormatJDK)nfmt).unwrap();\r
228         }\r
229         if (nfmt instanceof com.ibm.icu.text.DecimalFormat) {\r
230             return DecimalFormatICU.wrap((com.ibm.icu.text.DecimalFormat)nfmt);\r
231         }\r
232         return NumberFormatICU.wrap(nfmt);\r
233     }\r
234 \r
235     @Override\r
236     public TimeZone getTimeZone() {\r
237         return getCalendar().getTimeZone();\r
238     }\r
239 \r
240     @Override\r
241     public boolean isLenient() {\r
242         return fIcuSdf.isLenient();\r
243     }\r
244 \r
245     private static final long SAMPLE_TIME = 962409600000L; //2000-07-01T00:00:00Z\r
246     private static final int JAPANESE_YEAR = 12; // Japanese calendar year @ SAMPLE_TIME\r
247     private static final int THAI_YEAR = 2543; // Thai Buddhist calendar year @ SAMPLE_TIME\r
248 \r
249     @Override\r
250     public void setCalendar(Calendar newCalendar) {\r
251         com.ibm.icu.util.Calendar icuCal = null;\r
252         if (newCalendar instanceof CalendarICU) {\r
253             icuCal = ((CalendarICU)newCalendar).unwrap();\r
254         } else {\r
255             // Note:    There is no easy way to implement ICU Calendar with\r
256             //          JDK Calendar implementation.  For now, this code assumes\r
257             //          the given calendar is either Gregorian, Buddhist or\r
258             //          JapaneseImperial.  Once the type is detected, this code\r
259             //          creates an instance of ICU Calendar with the same type.\r
260             com.ibm.icu.util.TimeZone icuTz = TimeZoneJDK.wrap(newCalendar.getTimeZone());\r
261             if (newCalendar instanceof GregorianCalendar) {\r
262                 icuCal = new com.ibm.icu.util.GregorianCalendar(icuTz);\r
263             } else {\r
264                 newCalendar.setTimeInMillis(SAMPLE_TIME);\r
265                 int year = newCalendar.get(Calendar.YEAR);\r
266                 if (year == JAPANESE_YEAR) {\r
267                     icuCal = new com.ibm.icu.util.JapaneseCalendar(icuTz);\r
268                 } else if (year == THAI_YEAR) {\r
269                     icuCal = new com.ibm.icu.util.BuddhistCalendar(icuTz);\r
270                 } else {\r
271                     // We cannot support the case\r
272                     throw new UnsupportedOperationException("Unsupported calendar type by ICU Calendar adapter.");\r
273                 }\r
274             }\r
275             // Copy the original calendar settings\r
276             icuCal.setFirstDayOfWeek(newCalendar.getFirstDayOfWeek());\r
277             icuCal.setLenient(newCalendar.isLenient());\r
278             icuCal.setMinimalDaysInFirstWeek(newCalendar.getMinimalDaysInFirstWeek());\r
279         }\r
280         fIcuSdf.setCalendar(icuCal);\r
281     }\r
282 \r
283     @Override\r
284     public void setLenient(boolean lenient) {\r
285         fIcuSdf.setLenient(lenient);\r
286     }\r
287 \r
288     @Override\r
289     public void setNumberFormat(NumberFormat newNumberFormat) {\r
290         if (newNumberFormat instanceof DecimalFormatICU) {\r
291             fIcuSdf.setNumberFormat(((DecimalFormatICU)newNumberFormat).unwrap());\r
292         } else if (newNumberFormat instanceof NumberFormatICU) {\r
293             fIcuSdf.setNumberFormat(((NumberFormatICU)newNumberFormat).unwrap());\r
294         } else {\r
295             fIcuSdf.setNumberFormat(NumberFormatJDK.wrap(newNumberFormat));\r
296         }\r
297     }\r
298 \r
299     @Override\r
300     public void setTimeZone(TimeZone zone) {\r
301         fIcuSdf.setTimeZone(TimeZoneJDK.wrap(zone));\r
302     }\r
303 \r
304     private String[] copySymbols(String[] newData, String[] curData, boolean alignEnd) {\r
305         if (newData.length >= curData.length) {\r
306             return newData;\r
307         }\r
308         int startOffset = alignEnd ? curData.length - newData.length : 0;\r
309         System.arraycopy(newData, 0, curData, startOffset, newData.length);\r
310         return curData;\r
311     }\r
312 \r
313     private static AttributedCharacterIterator.Attribute mapAttribute(AttributedCharacterIterator.Attribute icuAttribute) {\r
314         AttributedCharacterIterator.Attribute jdkAttribute = icuAttribute;\r
315 \r
316         if (icuAttribute == DateFormat.Field.AM_PM) {\r
317             jdkAttribute = java.text.DateFormat.Field.AM_PM;\r
318         } else if (icuAttribute == DateFormat.Field.DAY_OF_MONTH) {\r
319             jdkAttribute = java.text.DateFormat.Field.DAY_OF_MONTH;\r
320         } else if (icuAttribute == DateFormat.Field.DAY_OF_WEEK) {\r
321             jdkAttribute = java.text.DateFormat.Field.DAY_OF_WEEK;\r
322         } else if (icuAttribute == DateFormat.Field.DAY_OF_WEEK_IN_MONTH) {\r
323             jdkAttribute = java.text.DateFormat.Field.DAY_OF_WEEK_IN_MONTH;\r
324         } else if (icuAttribute == DateFormat.Field.DAY_OF_YEAR) {\r
325             jdkAttribute = java.text.DateFormat.Field.DAY_OF_YEAR;\r
326         } else if (icuAttribute == DateFormat.Field.ERA) {\r
327             jdkAttribute = java.text.DateFormat.Field.ERA;\r
328         } else if (icuAttribute == DateFormat.Field.HOUR_OF_DAY0) {\r
329             jdkAttribute = java.text.DateFormat.Field.HOUR_OF_DAY0;\r
330         } else if (icuAttribute == DateFormat.Field.HOUR_OF_DAY1) {\r
331             jdkAttribute = java.text.DateFormat.Field.HOUR_OF_DAY1;\r
332         } else if (icuAttribute == DateFormat.Field.HOUR0) {\r
333             jdkAttribute = java.text.DateFormat.Field.HOUR0;\r
334         } else if (icuAttribute == DateFormat.Field.HOUR1) {\r
335             jdkAttribute = java.text.DateFormat.Field.HOUR1;\r
336         } else if (icuAttribute == DateFormat.Field.MILLISECOND) {\r
337             jdkAttribute = java.text.DateFormat.Field.MILLISECOND;\r
338         } else if (icuAttribute == DateFormat.Field.MINUTE) {\r
339             jdkAttribute = java.text.DateFormat.Field.MINUTE;\r
340         } else if (icuAttribute == DateFormat.Field.MONTH) {\r
341             jdkAttribute = java.text.DateFormat.Field.MONTH;\r
342         } else if (icuAttribute == DateFormat.Field.SECOND) {\r
343             jdkAttribute = java.text.DateFormat.Field.SECOND;\r
344         } else if (icuAttribute == DateFormat.Field.TIME_ZONE) {\r
345             jdkAttribute = java.text.DateFormat.Field.TIME_ZONE;\r
346         } else if (icuAttribute == DateFormat.Field.WEEK_OF_MONTH) {\r
347             jdkAttribute = java.text.DateFormat.Field.WEEK_OF_MONTH;\r
348         } else if (icuAttribute == DateFormat.Field.WEEK_OF_YEAR) {\r
349             jdkAttribute = java.text.DateFormat.Field.WEEK_OF_YEAR;\r
350         } else if (icuAttribute == DateFormat.Field.YEAR) {\r
351             jdkAttribute = java.text.DateFormat.Field.YEAR;\r
352         }\r
353         // There are other DateFormat.Field constants defined in\r
354         // ICU4J DateFormat below.\r
355         //\r
356         //   DOW_LOCAL\r
357         //   EXTENDED_YEAR\r
358         //   JULIAN_DAY\r
359         //   MILLISECONDS_IN_DAY\r
360         //   QUARTER\r
361         //   YEAR_WOY\r
362         //\r
363         // However, the corresponding pattern characters are not used by\r
364         // the default factory method - getXXXInstance.  So these constants\r
365         // are only used when user intentionally set a pattern including\r
366         // these ICU4J specific pattern letters.  Even it happens,\r
367         // ICU4J's DateFormat.Field extends java.text.Format.Field, so\r
368         // it does not break the contract of formatToCharacterIterator.\r
369 \r
370         return jdkAttribute;\r
371     }\r
372 \r
373 }\r