• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /*
4  *******************************************************************************
5  * Copyright (C) 2008, International Business Machines Corporation and         *
6  * others. All Rights Reserved.                                                *
7  *******************************************************************************
8  */
9 package com.ibm.icu.impl.jdkadapter;
10 
11 import java.util.HashMap;
12 import java.util.Locale;
13 import java.util.Map;
14 import java.util.TimeZone;
15 
16 import com.ibm.icu.impl.icuadapter.TimeZoneJDK;
17 import com.ibm.icu.text.DateFormatSymbols;
18 import com.ibm.icu.util.Calendar;
19 
20 /**
21  * CalendarICU is an adapter class which wraps ICU4J Calendar and
22  * implements java.util.Calendar APIs.
23  */
24 public class CalendarICU extends java.util.Calendar {
25 
26     private static final long serialVersionUID = -8641226371713600671L;
27 
28     private Calendar fIcuCal;
29 
CalendarICU(Calendar icuCal)30     private CalendarICU(Calendar icuCal) {
31         fIcuCal = icuCal;
32         init();
33     }
34 
wrap(Calendar icuCal)35     public static java.util.Calendar wrap(Calendar icuCal) {
36         return new CalendarICU(icuCal);
37     }
38 
unwrap()39     public Calendar unwrap() {
40         sync();
41         return fIcuCal;
42     }
43 
44     @Override
add(int field, int amount)45     public void add(int field, int amount) {
46         sync();
47         fIcuCal.add(field, amount);
48     }
49 
50     // Note:    We do not need to override followings.  These methods
51     //          call int compareTo(Calendar anotherCalendar) and we
52     //          override the method.
53     //public boolean after(Object when)
54     //public boolean before(Object when)
55 
56     // Note:    Jeez!  These methods are final and we cannot override them.
57     //          We do not want to rewrite ICU Calendar implementation classes
58     //          as subclasses of java.util.Calendar.  This adapter class
59     //          wraps an ICU Calendar instance and the calendar calculation
60     //          is actually done independently from java.util.Calendar
61     //          implementation.  Thus, we need to monitor the status of
62     //          superclass fields in some methods and call ICU Calendar's
63     //          clear if superclass clear update the status of superclass's
64     //          calendar fields.  See private void sync().
65     //public void clear()
66     //public void clear(int field)
67 
68     @Override
clone()69     public Object clone() {
70         sync();
71         CalendarICU other = (CalendarICU)super.clone();
72         other.fIcuCal = (Calendar)fIcuCal.clone();
73         return other;
74     }
75 
compareTo(Calendar anotherCalendar)76     public int compareTo(Calendar anotherCalendar)  {
77         sync();
78         long thisMillis = getTimeInMillis();
79         long otherMillis = anotherCalendar.getTimeInMillis();
80         return thisMillis > otherMillis ? 1 : (thisMillis == otherMillis ? 0 : -1);
81     }
82 
83     // Note:    These methods are supposed to be implemented by java.util.Calendar
84     //          subclasses.  But we actually use a instance of ICU Calendar
85     //          for all calendar calculation, we do nothing here.
86     @Override
complete()87     protected void complete() {}
88     @Override
computeFields()89     protected void computeFields() {}
90     @Override
computeTime()91     protected void computeTime() {}
92 
93     @Override
equals(Object obj)94     public boolean equals(Object obj) {
95         if (obj instanceof CalendarICU) {
96             sync();
97             return ((CalendarICU)obj).fIcuCal.equals(fIcuCal);
98         }
99         return false;
100     }
101 
102     @Override
get(int field)103     public int get(int field) {
104         sync();
105         return fIcuCal.get(field);
106     }
107 
108     @Override
getActualMaximum(int field)109     public int getActualMaximum(int field) {
110         return fIcuCal.getActualMaximum(field);
111     }
112 
113     @Override
getActualMinimum(int field)114     public int getActualMinimum(int field) {
115         return fIcuCal.getActualMinimum(field);
116     }
117 
118     @Override
getDisplayName(int field, int style, Locale locale)119     public String getDisplayName(int field, int style, Locale locale) {
120         if (field < 0 || field >= FIELD_COUNT || (style != SHORT && style != LONG && style != ALL_STYLES)) {
121             throw new IllegalArgumentException("Bad field or style.");
122         }
123         DateFormatSymbols dfs = DateFormatSymbols.getInstance(locale);
124         String[] array = getFieldStrings(field, style, dfs);
125         if (array != null) {
126             int fieldVal = get(field);
127             if (fieldVal < array.length) {
128                 return array[fieldVal];
129             }
130         }
131         return null;
132     }
133 
134     @Override
getDisplayNames(int field, int style, Locale locale)135     public Map<String,Integer> getDisplayNames(int field, int style, Locale locale) {
136         if (field < 0 || field >= FIELD_COUNT || (style != SHORT && style != LONG && style != ALL_STYLES)) {
137             throw new IllegalArgumentException("Bad field or style.");
138         }
139         DateFormatSymbols dfs = DateFormatSymbols.getInstance(locale);
140         if (style != ALL_STYLES) {
141             return getFieldStringsMap(field, style, dfs);
142         }
143 
144         Map<String,Integer> result = getFieldStringsMap(field, SHORT, dfs);
145         if (result == null) {
146             return null;
147         }
148         if (field == MONTH || field == DAY_OF_WEEK) {
149             Map<String,Integer> longMap = getFieldStringsMap(field, LONG, dfs);
150             if (longMap != null) {
151                 result.putAll(longMap);
152             }
153         }
154         return result;
155     }
156 
157     @Override
getFirstDayOfWeek()158     public int getFirstDayOfWeek() {
159         return fIcuCal.getFirstDayOfWeek();
160     }
161 
162     @Override
getGreatestMinimum(int field)163     public int getGreatestMinimum(int field) {
164         return fIcuCal.getGreatestMinimum(field);
165     }
166 
167     @Override
getLeastMaximum(int field)168     public int getLeastMaximum(int field) {
169         return fIcuCal.getLeastMaximum(field);
170     }
171 
172     @Override
getMaximum(int field)173     public int getMaximum(int field) {
174         return fIcuCal.getMaximum(field);
175     }
176 
177     @Override
getMinimalDaysInFirstWeek()178     public int getMinimalDaysInFirstWeek() {
179         return fIcuCal.getMinimalDaysInFirstWeek();
180     }
181 
182     @Override
getMinimum(int field)183     public int getMinimum(int field) {
184         return fIcuCal.getMinimum(field);
185     }
186 
187     // Note:    getTime() calls getTimeInMillis()
188     //public Date getTime()
189 
190     @Override
getTimeInMillis()191     public long getTimeInMillis() {
192         sync();
193         return fIcuCal.getTimeInMillis();
194     }
195 
196     @Override
getTimeZone()197     public TimeZone getTimeZone() {
198         return TimeZoneICU.wrap(fIcuCal.getTimeZone());
199     }
200 
201     @Override
hashCode()202     public int hashCode() {
203         sync();
204         return fIcuCal.hashCode();
205     }
206 
207     //protected int internalGet(int field)
208 
209     @Override
isLenient()210     public boolean isLenient() {
211         return fIcuCal.isLenient();
212     }
213 
214     //public boolean isSet(int field)
215 
216     @Override
roll(int field, boolean up)217     public void roll(int field, boolean up) {
218         sync();
219         fIcuCal.roll(field, up);
220     }
221 
222     @Override
roll(int field, int amount)223     public void roll(int field, int amount) {
224         sync();
225         fIcuCal.roll(field, amount);
226     }
227 
228     @Override
set(int field, int value)229     public void set(int field, int value) {
230         sync();
231         fIcuCal.set(field, value);
232     }
233 
234     // Note:    These set methods call set(int field, int value) for each field.
235     //          These are final, so we cannot override them, but we override
236     //          set(int field, int value), so the superclass implementations
237     //          still work as we want.
238     //public void set(int year, int month, int date)
239     //public void set(int year, int month, int date, int hourOfDay, int minute)
240     //public void set(int year, int month, int date, int hourOfDay, int minute, int second)
241 
242     @Override
setFirstDayOfWeek(int value)243     public void setFirstDayOfWeek(int value) {
244         fIcuCal.setFirstDayOfWeek(value);
245     }
246 
247     @Override
setLenient(boolean lenient)248     public void setLenient(boolean lenient) {
249         fIcuCal.setLenient(lenient);
250     }
251 
252     @Override
setMinimalDaysInFirstWeek(int value)253     public void setMinimalDaysInFirstWeek(int value) {
254         fIcuCal.setMinimalDaysInFirstWeek(value);
255     }
256 
257     // Note:    This method calls setTimeInMillis(long millis).
258     //          This method is final, so we cannot override it, but we
259     //          override setTimeInMillis(long millis), so the superclass
260     //          implementation still works as we want.
261     //public void setTime(Date date)
262 
263     @Override
setTimeInMillis(long millis)264     public void setTimeInMillis(long millis) {
265         fIcuCal.setTimeInMillis(millis);
266     }
267 
268     @Override
setTimeZone(TimeZone value)269     public void setTimeZone(TimeZone value) {
270         fIcuCal.setTimeZone(TimeZoneJDK.wrap(value));
271     }
272 
273     @Override
toString()274     public String toString() {
275         sync();
276         return "CalendarICU: " + fIcuCal.toString();
277     }
278 
sync()279     private void sync() {
280         // Check if clear is called for each JDK Calendar field.
281         // If it was, then call clear for the field in the wrapped
282         // ICU Calendar.
283         for (int i = 0; i < isSet.length; i++) {
284             if (!isSet[i]) {
285                 isSet[i] = true;
286                 try {
287                     fIcuCal.clear(i);
288                 } catch (ArrayIndexOutOfBoundsException e) {
289                     // More fields in JDK calendar, which is unlikely
290                 }
291             }
292         }
293     }
294 
init()295     private void init() {
296         // Mark "set" for all fields, so we can detect the invocation of
297         // clear() later.
298         for (int i = 0; i < isSet.length; i++) {
299             isSet[i] = true;
300         }
301     }
302 
getFieldStrings(int field, int style, DateFormatSymbols dfs)303     private static String[] getFieldStrings(int field, int style, DateFormatSymbols dfs) {
304         String[] result = null;
305         switch (field) {
306         case AM_PM:
307             result = dfs.getAmPmStrings();
308             break;
309         case DAY_OF_WEEK:
310             result = (style == LONG) ? dfs.getWeekdays() : dfs.getShortWeekdays();
311             break;
312         case ERA:
313             //result = (style == LONG) ? dfs.getEraNames() : dfs.getEras();
314             result = dfs.getEras();
315             break;
316         case MONTH:
317             result = (style == LONG) ? dfs.getMonths() : dfs.getShortMonths();
318             break;
319         }
320         return result;
321     }
322 
getFieldStringsMap(int field, int style, DateFormatSymbols dfs)323     private static Map<String,Integer> getFieldStringsMap(int field, int style, DateFormatSymbols dfs) {
324         String[] strings = getFieldStrings(field, style, dfs);
325         if (strings == null) {
326             return null;
327         }
328         Map<String,Integer> res = new HashMap<String,Integer>();
329         for (int i = 0; i < strings.length; i++) {
330             if (strings[i].length() != 0) {
331                 res.put(strings[i], Integer.valueOf(i));
332             }
333         }
334         return res;
335     }
336 }
337