/src/icu/source/i18n/calendar.cpp
Line  | Count  | Source (jump to first uncovered line)  | 
1  |  | // © 2016 and later: Unicode, Inc. and others.  | 
2  |  | // License & terms of use: http://www.unicode.org/copyright.html  | 
3  |  | /*  | 
4  |  | *******************************************************************************  | 
5  |  | * Copyright (C) 1997-2016, International Business Machines Corporation and    *  | 
6  |  | * others. All Rights Reserved.                                                *  | 
7  |  | *******************************************************************************  | 
8  |  | *  | 
9  |  | * File CALENDAR.CPP  | 
10  |  | *  | 
11  |  | * Modification History:  | 
12  |  | *  | 
13  |  | *   Date        Name        Description  | 
14  |  | *   02/03/97    clhuang     Creation.  | 
15  |  | *   04/22/97    aliu        Cleaned up, fixed memory leak, made  | 
16  |  | *                           setWeekCountData() more robust.  | 
17  |  | *                           Moved platform code to TPlatformUtilities.  | 
18  |  | *   05/01/97    aliu        Made equals(), before(), after() arguments const.  | 
19  |  | *   05/20/97    aliu        Changed logic of when to compute fields and time  | 
20  |  | *                           to fix bugs.  | 
21  |  | *   08/12/97    aliu        Added equivalentTo.  Misc other fixes.  | 
22  |  | *   07/28/98    stephen     Sync up with JDK 1.2  | 
23  |  | *   09/02/98    stephen     Sync with JDK 1.2 8/31 build (getActualMin/Max)  | 
24  |  | *   03/17/99    stephen     Changed adoptTimeZone() - now fAreFieldsSet is  | 
25  |  | *                           set to FALSE to force update of time.  | 
26  |  | *******************************************************************************  | 
27  |  | */  | 
28  |  |  | 
29  |  | #include "utypeinfo.h"  // for 'typeid' to work  | 
30  |  |  | 
31  |  | #include "unicode/utypes.h"  | 
32  |  |  | 
33  |  | #if !UCONFIG_NO_FORMATTING  | 
34  |  |  | 
35  |  | #include "unicode/gregocal.h"  | 
36  |  | #include "unicode/basictz.h"  | 
37  |  | #include "unicode/simpletz.h"  | 
38  |  | #include "unicode/rbtz.h"  | 
39  |  | #include "unicode/vtzone.h"  | 
40  |  | #include "gregoimp.h"  | 
41  |  | #include "buddhcal.h"  | 
42  |  | #include "taiwncal.h"  | 
43  |  | #include "japancal.h"  | 
44  |  | #include "islamcal.h"  | 
45  |  | #include "hebrwcal.h"  | 
46  |  | #include "persncal.h"  | 
47  |  | #include "indiancal.h"  | 
48  |  | #include "chnsecal.h"  | 
49  |  | #include "coptccal.h"  | 
50  |  | #include "dangical.h"  | 
51  |  | #include "ethpccal.h"  | 
52  |  | #include "unicode/calendar.h"  | 
53  |  | #include "cpputils.h"  | 
54  |  | #include "servloc.h"  | 
55  |  | #include "ucln_in.h"  | 
56  |  | #include "cstring.h"  | 
57  |  | #include "locbased.h"  | 
58  |  | #include "uresimp.h"  | 
59  |  | #include "ustrenum.h"  | 
60  |  | #include "uassert.h"  | 
61  |  | #include "olsontz.h"  | 
62  |  | #include "sharedcalendar.h"  | 
63  |  | #include "unifiedcache.h"  | 
64  |  | #include "ulocimp.h"  | 
65  |  |  | 
66  |  | #if !UCONFIG_NO_SERVICE  | 
67  |  | static icu::ICULocaleService* gService = NULL;  | 
68  |  | static icu::UInitOnce gServiceInitOnce = U_INITONCE_INITIALIZER;  | 
69  |  |  | 
70  |  | // INTERNAL - for cleanup  | 
71  |  | U_CDECL_BEGIN  | 
72  | 0  | static UBool calendar_cleanup(void) { | 
73  | 0  | #if !UCONFIG_NO_SERVICE  | 
74  | 0  |     if (gService) { | 
75  | 0  |         delete gService;  | 
76  | 0  |         gService = NULL;  | 
77  | 0  |     }  | 
78  | 0  |     gServiceInitOnce.reset();  | 
79  | 0  | #endif  | 
80  | 0  |     return TRUE;  | 
81  | 0  | }  | 
82  |  | U_CDECL_END  | 
83  |  | #endif  | 
84  |  |  | 
85  |  | // ------------------------------------------  | 
86  |  | //  | 
87  |  | // Registration  | 
88  |  | //  | 
89  |  | //-------------------------------------------  | 
90  |  | //#define U_DEBUG_CALSVC 1  | 
91  |  | //  | 
92  |  |  | 
93  |  | #if defined( U_DEBUG_CALSVC ) || defined (U_DEBUG_CAL)  | 
94  |  |  | 
95  |  | /**  | 
96  |  |  * fldName was removed as a duplicate implementation.  | 
97  |  |  * use  udbg_ services instead,  | 
98  |  |  * which depend on include files and library from ../tools/toolutil, the following circular link:  | 
99  |  |  *   CPPFLAGS+=-I$(top_srcdir)/tools/toolutil  | 
100  |  |  *   LIBS+=$(LIBICUTOOLUTIL)  | 
101  |  |  */  | 
102  |  | #include "udbgutil.h"  | 
103  |  | #include <stdio.h>  | 
104  |  |  | 
105  |  | /**  | 
106  |  | * convert a UCalendarDateFields into a string - for debugging  | 
107  |  | * @param f field enum  | 
108  |  | * @return static string to the field name  | 
109  |  | * @internal  | 
110  |  | */  | 
111  |  |  | 
112  |  | const char* fldName(UCalendarDateFields f) { | 
113  |  |     return udbg_enumName(UDBG_UCalendarDateFields, (int32_t)f);  | 
114  |  | }  | 
115  |  |  | 
116  |  | #if UCAL_DEBUG_DUMP  | 
117  |  | // from CalendarTest::calToStr - but doesn't modify contents.  | 
118  |  | void ucal_dump(const Calendar &cal) { | 
119  |  |     cal.dump();  | 
120  |  | }  | 
121  |  |  | 
122  |  | void Calendar::dump() const { | 
123  |  |     int i;  | 
124  |  |     fprintf(stderr, "@calendar=%s, timeset=%c, fieldset=%c, allfields=%c, virtualset=%c, t=%.2f",  | 
125  |  |         getType(), fIsTimeSet?'y':'n',  fAreFieldsSet?'y':'n',  fAreAllFieldsSet?'y':'n',  | 
126  |  |         fAreFieldsVirtuallySet?'y':'n',  | 
127  |  |         fTime);  | 
128  |  |  | 
129  |  |     // can add more things here: DST, zone, etc.  | 
130  |  |     fprintf(stderr, "\n");  | 
131  |  |     for(i = 0;i<UCAL_FIELD_COUNT;i++) { | 
132  |  |         int n;  | 
133  |  |         const char *f = fldName((UCalendarDateFields)i);  | 
134  |  |         fprintf(stderr, "  %25s: %-11ld", f, fFields[i]);  | 
135  |  |         if(fStamp[i] == kUnset) { | 
136  |  |             fprintf(stderr, " (unset) ");  | 
137  |  |         } else if(fStamp[i] == kInternallySet) { | 
138  |  |             fprintf(stderr, " (internally set) ");  | 
139  |  |             //} else if(fStamp[i] == kInternalDefault) { | 
140  |  |             //    fprintf(stderr, " (internal default) ");  | 
141  |  |         } else { | 
142  |  |             fprintf(stderr, " %%%d ", fStamp[i]);  | 
143  |  |         }  | 
144  |  |         fprintf(stderr, "\n");  | 
145  |  |  | 
146  |  |     }  | 
147  |  | }  | 
148  |  |  | 
149  |  | U_CFUNC void ucal_dump(UCalendar* cal) { | 
150  |  |     ucal_dump( *((Calendar*)cal)  );  | 
151  |  | }  | 
152  |  | #endif  | 
153  |  |  | 
154  |  | #endif  | 
155  |  |  | 
156  |  | /* Max value for stamp allowable before recalculation */  | 
157  | 0  | #define STAMP_MAX 10000  | 
158  |  |  | 
159  |  | static const char * const gCalTypes[] = { | 
160  |  |     "gregorian",  | 
161  |  |     "japanese",  | 
162  |  |     "buddhist",  | 
163  |  |     "roc",  | 
164  |  |     "persian",  | 
165  |  |     "islamic-civil",  | 
166  |  |     "islamic",  | 
167  |  |     "hebrew",  | 
168  |  |     "chinese",  | 
169  |  |     "indian",  | 
170  |  |     "coptic",  | 
171  |  |     "ethiopic",  | 
172  |  |     "ethiopic-amete-alem",  | 
173  |  |     "iso8601",  | 
174  |  |     "dangi",  | 
175  |  |     "islamic-umalqura",  | 
176  |  |     "islamic-tbla",  | 
177  |  |     "islamic-rgsa",  | 
178  |  |     NULL  | 
179  |  | };  | 
180  |  |  | 
181  |  | // Must be in the order of gCalTypes above  | 
182  |  | typedef enum ECalType { | 
183  |  |     CALTYPE_UNKNOWN = -1,  | 
184  |  |     CALTYPE_GREGORIAN = 0,  | 
185  |  |     CALTYPE_JAPANESE,  | 
186  |  |     CALTYPE_BUDDHIST,  | 
187  |  |     CALTYPE_ROC,  | 
188  |  |     CALTYPE_PERSIAN,  | 
189  |  |     CALTYPE_ISLAMIC_CIVIL,  | 
190  |  |     CALTYPE_ISLAMIC,  | 
191  |  |     CALTYPE_HEBREW,  | 
192  |  |     CALTYPE_CHINESE,  | 
193  |  |     CALTYPE_INDIAN,  | 
194  |  |     CALTYPE_COPTIC,  | 
195  |  |     CALTYPE_ETHIOPIC,  | 
196  |  |     CALTYPE_ETHIOPIC_AMETE_ALEM,  | 
197  |  |     CALTYPE_ISO8601,  | 
198  |  |     CALTYPE_DANGI,  | 
199  |  |     CALTYPE_ISLAMIC_UMALQURA,  | 
200  |  |     CALTYPE_ISLAMIC_TBLA,  | 
201  |  |     CALTYPE_ISLAMIC_RGSA  | 
202  |  | } ECalType;  | 
203  |  |  | 
204  |  | U_NAMESPACE_BEGIN  | 
205  |  |  | 
206  | 0  | SharedCalendar::~SharedCalendar() { | 
207  | 0  |     delete ptr;  | 
208  | 0  | }  | 
209  |  |  | 
210  |  | template<> U_I18N_API  | 
211  |  | const SharedCalendar *LocaleCacheKey<SharedCalendar>::createObject(  | 
212  | 0  |         const void * /*unusedCreationContext*/, UErrorCode &status) const { | 
213  | 0  |     Calendar *calendar = Calendar::makeInstance(fLoc, status);  | 
214  | 0  |     if (U_FAILURE(status)) { | 
215  | 0  |         return NULL;  | 
216  | 0  |     }  | 
217  | 0  |     SharedCalendar *shared = new SharedCalendar(calendar);  | 
218  | 0  |     if (shared == NULL) { | 
219  | 0  |         delete calendar;  | 
220  | 0  |         status = U_MEMORY_ALLOCATION_ERROR;  | 
221  | 0  |         return NULL;  | 
222  | 0  |     }  | 
223  | 0  |     shared->addRef();  | 
224  | 0  |     return shared;  | 
225  | 0  | }  | 
226  |  |  | 
227  | 0  | static ECalType getCalendarType(const char *s) { | 
228  | 0  |     for (int i = 0; gCalTypes[i] != NULL; i++) { | 
229  | 0  |         if (uprv_stricmp(s, gCalTypes[i]) == 0) { | 
230  | 0  |             return (ECalType)i;  | 
231  | 0  |         }  | 
232  | 0  |     }  | 
233  | 0  |     return CALTYPE_UNKNOWN;  | 
234  | 0  | }  | 
235  |  |  | 
236  |  | #if !UCONFIG_NO_SERVICE  | 
237  |  | // Only used with service registration.  | 
238  | 0  | static UBool isStandardSupportedKeyword(const char *keyword, UErrorCode& status) { | 
239  | 0  |     if(U_FAILURE(status)) { | 
240  | 0  |         return FALSE;  | 
241  | 0  |     }  | 
242  | 0  |     ECalType calType = getCalendarType(keyword);  | 
243  | 0  |     return (calType != CALTYPE_UNKNOWN);  | 
244  | 0  | }  | 
245  |  |  | 
246  |  | // only used with service registration.  | 
247  | 0  | static void getCalendarKeyword(const UnicodeString &id, char *targetBuffer, int32_t targetBufferSize) { | 
248  | 0  |     UnicodeString calendarKeyword = UNICODE_STRING_SIMPLE("calendar="); | 
249  | 0  |     int32_t calKeyLen = calendarKeyword.length();  | 
250  | 0  |     int32_t keyLen = 0;  | 
251  |  | 
  | 
252  | 0  |     int32_t keywordIdx = id.indexOf((UChar)0x003D); /* '=' */  | 
253  | 0  |     if (id[0] == 0x40/*'@'*/  | 
254  | 0  |         && id.compareBetween(1, keywordIdx+1, calendarKeyword, 0, calKeyLen) == 0)  | 
255  | 0  |     { | 
256  | 0  |         keyLen = id.extract(keywordIdx+1, id.length(), targetBuffer, targetBufferSize, US_INV);  | 
257  | 0  |     }  | 
258  | 0  |     targetBuffer[keyLen] = 0;  | 
259  | 0  | }  | 
260  |  | #endif  | 
261  |  |  | 
262  | 0  | static ECalType getCalendarTypeForLocale(const char *locid) { | 
263  | 0  |     UErrorCode status = U_ZERO_ERROR;  | 
264  | 0  |     ECalType calType = CALTYPE_UNKNOWN;  | 
265  |  |  | 
266  |  |     //TODO: ULOC_FULL_NAME is out of date and too small..  | 
267  | 0  |     char canonicalName[256];  | 
268  |  |  | 
269  |  |     // Canonicalize, so that an old-style variant will be transformed to keywords.  | 
270  |  |     // e.g ja_JP_TRADITIONAL -> ja_JP@calendar=japanese  | 
271  |  |     // NOTE: Since ICU-20187, ja_JP_TRADITIONAL no longer canonicalizes, and  | 
272  |  |     // the Gregorian calendar is returned instead.  | 
273  | 0  |     int32_t canonicalLen = uloc_canonicalize(locid, canonicalName, sizeof(canonicalName) - 1, &status);  | 
274  | 0  |     if (U_FAILURE(status)) { | 
275  | 0  |         return CALTYPE_GREGORIAN;  | 
276  | 0  |     }  | 
277  | 0  |     canonicalName[canonicalLen] = 0;    // terminate  | 
278  |  | 
  | 
279  | 0  |     char calTypeBuf[32];  | 
280  | 0  |     int32_t calTypeBufLen;  | 
281  |  | 
  | 
282  | 0  |     calTypeBufLen = uloc_getKeywordValue(canonicalName, "calendar", calTypeBuf, sizeof(calTypeBuf) - 1, &status);  | 
283  | 0  |     if (U_SUCCESS(status)) { | 
284  | 0  |         calTypeBuf[calTypeBufLen] = 0;  | 
285  | 0  |         calType = getCalendarType(calTypeBuf);  | 
286  | 0  |         if (calType != CALTYPE_UNKNOWN) { | 
287  | 0  |             return calType;  | 
288  | 0  |         }  | 
289  | 0  |     }  | 
290  | 0  |     status = U_ZERO_ERROR;  | 
291  |  |  | 
292  |  |     // when calendar keyword is not available or not supported, read supplementalData  | 
293  |  |     // to get the default calendar type for the locale's region  | 
294  | 0  |     char region[ULOC_COUNTRY_CAPACITY];  | 
295  | 0  |     (void)ulocimp_getRegionForSupplementalData(canonicalName, TRUE, region, sizeof(region), &status);  | 
296  | 0  |     if (U_FAILURE(status)) { | 
297  | 0  |         return CALTYPE_GREGORIAN;  | 
298  | 0  |     }  | 
299  |  |  | 
300  |  |     // Read preferred calendar values from supplementalData calendarPreference  | 
301  | 0  |     UResourceBundle *rb = ures_openDirect(NULL, "supplementalData", &status);  | 
302  | 0  |     ures_getByKey(rb, "calendarPreferenceData", rb, &status);  | 
303  | 0  |     UResourceBundle *order = ures_getByKey(rb, region, NULL, &status);  | 
304  | 0  |     if (status == U_MISSING_RESOURCE_ERROR && rb != NULL) { | 
305  | 0  |         status = U_ZERO_ERROR;  | 
306  | 0  |         order = ures_getByKey(rb, "001", NULL, &status);  | 
307  | 0  |     }  | 
308  |  | 
  | 
309  | 0  |     calTypeBuf[0] = 0;  | 
310  | 0  |     if (U_SUCCESS(status) && order != NULL) { | 
311  |  |         // the first calendar type is the default for the region  | 
312  | 0  |         int32_t len = 0;  | 
313  | 0  |         const UChar *uCalType = ures_getStringByIndex(order, 0, &len, &status);  | 
314  | 0  |         if (len < (int32_t)sizeof(calTypeBuf)) { | 
315  | 0  |             u_UCharsToChars(uCalType, calTypeBuf, len);  | 
316  | 0  |             *(calTypeBuf + len) = 0; // terminate;  | 
317  | 0  |             calType = getCalendarType(calTypeBuf);  | 
318  | 0  |         }  | 
319  | 0  |     }  | 
320  |  | 
  | 
321  | 0  |     ures_close(order);  | 
322  | 0  |     ures_close(rb);  | 
323  |  | 
  | 
324  | 0  |     if (calType == CALTYPE_UNKNOWN) { | 
325  |  |         // final fallback  | 
326  | 0  |         calType = CALTYPE_GREGORIAN;  | 
327  | 0  |     }  | 
328  | 0  |     return calType;  | 
329  | 0  | }  | 
330  |  |  | 
331  | 0  | static Calendar *createStandardCalendar(ECalType calType, const Locale &loc, UErrorCode& status) { | 
332  | 0  |     if (U_FAILURE(status)) { | 
333  | 0  |         return nullptr;  | 
334  | 0  |     }  | 
335  | 0  |     LocalPointer<Calendar> cal;  | 
336  |  | 
  | 
337  | 0  |     switch (calType) { | 
338  | 0  |         case CALTYPE_GREGORIAN:  | 
339  | 0  |             cal.adoptInsteadAndCheckErrorCode(new GregorianCalendar(loc, status), status);  | 
340  | 0  |             break;  | 
341  | 0  |         case CALTYPE_JAPANESE:  | 
342  | 0  |             cal.adoptInsteadAndCheckErrorCode(new JapaneseCalendar(loc, status), status);  | 
343  | 0  |             break;  | 
344  | 0  |         case CALTYPE_BUDDHIST:  | 
345  | 0  |             cal.adoptInsteadAndCheckErrorCode(new BuddhistCalendar(loc, status), status);  | 
346  | 0  |             break;  | 
347  | 0  |         case CALTYPE_ROC:  | 
348  | 0  |             cal.adoptInsteadAndCheckErrorCode(new TaiwanCalendar(loc, status), status);  | 
349  | 0  |             break;  | 
350  | 0  |         case CALTYPE_PERSIAN:  | 
351  | 0  |             cal.adoptInsteadAndCheckErrorCode(new PersianCalendar(loc, status), status);  | 
352  | 0  |             break;  | 
353  | 0  |         case CALTYPE_ISLAMIC_TBLA:  | 
354  | 0  |             cal.adoptInsteadAndCheckErrorCode(new IslamicCalendar(loc, status, IslamicCalendar::TBLA), status);  | 
355  | 0  |             break;  | 
356  | 0  |         case CALTYPE_ISLAMIC_CIVIL:  | 
357  | 0  |             cal.adoptInsteadAndCheckErrorCode(new IslamicCalendar(loc, status, IslamicCalendar::CIVIL), status);  | 
358  | 0  |             break;  | 
359  | 0  |         case CALTYPE_ISLAMIC_RGSA:  | 
360  |  |             // default any region specific not handled individually to islamic  | 
361  | 0  |         case CALTYPE_ISLAMIC:  | 
362  | 0  |             cal.adoptInsteadAndCheckErrorCode(new IslamicCalendar(loc, status, IslamicCalendar::ASTRONOMICAL), status);  | 
363  | 0  |             break;  | 
364  | 0  |         case CALTYPE_ISLAMIC_UMALQURA:  | 
365  | 0  |             cal.adoptInsteadAndCheckErrorCode(new IslamicCalendar(loc, status, IslamicCalendar::UMALQURA), status);  | 
366  | 0  |             break;  | 
367  | 0  |         case CALTYPE_HEBREW:  | 
368  | 0  |             cal.adoptInsteadAndCheckErrorCode(new HebrewCalendar(loc, status), status);  | 
369  | 0  |             break;  | 
370  | 0  |         case CALTYPE_CHINESE:  | 
371  | 0  |             cal.adoptInsteadAndCheckErrorCode(new ChineseCalendar(loc, status), status);  | 
372  | 0  |             break;  | 
373  | 0  |         case CALTYPE_INDIAN:  | 
374  | 0  |             cal.adoptInsteadAndCheckErrorCode(new IndianCalendar(loc, status), status);  | 
375  | 0  |             break;  | 
376  | 0  |         case CALTYPE_COPTIC:  | 
377  | 0  |             cal.adoptInsteadAndCheckErrorCode(new CopticCalendar(loc, status), status);  | 
378  | 0  |             break;  | 
379  | 0  |         case CALTYPE_ETHIOPIC:  | 
380  | 0  |             cal.adoptInsteadAndCheckErrorCode(new EthiopicCalendar(loc, status, EthiopicCalendar::AMETE_MIHRET_ERA), status);  | 
381  | 0  |             break;  | 
382  | 0  |         case CALTYPE_ETHIOPIC_AMETE_ALEM:  | 
383  | 0  |             cal.adoptInsteadAndCheckErrorCode(new EthiopicCalendar(loc, status, EthiopicCalendar::AMETE_ALEM_ERA), status);  | 
384  | 0  |             break;  | 
385  | 0  |         case CALTYPE_ISO8601:  | 
386  | 0  |             cal.adoptInsteadAndCheckErrorCode(new GregorianCalendar(loc, status), status);  | 
387  | 0  |             if (cal.isValid()) { | 
388  | 0  |                 cal->setFirstDayOfWeek(UCAL_MONDAY);  | 
389  | 0  |                 cal->setMinimalDaysInFirstWeek(4);  | 
390  | 0  |             }  | 
391  | 0  |             break;  | 
392  | 0  |         case CALTYPE_DANGI:  | 
393  | 0  |             cal.adoptInsteadAndCheckErrorCode(new DangiCalendar(loc, status), status);  | 
394  | 0  |             break;  | 
395  | 0  |         default:  | 
396  | 0  |             status = U_UNSUPPORTED_ERROR;  | 
397  | 0  |     }  | 
398  | 0  |     return cal.orphan();  | 
399  | 0  | }  | 
400  |  |  | 
401  |  |  | 
402  |  | #if !UCONFIG_NO_SERVICE  | 
403  |  |  | 
404  |  | // -------------------------------------  | 
405  |  |  | 
406  |  | /**  | 
407  |  | * a Calendar Factory which creates the "basic" calendar types, that is, those  | 
408  |  | * shipped with ICU.  | 
409  |  | */  | 
410  |  | class BasicCalendarFactory : public LocaleKeyFactory { | 
411  |  | public:  | 
412  |  |     /**  | 
413  |  |     * @param calendarType static const string (caller owns storage - will be aliased) to calendar type  | 
414  |  |     */  | 
415  |  |     BasicCalendarFactory()  | 
416  | 0  |         : LocaleKeyFactory(LocaleKeyFactory::INVISIBLE) { } | 
417  |  |  | 
418  |  |     virtual ~BasicCalendarFactory();  | 
419  |  |  | 
420  |  | protected:  | 
421  |  |     //virtual UBool isSupportedID( const UnicodeString& id, UErrorCode& status) const { | 
422  |  |     //  if(U_FAILURE(status)) { | 
423  |  |     //    return FALSE;  | 
424  |  |     //  }  | 
425  |  |     //  char keyword[ULOC_FULLNAME_CAPACITY];  | 
426  |  |     //  getCalendarKeyword(id, keyword, (int32_t)sizeof(keyword));  | 
427  |  |     //  return isStandardSupportedKeyword(keyword, status);  | 
428  |  |     //}  | 
429  |  |  | 
430  |  |     virtual void updateVisibleIDs(Hashtable& result, UErrorCode& status) const  | 
431  | 0  |     { | 
432  | 0  |         if (U_SUCCESS(status)) { | 
433  | 0  |             for(int32_t i=0;gCalTypes[i] != NULL;i++) { | 
434  | 0  |                 UnicodeString id((UChar)0x40); /* '@' a variant character */  | 
435  | 0  |                 id.append(UNICODE_STRING_SIMPLE("calendar=")); | 
436  | 0  |                 id.append(UnicodeString(gCalTypes[i], -1, US_INV));  | 
437  | 0  |                 result.put(id, (void*)this, status);  | 
438  | 0  |             }  | 
439  | 0  |         }  | 
440  | 0  |     }  | 
441  |  |  | 
442  | 0  |     virtual UObject* create(const ICUServiceKey& key, const ICUService* /*service*/, UErrorCode& status) const { | 
443  |  | #ifdef U_DEBUG_CALSVC  | 
444  |  |         if(dynamic_cast<const LocaleKey*>(&key) == NULL) { | 
445  |  |             fprintf(stderr, "::create - not a LocaleKey!\n");  | 
446  |  |         }  | 
447  |  | #endif  | 
448  | 0  |         const LocaleKey& lkey = (LocaleKey&)key;  | 
449  | 0  |         Locale curLoc;  // current locale  | 
450  | 0  |         Locale canLoc;  // Canonical locale  | 
451  |  | 
  | 
452  | 0  |         lkey.currentLocale(curLoc);  | 
453  | 0  |         lkey.canonicalLocale(canLoc);  | 
454  |  | 
  | 
455  | 0  |         char keyword[ULOC_FULLNAME_CAPACITY];  | 
456  | 0  |         UnicodeString str;  | 
457  |  | 
  | 
458  | 0  |         key.currentID(str);  | 
459  | 0  |         getCalendarKeyword(str, keyword, (int32_t) sizeof(keyword));  | 
460  |  | 
  | 
461  |  | #ifdef U_DEBUG_CALSVC  | 
462  |  |         fprintf(stderr, "BasicCalendarFactory::create() - cur %s, can %s\n", (const char*)curLoc.getName(), (const char*)canLoc.getName());  | 
463  |  | #endif  | 
464  |  | 
  | 
465  | 0  |         if(!isStandardSupportedKeyword(keyword,status)) {  // Do we handle this type? | 
466  |  | #ifdef U_DEBUG_CALSVC  | 
467  |  |  | 
468  |  |             fprintf(stderr, "BasicCalendarFactory - not handling %s.[%s]\n", (const char*) curLoc.getName(), tmp );  | 
469  |  | #endif  | 
470  | 0  |             return NULL;  | 
471  | 0  |         }  | 
472  |  |  | 
473  | 0  |         return createStandardCalendar(getCalendarType(keyword), canLoc, status);  | 
474  | 0  |     }  | 
475  |  | };  | 
476  |  |  | 
477  | 0  | BasicCalendarFactory::~BasicCalendarFactory() {} | 
478  |  |  | 
479  |  | /**  | 
480  |  | * A factory which looks up the DefaultCalendar resource to determine which class of calendar to use  | 
481  |  | */  | 
482  |  |  | 
483  |  | class DefaultCalendarFactory : public ICUResourceBundleFactory { | 
484  |  | public:  | 
485  | 0  |     DefaultCalendarFactory() : ICUResourceBundleFactory() { } | 
486  |  |     virtual ~DefaultCalendarFactory();  | 
487  |  | protected:  | 
488  | 0  |     virtual UObject* create(const ICUServiceKey& key, const ICUService* /*service*/, UErrorCode& status) const  { | 
489  |  | 
  | 
490  | 0  |         LocaleKey &lkey = (LocaleKey&)key;  | 
491  | 0  |         Locale loc;  | 
492  | 0  |         lkey.currentLocale(loc);  | 
493  |  | 
  | 
494  | 0  |         UnicodeString *ret = new UnicodeString();  | 
495  | 0  |         if (ret == NULL) { | 
496  | 0  |             status = U_MEMORY_ALLOCATION_ERROR;  | 
497  | 0  |         } else { | 
498  | 0  |             ret->append((UChar)0x40); // '@' is a variant character  | 
499  | 0  |             ret->append(UNICODE_STRING("calendar=", 9)); | 
500  | 0  |             ret->append(UnicodeString(gCalTypes[getCalendarTypeForLocale(loc.getName())], -1, US_INV));  | 
501  | 0  |         }  | 
502  | 0  |         return ret;  | 
503  | 0  |     }  | 
504  |  | };  | 
505  |  |  | 
506  | 0  | DefaultCalendarFactory::~DefaultCalendarFactory() {} | 
507  |  |  | 
508  |  | // -------------------------------------  | 
509  |  | class CalendarService : public ICULocaleService { | 
510  |  | public:  | 
511  |  |     CalendarService()  | 
512  | 0  |         : ICULocaleService(UNICODE_STRING_SIMPLE("Calendar")) | 
513  | 0  |     { | 
514  | 0  |         UErrorCode status = U_ZERO_ERROR;  | 
515  | 0  |         registerFactory(new DefaultCalendarFactory(), status);  | 
516  | 0  |     }  | 
517  |  |  | 
518  |  |     virtual ~CalendarService();  | 
519  |  |  | 
520  | 0  |     virtual UObject* cloneInstance(UObject* instance) const { | 
521  | 0  |         UnicodeString *s = dynamic_cast<UnicodeString *>(instance);  | 
522  | 0  |         if(s != NULL) { | 
523  | 0  |             return s->clone();  | 
524  | 0  |         } else { | 
525  |  | #ifdef U_DEBUG_CALSVC_F  | 
526  |  |             UErrorCode status2 = U_ZERO_ERROR;  | 
527  |  |             fprintf(stderr, "Cloning a %s calendar with tz=%ld\n", ((Calendar*)instance)->getType(), ((Calendar*)instance)->get(UCAL_ZONE_OFFSET, status2));  | 
528  |  | #endif  | 
529  | 0  |             return ((Calendar*)instance)->clone();  | 
530  | 0  |         }  | 
531  | 0  |     }  | 
532  |  |  | 
533  | 0  |     virtual UObject* handleDefault(const ICUServiceKey& key, UnicodeString* /*actualID*/, UErrorCode& status) const { | 
534  | 0  |         LocaleKey& lkey = (LocaleKey&)key;  | 
535  |  |         //int32_t kind = lkey.kind();  | 
536  |  | 
  | 
537  | 0  |         Locale loc;  | 
538  | 0  |         lkey.canonicalLocale(loc);  | 
539  |  | 
  | 
540  |  | #ifdef U_DEBUG_CALSVC  | 
541  |  |         Locale loc2;  | 
542  |  |         lkey.currentLocale(loc2);  | 
543  |  |         fprintf(stderr, "CalSvc:handleDefault for currentLoc %s, canloc %s\n", (const char*)loc.getName(),  (const char*)loc2.getName());  | 
544  |  | #endif  | 
545  | 0  |         Calendar *nc =  new GregorianCalendar(loc, status);  | 
546  | 0  |         if (nc == nullptr) { | 
547  | 0  |             status = U_MEMORY_ALLOCATION_ERROR;  | 
548  | 0  |             return nc;  | 
549  | 0  |         }  | 
550  |  |  | 
551  |  | #ifdef U_DEBUG_CALSVC  | 
552  |  |         UErrorCode status2 = U_ZERO_ERROR;  | 
553  |  |         fprintf(stderr, "New default calendar has tz=%d\n", ((Calendar*)nc)->get(UCAL_ZONE_OFFSET, status2));  | 
554  |  | #endif  | 
555  | 0  |         return nc;  | 
556  | 0  |     }  | 
557  |  |  | 
558  | 0  |     virtual UBool isDefault() const { | 
559  | 0  |         return countFactories() == 1;  | 
560  | 0  |     }  | 
561  |  | };  | 
562  |  |  | 
563  | 0  | CalendarService::~CalendarService() {} | 
564  |  |  | 
565  |  | // -------------------------------------  | 
566  |  |  | 
567  |  | static inline UBool  | 
568  | 0  | isCalendarServiceUsed() { | 
569  | 0  |     return !gServiceInitOnce.isReset();  | 
570  | 0  | }  | 
571  |  |  | 
572  |  | // -------------------------------------  | 
573  |  |  | 
574  |  | static void U_CALLCONV  | 
575  |  | initCalendarService(UErrorCode &status)  | 
576  | 0  | { | 
577  |  | #ifdef U_DEBUG_CALSVC  | 
578  |  |         fprintf(stderr, "Spinning up Calendar Service\n");  | 
579  |  | #endif  | 
580  | 0  |     ucln_i18n_registerCleanup(UCLN_I18N_CALENDAR, calendar_cleanup);  | 
581  | 0  |     gService = new CalendarService();  | 
582  | 0  |     if (gService == NULL) { | 
583  | 0  |             status = U_MEMORY_ALLOCATION_ERROR;  | 
584  | 0  |         return;  | 
585  | 0  |         }  | 
586  |  | #ifdef U_DEBUG_CALSVC  | 
587  |  |         fprintf(stderr, "Registering classes..\n");  | 
588  |  | #endif  | 
589  |  |  | 
590  |  |         // Register all basic instances.  | 
591  | 0  |     gService->registerFactory(new BasicCalendarFactory(),status);  | 
592  |  | 
  | 
593  |  | #ifdef U_DEBUG_CALSVC  | 
594  |  |         fprintf(stderr, "Done..\n");  | 
595  |  | #endif  | 
596  |  | 
  | 
597  | 0  |         if(U_FAILURE(status)) { | 
598  |  | #ifdef U_DEBUG_CALSVC  | 
599  |  |             fprintf(stderr, "err (%s) registering classes, deleting service.....\n", u_errorName(status));  | 
600  |  | #endif  | 
601  | 0  |         delete gService;  | 
602  | 0  |         gService = NULL;  | 
603  | 0  |     }  | 
604  | 0  |         }  | 
605  |  |  | 
606  |  | static ICULocaleService*  | 
607  |  | getCalendarService(UErrorCode &status)  | 
608  | 0  | { | 
609  | 0  |     umtx_initOnce(gServiceInitOnce, &initCalendarService, status);  | 
610  | 0  |     return gService;  | 
611  | 0  | }  | 
612  |  |  | 
613  |  | URegistryKey Calendar::registerFactory(ICUServiceFactory* toAdopt, UErrorCode& status)  | 
614  | 0  | { | 
615  | 0  |     return getCalendarService(status)->registerFactory(toAdopt, status);  | 
616  | 0  | }  | 
617  |  |  | 
618  | 0  | UBool Calendar::unregister(URegistryKey key, UErrorCode& status) { | 
619  | 0  |     return getCalendarService(status)->unregister(key, status);  | 
620  | 0  | }  | 
621  |  | #endif /* UCONFIG_NO_SERVICE */  | 
622  |  |  | 
623  |  | // -------------------------------------  | 
624  |  |  | 
625  |  | static const int32_t kCalendarLimits[UCAL_FIELD_COUNT][4] = { | 
626  |  |     //    Minimum  Greatest min      Least max   Greatest max  | 
627  |  |     {/*N/A*/-1,       /*N/A*/-1,     /*N/A*/-1,       /*N/A*/-1}, // ERA | 
628  |  |     {/*N/A*/-1,       /*N/A*/-1,     /*N/A*/-1,       /*N/A*/-1}, // YEAR | 
629  |  |     {/*N/A*/-1,       /*N/A*/-1,     /*N/A*/-1,       /*N/A*/-1}, // MONTH | 
630  |  |     {/*N/A*/-1,       /*N/A*/-1,     /*N/A*/-1,       /*N/A*/-1}, // WEEK_OF_YEAR | 
631  |  |     {/*N/A*/-1,       /*N/A*/-1,     /*N/A*/-1,       /*N/A*/-1}, // WEEK_OF_MONTH | 
632  |  |     {/*N/A*/-1,       /*N/A*/-1,     /*N/A*/-1,       /*N/A*/-1}, // DAY_OF_MONTH | 
633  |  |     {/*N/A*/-1,       /*N/A*/-1,     /*N/A*/-1,       /*N/A*/-1}, // DAY_OF_YEAR | 
634  |  |     {           1,            1,             7,             7  }, // DAY_OF_WEEK | 
635  |  |     {/*N/A*/-1,       /*N/A*/-1,     /*N/A*/-1,       /*N/A*/-1}, // DAY_OF_WEEK_IN_MONTH | 
636  |  |     {           0,            0,             1,             1  }, // AM_PM | 
637  |  |     {           0,            0,            11,            11  }, // HOUR | 
638  |  |     {           0,            0,            23,            23  }, // HOUR_OF_DAY | 
639  |  |     {           0,            0,            59,            59  }, // MINUTE | 
640  |  |     {           0,            0,            59,            59  }, // SECOND | 
641  |  |     {           0,            0,           999,           999  }, // MILLISECOND | 
642  |  |     {-12*kOneHour, -12*kOneHour,   12*kOneHour,   15*kOneHour  }, // ZONE_OFFSET | 
643  |  |     {           0,            0,    1*kOneHour,    1*kOneHour  }, // DST_OFFSET | 
644  |  |     {/*N/A*/-1,       /*N/A*/-1,     /*N/A*/-1,       /*N/A*/-1}, // YEAR_WOY | 
645  |  |     {           1,            1,             7,             7  }, // DOW_LOCAL | 
646  |  |     {/*N/A*/-1,       /*N/A*/-1,     /*N/A*/-1,       /*N/A*/-1}, // EXTENDED_YEAR | 
647  |  |     { -0x7F000000,  -0x7F000000,    0x7F000000,    0x7F000000  }, // JULIAN_DAY | 
648  |  |     {           0,            0, 24*kOneHour-1, 24*kOneHour-1  }, // MILLISECONDS_IN_DAY | 
649  |  |     {           0,            0,             1,             1  }, // IS_LEAP_MONTH | 
650  |  | };  | 
651  |  |  | 
652  |  | // Resource bundle tags read by this class  | 
653  |  | static const char gCalendar[] = "calendar";  | 
654  |  | static const char gMonthNames[] = "monthNames";  | 
655  |  | static const char gGregorian[] = "gregorian";  | 
656  |  |  | 
657  |  | // Data flow in Calendar  | 
658  |  | // ---------------------  | 
659  |  |  | 
660  |  | // The current time is represented in two ways by Calendar: as UTC  | 
661  |  | // milliseconds from the epoch start (1 January 1970 0:00 UTC), and as local  | 
662  |  | // fields such as MONTH, HOUR, AM_PM, etc.  It is possible to compute the  | 
663  |  | // millis from the fields, and vice versa.  The data needed to do this  | 
664  |  | // conversion is encapsulated by a TimeZone object owned by the Calendar.  | 
665  |  | // The data provided by the TimeZone object may also be overridden if the  | 
666  |  | // user sets the ZONE_OFFSET and/or DST_OFFSET fields directly. The class  | 
667  |  | // keeps track of what information was most recently set by the caller, and  | 
668  |  | // uses that to compute any other information as needed.  | 
669  |  |  | 
670  |  | // If the user sets the fields using set(), the data flow is as follows.  | 
671  |  | // This is implemented by the Calendar subclass's computeTime() method.  | 
672  |  | // During this process, certain fields may be ignored.  The disambiguation  | 
673  |  | // algorithm for resolving which fields to pay attention to is described  | 
674  |  | // above.  | 
675  |  |  | 
676  |  | //   local fields (YEAR, MONTH, DATE, HOUR, MINUTE, etc.)  | 
677  |  | //           |  | 
678  |  | //           | Using Calendar-specific algorithm  | 
679  |  | //           V  | 
680  |  | //   local standard millis  | 
681  |  | //           |  | 
682  |  | //           | Using TimeZone or user-set ZONE_OFFSET / DST_OFFSET  | 
683  |  | //           V  | 
684  |  | //   UTC millis (in time data member)  | 
685  |  |  | 
686  |  | // If the user sets the UTC millis using setTime(), the data flow is as  | 
687  |  | // follows.  This is implemented by the Calendar subclass's computeFields()  | 
688  |  | // method.  | 
689  |  |  | 
690  |  | //   UTC millis (in time data member)  | 
691  |  | //           |  | 
692  |  | //           | Using TimeZone getOffset()  | 
693  |  | //           V  | 
694  |  | //   local standard millis  | 
695  |  | //           |  | 
696  |  | //           | Using Calendar-specific algorithm  | 
697  |  | //           V  | 
698  |  | //   local fields (YEAR, MONTH, DATE, HOUR, MINUTE, etc.)  | 
699  |  |  | 
700  |  | // In general, a round trip from fields, through local and UTC millis, and  | 
701  |  | // back out to fields is made when necessary.  This is implemented by the  | 
702  |  | // complete() method.  Resolving a partial set of fields into a UTC millis  | 
703  |  | // value allows all remaining fields to be generated from that value.  If  | 
704  |  | // the Calendar is lenient, the fields are also renormalized to standard  | 
705  |  | // ranges when they are regenerated.  | 
706  |  |  | 
707  |  | // -------------------------------------  | 
708  |  |  | 
709  |  | Calendar::Calendar(UErrorCode& success)  | 
710  | 0  | :   UObject(),  | 
711  | 0  | fIsTimeSet(FALSE),  | 
712  | 0  | fAreFieldsSet(FALSE),  | 
713  | 0  | fAreAllFieldsSet(FALSE),  | 
714  | 0  | fAreFieldsVirtuallySet(FALSE),  | 
715  | 0  | fNextStamp((int32_t)kMinimumUserStamp),  | 
716  | 0  | fTime(0),  | 
717  | 0  | fLenient(TRUE),  | 
718  |  | fZone(NULL),  | 
719  | 0  | fRepeatedWallTime(UCAL_WALLTIME_LAST),  | 
720  | 0  | fSkippedWallTime(UCAL_WALLTIME_LAST)  | 
721  | 0  | { | 
722  | 0  |     validLocale[0] = 0;  | 
723  | 0  |     actualLocale[0] = 0;  | 
724  | 0  |     clear();  | 
725  | 0  |     if (U_FAILURE(success)) { | 
726  | 0  |         return;  | 
727  | 0  |     }  | 
728  | 0  |     fZone = TimeZone::createDefault();  | 
729  | 0  |     if (fZone == NULL) { | 
730  | 0  |         success = U_MEMORY_ALLOCATION_ERROR;  | 
731  | 0  |     }  | 
732  | 0  |     setWeekData(Locale::getDefault(), NULL, success);  | 
733  | 0  | }  | 
734  |  |  | 
735  |  | // -------------------------------------  | 
736  |  |  | 
737  |  | Calendar::Calendar(TimeZone* zone, const Locale& aLocale, UErrorCode& success)  | 
738  | 0  | :   UObject(),  | 
739  | 0  | fIsTimeSet(FALSE),  | 
740  | 0  | fAreFieldsSet(FALSE),  | 
741  | 0  | fAreAllFieldsSet(FALSE),  | 
742  | 0  | fAreFieldsVirtuallySet(FALSE),  | 
743  | 0  | fNextStamp((int32_t)kMinimumUserStamp),  | 
744  | 0  | fTime(0),  | 
745  | 0  | fLenient(TRUE),  | 
746  |  | fZone(NULL),  | 
747  | 0  | fRepeatedWallTime(UCAL_WALLTIME_LAST),  | 
748  | 0  | fSkippedWallTime(UCAL_WALLTIME_LAST)  | 
749  | 0  | { | 
750  | 0  |     validLocale[0] = 0;  | 
751  | 0  |     actualLocale[0] = 0;  | 
752  | 0  |     if (U_FAILURE(success)) { | 
753  | 0  |         delete zone;  | 
754  | 0  |         return;  | 
755  | 0  |     }  | 
756  | 0  |     if(zone == 0) { | 
757  |  | #if defined (U_DEBUG_CAL)  | 
758  |  |         fprintf(stderr, "%s:%d: ILLEGAL ARG because timezone cannot be 0\n",  | 
759  |  |             __FILE__, __LINE__);  | 
760  |  | #endif  | 
761  | 0  |         success = U_ILLEGAL_ARGUMENT_ERROR;  | 
762  | 0  |         return;  | 
763  | 0  |     }  | 
764  |  |  | 
765  | 0  |     clear();  | 
766  | 0  |     fZone = zone;  | 
767  | 0  |     setWeekData(aLocale, NULL, success);  | 
768  | 0  | }  | 
769  |  |  | 
770  |  | // -------------------------------------  | 
771  |  |  | 
772  |  | Calendar::Calendar(const TimeZone& zone, const Locale& aLocale, UErrorCode& success)  | 
773  | 0  | :   UObject(),  | 
774  | 0  | fIsTimeSet(FALSE),  | 
775  | 0  | fAreFieldsSet(FALSE),  | 
776  | 0  | fAreAllFieldsSet(FALSE),  | 
777  | 0  | fAreFieldsVirtuallySet(FALSE),  | 
778  | 0  | fNextStamp((int32_t)kMinimumUserStamp),  | 
779  | 0  | fTime(0),  | 
780  | 0  | fLenient(TRUE),  | 
781  |  | fZone(NULL),  | 
782  | 0  | fRepeatedWallTime(UCAL_WALLTIME_LAST),  | 
783  | 0  | fSkippedWallTime(UCAL_WALLTIME_LAST)  | 
784  | 0  | { | 
785  | 0  |     validLocale[0] = 0;  | 
786  | 0  |     actualLocale[0] = 0;  | 
787  | 0  |     if (U_FAILURE(success)) { | 
788  | 0  |         return;  | 
789  | 0  |     }  | 
790  | 0  |     clear();  | 
791  | 0  |     fZone = zone.clone();  | 
792  | 0  |     if (fZone == NULL) { | 
793  | 0  |         success = U_MEMORY_ALLOCATION_ERROR;  | 
794  | 0  |     }  | 
795  | 0  |     setWeekData(aLocale, NULL, success);  | 
796  | 0  | }  | 
797  |  |  | 
798  |  | // -------------------------------------  | 
799  |  |  | 
800  |  | Calendar::~Calendar()  | 
801  | 0  | { | 
802  | 0  |     delete fZone;  | 
803  | 0  | }  | 
804  |  |  | 
805  |  | // -------------------------------------  | 
806  |  |  | 
807  |  | Calendar::Calendar(const Calendar &source)  | 
808  | 0  | :   UObject(source)  | 
809  | 0  | { | 
810  | 0  |     fZone = NULL;  | 
811  | 0  |     *this = source;  | 
812  | 0  | }  | 
813  |  |  | 
814  |  | // -------------------------------------  | 
815  |  |  | 
816  |  | Calendar &  | 
817  |  | Calendar::operator=(const Calendar &right)  | 
818  | 0  | { | 
819  | 0  |     if (this != &right) { | 
820  | 0  |         uprv_arrayCopy(right.fFields, fFields, UCAL_FIELD_COUNT);  | 
821  | 0  |         uprv_arrayCopy(right.fIsSet, fIsSet, UCAL_FIELD_COUNT);  | 
822  | 0  |         uprv_arrayCopy(right.fStamp, fStamp, UCAL_FIELD_COUNT);  | 
823  | 0  |         fTime                    = right.fTime;  | 
824  | 0  |         fIsTimeSet               = right.fIsTimeSet;  | 
825  | 0  |         fAreAllFieldsSet         = right.fAreAllFieldsSet;  | 
826  | 0  |         fAreFieldsSet            = right.fAreFieldsSet;  | 
827  | 0  |         fAreFieldsVirtuallySet   = right.fAreFieldsVirtuallySet;  | 
828  | 0  |         fLenient                 = right.fLenient;  | 
829  | 0  |         fRepeatedWallTime        = right.fRepeatedWallTime;  | 
830  | 0  |         fSkippedWallTime         = right.fSkippedWallTime;  | 
831  | 0  |         delete fZone;  | 
832  | 0  |         fZone = NULL;  | 
833  | 0  |         if (right.fZone != NULL) { | 
834  | 0  |             fZone                = right.fZone->clone();  | 
835  | 0  |         }  | 
836  | 0  |         fFirstDayOfWeek          = right.fFirstDayOfWeek;  | 
837  | 0  |         fMinimalDaysInFirstWeek  = right.fMinimalDaysInFirstWeek;  | 
838  | 0  |         fWeekendOnset            = right.fWeekendOnset;  | 
839  | 0  |         fWeekendOnsetMillis      = right.fWeekendOnsetMillis;  | 
840  | 0  |         fWeekendCease            = right.fWeekendCease;  | 
841  | 0  |         fWeekendCeaseMillis      = right.fWeekendCeaseMillis;  | 
842  | 0  |         fNextStamp               = right.fNextStamp;  | 
843  | 0  |         uprv_strncpy(validLocale, right.validLocale, sizeof(validLocale));  | 
844  | 0  |         uprv_strncpy(actualLocale, right.actualLocale, sizeof(actualLocale));  | 
845  | 0  |         validLocale[sizeof(validLocale)-1] = 0;  | 
846  | 0  |         actualLocale[sizeof(validLocale)-1] = 0;  | 
847  | 0  |     }  | 
848  |  | 
  | 
849  | 0  |     return *this;  | 
850  | 0  | }  | 
851  |  |  | 
852  |  | // -------------------------------------  | 
853  |  |  | 
854  |  | Calendar* U_EXPORT2  | 
855  |  | Calendar::createInstance(UErrorCode& success)  | 
856  | 0  | { | 
857  | 0  |     return createInstance(TimeZone::createDefault(), Locale::getDefault(), success);  | 
858  | 0  | }  | 
859  |  |  | 
860  |  | // -------------------------------------  | 
861  |  |  | 
862  |  | Calendar* U_EXPORT2  | 
863  |  | Calendar::createInstance(const TimeZone& zone, UErrorCode& success)  | 
864  | 0  | { | 
865  | 0  |     return createInstance(zone, Locale::getDefault(), success);  | 
866  | 0  | }  | 
867  |  |  | 
868  |  | // -------------------------------------  | 
869  |  |  | 
870  |  | Calendar* U_EXPORT2  | 
871  |  | Calendar::createInstance(const Locale& aLocale, UErrorCode& success)  | 
872  | 0  | { | 
873  | 0  |     return createInstance(TimeZone::forLocaleOrDefault(aLocale), aLocale, success);  | 
874  | 0  | }  | 
875  |  |  | 
876  |  | // ------------------------------------- Adopting  | 
877  |  |  | 
878  |  | // Note: this is the bottleneck that actually calls the service routines.  | 
879  |  |  | 
880  |  | Calendar * U_EXPORT2  | 
881  | 0  | Calendar::makeInstance(const Locale& aLocale, UErrorCode& success) { | 
882  | 0  |     if (U_FAILURE(success)) { | 
883  | 0  |         return NULL;  | 
884  | 0  |     }  | 
885  |  |  | 
886  | 0  |     Locale actualLoc;  | 
887  | 0  |     UObject* u = NULL;  | 
888  |  | 
  | 
889  | 0  | #if !UCONFIG_NO_SERVICE  | 
890  | 0  |     if (isCalendarServiceUsed()) { | 
891  | 0  |         u = getCalendarService(success)->get(aLocale, LocaleKey::KIND_ANY, &actualLoc, success);  | 
892  | 0  |     }  | 
893  | 0  |     else  | 
894  | 0  | #endif  | 
895  | 0  |     { | 
896  | 0  |         u = createStandardCalendar(getCalendarTypeForLocale(aLocale.getName()), aLocale, success);  | 
897  | 0  |     }  | 
898  | 0  |     Calendar* c = NULL;  | 
899  |  | 
  | 
900  | 0  |     if(U_FAILURE(success) || !u) { | 
901  | 0  |         if(U_SUCCESS(success)) { // Propagate some kind of err | 
902  | 0  |             success = U_INTERNAL_PROGRAM_ERROR;  | 
903  | 0  |         }  | 
904  | 0  |         return NULL;  | 
905  | 0  |     }  | 
906  |  |  | 
907  | 0  | #if !UCONFIG_NO_SERVICE  | 
908  | 0  |     const UnicodeString* str = dynamic_cast<const UnicodeString*>(u);  | 
909  | 0  |     if(str != NULL) { | 
910  |  |         // It's a unicode string telling us what type of calendar to load ("gregorian", etc) | 
911  |  |         // Create a Locale over this string  | 
912  | 0  |         Locale l(""); | 
913  | 0  |         LocaleUtility::initLocaleFromName(*str, l);  | 
914  |  | 
  | 
915  |  | #ifdef U_DEBUG_CALSVC  | 
916  |  |         fprintf(stderr, "Calendar::createInstance(%s), looking up [%s]\n", aLocale.getName(), l.getName());  | 
917  |  | #endif  | 
918  |  | 
  | 
919  | 0  |         Locale actualLoc2;  | 
920  | 0  |         delete u;  | 
921  | 0  |         u = NULL;  | 
922  |  |  | 
923  |  |         // Don't overwrite actualLoc, since the actual loc from this call  | 
924  |  |         // may be something like "@calendar=gregorian" -- TODO investigate  | 
925  |  |         // further...  | 
926  | 0  |         c = (Calendar*)getCalendarService(success)->get(l, LocaleKey::KIND_ANY, &actualLoc2, success);  | 
927  |  | 
  | 
928  | 0  |         if(U_FAILURE(success) || !c) { | 
929  | 0  |             if(U_SUCCESS(success)) { | 
930  | 0  |                 success = U_INTERNAL_PROGRAM_ERROR; // Propagate some err  | 
931  | 0  |             }  | 
932  | 0  |             return NULL;  | 
933  | 0  |         }  | 
934  |  |  | 
935  | 0  |         str = dynamic_cast<const UnicodeString*>(c);  | 
936  | 0  |         if(str != NULL) { | 
937  |  |             // recursed! Second lookup returned a UnicodeString.  | 
938  |  |             // Perhaps DefaultCalendar{} was set to another locale. | 
939  |  | #ifdef U_DEBUG_CALSVC  | 
940  |  |             char tmp[200];  | 
941  |  |             // Extract a char* out of it..  | 
942  |  |             int32_t len = str->length();  | 
943  |  |             int32_t actLen = sizeof(tmp)-1;  | 
944  |  |             if(len > actLen) { | 
945  |  |                 len = actLen;  | 
946  |  |             }  | 
947  |  |             str->extract(0,len,tmp);  | 
948  |  |             tmp[len]=0;  | 
949  |  |  | 
950  |  |             fprintf(stderr, "err - recursed, 2nd lookup was unistring %s\n", tmp);  | 
951  |  | #endif  | 
952  | 0  |             success = U_MISSING_RESOURCE_ERROR;  // requested a calendar type which could NOT be found.  | 
953  | 0  |             delete c;  | 
954  | 0  |             return NULL;  | 
955  | 0  |         }  | 
956  |  | #ifdef U_DEBUG_CALSVC  | 
957  |  |         fprintf(stderr, "%p: setting week count data to locale %s, actual locale %s\n", c, (const char*)aLocale.getName(), (const char *)actualLoc.getName());  | 
958  |  | #endif  | 
959  | 0  |         c->setWeekData(aLocale, c->getType(), success);  // set the correct locale (this was an indirected calendar)  | 
960  |  | 
  | 
961  | 0  |         char keyword[ULOC_FULLNAME_CAPACITY] = "";  | 
962  | 0  |         UErrorCode tmpStatus = U_ZERO_ERROR;  | 
963  | 0  |         l.getKeywordValue("calendar", keyword, ULOC_FULLNAME_CAPACITY, tmpStatus); | 
964  | 0  |         if (U_SUCCESS(tmpStatus) && uprv_strcmp(keyword, "iso8601") == 0) { | 
965  | 0  |             c->setFirstDayOfWeek(UCAL_MONDAY);  | 
966  | 0  |             c->setMinimalDaysInFirstWeek(4);  | 
967  | 0  |         }  | 
968  | 0  |     }  | 
969  | 0  |     else  | 
970  | 0  | #endif /* UCONFIG_NO_SERVICE */  | 
971  | 0  |     { | 
972  |  |         // a calendar was returned - we assume the factory did the right thing.  | 
973  | 0  |         c = (Calendar*)u;  | 
974  | 0  |     }  | 
975  |  |  | 
976  | 0  |     return c;  | 
977  | 0  | }  | 
978  |  |  | 
979  |  | Calendar* U_EXPORT2  | 
980  |  | Calendar::createInstance(TimeZone* zone, const Locale& aLocale, UErrorCode& success)  | 
981  | 0  | { | 
982  | 0  |     LocalPointer<TimeZone> zonePtr(zone);  | 
983  | 0  |     const SharedCalendar *shared = NULL;  | 
984  | 0  |     UnifiedCache::getByLocale(aLocale, shared, success);  | 
985  | 0  |     if (U_FAILURE(success)) { | 
986  | 0  |         return NULL;  | 
987  | 0  |     }  | 
988  | 0  |     Calendar *c = (*shared)->clone();  | 
989  | 0  |     shared->removeRef();  | 
990  | 0  |     if (c == NULL) { | 
991  | 0  |         success = U_MEMORY_ALLOCATION_ERROR;  | 
992  | 0  |         return NULL;  | 
993  | 0  |     }  | 
994  |  |  | 
995  |  |     // Now, reset calendar to default state:  | 
996  | 0  |     c->adoptTimeZone(zonePtr.orphan()); //  Set the correct time zone  | 
997  | 0  |     c->setTimeInMillis(getNow(), success); // let the new calendar have the current time.  | 
998  |  | 
  | 
999  | 0  |     return c;  | 
1000  | 0  | }  | 
1001  |  |  | 
1002  |  | // -------------------------------------  | 
1003  |  |  | 
1004  |  | Calendar* U_EXPORT2  | 
1005  |  | Calendar::createInstance(const TimeZone& zone, const Locale& aLocale, UErrorCode& success)  | 
1006  | 0  | { | 
1007  | 0  |     Calendar* c = createInstance(aLocale, success);  | 
1008  | 0  |     if(U_SUCCESS(success) && c) { | 
1009  | 0  |         c->setTimeZone(zone);  | 
1010  | 0  |     }  | 
1011  | 0  |     return c;  | 
1012  | 0  | }  | 
1013  |  |  | 
1014  |  | // -------------------------------------  | 
1015  |  |  | 
1016  |  | void U_EXPORT2  | 
1017  |  | Calendar::getCalendarTypeFromLocale(  | 
1018  |  |         const Locale &aLocale,  | 
1019  |  |         char *typeBuffer,  | 
1020  |  |         int32_t typeBufferSize,  | 
1021  | 0  |         UErrorCode &success) { | 
1022  | 0  |     const SharedCalendar *shared = NULL;  | 
1023  | 0  |     UnifiedCache::getByLocale(aLocale, shared, success);  | 
1024  | 0  |     if (U_FAILURE(success)) { | 
1025  | 0  |         return;  | 
1026  | 0  |     }  | 
1027  | 0  |     uprv_strncpy(typeBuffer, (*shared)->getType(), typeBufferSize);  | 
1028  | 0  |     shared->removeRef();  | 
1029  | 0  |     if (typeBuffer[typeBufferSize - 1]) { | 
1030  | 0  |         success = U_BUFFER_OVERFLOW_ERROR;  | 
1031  | 0  |     }  | 
1032  | 0  | }  | 
1033  |  |  | 
1034  |  | bool  | 
1035  |  | Calendar::operator==(const Calendar& that) const  | 
1036  | 0  | { | 
1037  | 0  |     UErrorCode status = U_ZERO_ERROR;  | 
1038  | 0  |     return isEquivalentTo(that) &&  | 
1039  | 0  |         getTimeInMillis(status) == that.getTimeInMillis(status) &&  | 
1040  | 0  |         U_SUCCESS(status);  | 
1041  | 0  | }  | 
1042  |  |  | 
1043  |  | UBool  | 
1044  |  | Calendar::isEquivalentTo(const Calendar& other) const  | 
1045  | 0  | { | 
1046  | 0  |     return typeid(*this) == typeid(other) &&  | 
1047  | 0  |         fLenient                == other.fLenient &&  | 
1048  | 0  |         fRepeatedWallTime       == other.fRepeatedWallTime &&  | 
1049  | 0  |         fSkippedWallTime        == other.fSkippedWallTime &&  | 
1050  | 0  |         fFirstDayOfWeek         == other.fFirstDayOfWeek &&  | 
1051  | 0  |         fMinimalDaysInFirstWeek == other.fMinimalDaysInFirstWeek &&  | 
1052  | 0  |         fWeekendOnset           == other.fWeekendOnset &&  | 
1053  | 0  |         fWeekendOnsetMillis     == other.fWeekendOnsetMillis &&  | 
1054  | 0  |         fWeekendCease           == other.fWeekendCease &&  | 
1055  | 0  |         fWeekendCeaseMillis     == other.fWeekendCeaseMillis &&  | 
1056  | 0  |         *fZone                  == *other.fZone;  | 
1057  | 0  | }  | 
1058  |  |  | 
1059  |  | // -------------------------------------  | 
1060  |  |  | 
1061  |  | UBool  | 
1062  |  | Calendar::equals(const Calendar& when, UErrorCode& status) const  | 
1063  | 0  | { | 
1064  | 0  |     return (this == &when ||  | 
1065  | 0  |         getTime(status) == when.getTime(status));  | 
1066  | 0  | }  | 
1067  |  |  | 
1068  |  | // -------------------------------------  | 
1069  |  |  | 
1070  |  | UBool  | 
1071  |  | Calendar::before(const Calendar& when, UErrorCode& status) const  | 
1072  | 0  | { | 
1073  | 0  |     return (this != &when &&  | 
1074  | 0  |         getTimeInMillis(status) < when.getTimeInMillis(status));  | 
1075  | 0  | }  | 
1076  |  |  | 
1077  |  | // -------------------------------------  | 
1078  |  |  | 
1079  |  | UBool  | 
1080  |  | Calendar::after(const Calendar& when, UErrorCode& status) const  | 
1081  | 0  | { | 
1082  | 0  |     return (this != &when &&  | 
1083  | 0  |         getTimeInMillis(status) > when.getTimeInMillis(status));  | 
1084  | 0  | }  | 
1085  |  |  | 
1086  |  | // -------------------------------------  | 
1087  |  |  | 
1088  |  |  | 
1089  |  | const Locale* U_EXPORT2  | 
1090  |  | Calendar::getAvailableLocales(int32_t& count)  | 
1091  | 0  | { | 
1092  | 0  |     return Locale::getAvailableLocales(count);  | 
1093  | 0  | }  | 
1094  |  |  | 
1095  |  | // -------------------------------------  | 
1096  |  |  | 
1097  |  | StringEnumeration* U_EXPORT2  | 
1098  |  | Calendar::getKeywordValuesForLocale(const char* key,  | 
1099  |  |                     const Locale& locale, UBool commonlyUsed, UErrorCode& status)  | 
1100  | 0  | { | 
1101  |  |     // This is a wrapper over ucal_getKeywordValuesForLocale  | 
1102  | 0  |     UEnumeration *uenum = ucal_getKeywordValuesForLocale(key, locale.getName(),  | 
1103  | 0  |                                                         commonlyUsed, &status);  | 
1104  | 0  |     if (U_FAILURE(status)) { | 
1105  | 0  |         uenum_close(uenum);  | 
1106  | 0  |         return NULL;  | 
1107  | 0  |     }  | 
1108  | 0  |     UStringEnumeration* ustringenum = new UStringEnumeration(uenum);  | 
1109  | 0  |     if (ustringenum == nullptr) { | 
1110  | 0  |         status = U_MEMORY_ALLOCATION_ERROR;  | 
1111  | 0  |     }  | 
1112  | 0  |     return ustringenum;  | 
1113  | 0  | }  | 
1114  |  |  | 
1115  |  | // -------------------------------------  | 
1116  |  |  | 
1117  |  | UDate U_EXPORT2  | 
1118  |  | Calendar::getNow()  | 
1119  | 0  | { | 
1120  | 0  |     return uprv_getUTCtime(); // return as milliseconds  | 
1121  | 0  | }  | 
1122  |  |  | 
1123  |  | // -------------------------------------  | 
1124  |  |  | 
1125  |  | /**  | 
1126  |  | * Gets this Calendar's current time as a long.  | 
1127  |  | * @return the current time as UTC milliseconds from the epoch.  | 
1128  |  | */  | 
1129  |  | double  | 
1130  |  | Calendar::getTimeInMillis(UErrorCode& status) const  | 
1131  | 0  | { | 
1132  | 0  |     if(U_FAILURE(status))  | 
1133  | 0  |         return 0.0;  | 
1134  |  |  | 
1135  | 0  |     if ( ! fIsTimeSet)  | 
1136  | 0  |         ((Calendar*)this)->updateTime(status);  | 
1137  |  |  | 
1138  |  |     /* Test for buffer overflows */  | 
1139  | 0  |     if(U_FAILURE(status)) { | 
1140  | 0  |         return 0.0;  | 
1141  | 0  |     }  | 
1142  | 0  |     return fTime;  | 
1143  | 0  | }  | 
1144  |  |  | 
1145  |  | // -------------------------------------  | 
1146  |  |  | 
1147  |  | /**  | 
1148  |  | * Sets this Calendar's current time from the given long value.  | 
1149  |  | * A status of U_ILLEGAL_ARGUMENT_ERROR is set when millis is  | 
1150  |  | * outside the range permitted by a Calendar object when not in lenient mode.  | 
1151  |  | * when in lenient mode the out of range values are pinned to their respective min/max.  | 
1152  |  | * @param date the new time in UTC milliseconds from the epoch.  | 
1153  |  | */  | 
1154  |  | void  | 
1155  | 0  | Calendar::setTimeInMillis( double millis, UErrorCode& status ) { | 
1156  | 0  |     if(U_FAILURE(status))  | 
1157  | 0  |         return;  | 
1158  |  |  | 
1159  | 0  |     if (millis > MAX_MILLIS) { | 
1160  | 0  |         if(isLenient()) { | 
1161  | 0  |             millis = MAX_MILLIS;  | 
1162  | 0  |         } else { | 
1163  | 0  |         status = U_ILLEGAL_ARGUMENT_ERROR;  | 
1164  | 0  |         return;  | 
1165  | 0  |         }  | 
1166  | 0  |     } else if (millis < MIN_MILLIS) { | 
1167  | 0  |         if(isLenient()) { | 
1168  | 0  |             millis = MIN_MILLIS;  | 
1169  | 0  |         } else { | 
1170  | 0  |         status = U_ILLEGAL_ARGUMENT_ERROR;  | 
1171  | 0  |         return;  | 
1172  | 0  |         }  | 
1173  | 0  |     }  | 
1174  |  |  | 
1175  | 0  |     fTime = millis;  | 
1176  | 0  |     fAreFieldsSet = fAreAllFieldsSet = FALSE;  | 
1177  | 0  |     fIsTimeSet = fAreFieldsVirtuallySet = TRUE;  | 
1178  |  | 
  | 
1179  | 0  |     for (int32_t i=0; i<UCAL_FIELD_COUNT; ++i) { | 
1180  | 0  |         fFields[i]     = 0;  | 
1181  | 0  |         fStamp[i]     = kUnset;  | 
1182  | 0  |         fIsSet[i]     = FALSE;  | 
1183  | 0  |     }  | 
1184  |  |  | 
1185  |  | 
  | 
1186  | 0  | }  | 
1187  |  |  | 
1188  |  | // -------------------------------------  | 
1189  |  |  | 
1190  |  | int32_t  | 
1191  |  | Calendar::get(UCalendarDateFields field, UErrorCode& status) const  | 
1192  | 0  | { | 
1193  |  |     // field values are only computed when actually requested; for more on when computation  | 
1194  |  |     // of various things happens, see the "data flow in Calendar" description at the top  | 
1195  |  |     // of this file  | 
1196  | 0  |     if (U_SUCCESS(status)) ((Calendar*)this)->complete(status); // Cast away const  | 
1197  | 0  |     return U_SUCCESS(status) ? fFields[field] : 0;  | 
1198  | 0  | }  | 
1199  |  |  | 
1200  |  | // -------------------------------------  | 
1201  |  |  | 
1202  |  | void  | 
1203  |  | Calendar::set(UCalendarDateFields field, int32_t value)  | 
1204  | 0  | { | 
1205  | 0  |     if (fAreFieldsVirtuallySet) { | 
1206  | 0  |         UErrorCode ec = U_ZERO_ERROR;  | 
1207  | 0  |         computeFields(ec);  | 
1208  | 0  |     }  | 
1209  | 0  |     fFields[field]     = value;  | 
1210  |  |     /* Ensure that the fNextStamp value doesn't go pass max value for int32_t */  | 
1211  | 0  |     if (fNextStamp == STAMP_MAX) { | 
1212  | 0  |         recalculateStamp();  | 
1213  | 0  |     }  | 
1214  | 0  |     fStamp[field]     = fNextStamp++;  | 
1215  | 0  |     fIsSet[field]     = TRUE; // Remove later  | 
1216  | 0  |     fIsTimeSet = fAreFieldsSet = fAreFieldsVirtuallySet = FALSE;  | 
1217  | 0  | }  | 
1218  |  |  | 
1219  |  | // -------------------------------------  | 
1220  |  |  | 
1221  |  | void  | 
1222  |  | Calendar::set(int32_t year, int32_t month, int32_t date)  | 
1223  | 0  | { | 
1224  | 0  |     set(UCAL_YEAR, year);  | 
1225  | 0  |     set(UCAL_MONTH, month);  | 
1226  | 0  |     set(UCAL_DATE, date);  | 
1227  | 0  | }  | 
1228  |  |  | 
1229  |  | // -------------------------------------  | 
1230  |  |  | 
1231  |  | void  | 
1232  |  | Calendar::set(int32_t year, int32_t month, int32_t date, int32_t hour, int32_t minute)  | 
1233  | 0  | { | 
1234  | 0  |     set(UCAL_YEAR, year);  | 
1235  | 0  |     set(UCAL_MONTH, month);  | 
1236  | 0  |     set(UCAL_DATE, date);  | 
1237  | 0  |     set(UCAL_HOUR_OF_DAY, hour);  | 
1238  | 0  |     set(UCAL_MINUTE, minute);  | 
1239  | 0  | }  | 
1240  |  |  | 
1241  |  | // -------------------------------------  | 
1242  |  |  | 
1243  |  | void  | 
1244  |  | Calendar::set(int32_t year, int32_t month, int32_t date, int32_t hour, int32_t minute, int32_t second)  | 
1245  | 0  | { | 
1246  | 0  |     set(UCAL_YEAR, year);  | 
1247  | 0  |     set(UCAL_MONTH, month);  | 
1248  | 0  |     set(UCAL_DATE, date);  | 
1249  | 0  |     set(UCAL_HOUR_OF_DAY, hour);  | 
1250  | 0  |     set(UCAL_MINUTE, minute);  | 
1251  | 0  |     set(UCAL_SECOND, second);  | 
1252  | 0  | }  | 
1253  |  |  | 
1254  |  | // -------------------------------------  | 
1255  |  | // For now the full getRelatedYear implementation is here;  | 
1256  |  | // per #10752 move the non-default implementation to subclasses  | 
1257  |  | // (default implementation will do no year adjustment)  | 
1258  |  |  | 
1259  | 0  | static int32_t gregoYearFromIslamicStart(int32_t year) { | 
1260  |  |     // ad hoc conversion, improve under #10752  | 
1261  |  |     // rough est for now, ok for grego 1846-2138,  | 
1262  |  |     // otherwise occasionally wrong (for 3% of years)  | 
1263  | 0  |     int cycle, offset, shift = 0;  | 
1264  | 0  |     if (year >= 1397) { | 
1265  | 0  |         cycle = (year - 1397) / 67;  | 
1266  | 0  |         offset = (year - 1397) % 67;  | 
1267  | 0  |         shift = 2*cycle + ((offset >= 33)? 1: 0);  | 
1268  | 0  |     } else { | 
1269  | 0  |         cycle = (year - 1396) / 67 - 1;  | 
1270  | 0  |         offset = -(year - 1396) % 67;  | 
1271  | 0  |         shift = 2*cycle + ((offset <= 33)? 1: 0);  | 
1272  | 0  |     }  | 
1273  | 0  |     return year + 579 - shift;  | 
1274  | 0  | }  | 
1275  |  |  | 
1276  |  | int32_t Calendar::getRelatedYear(UErrorCode &status) const  | 
1277  | 0  | { | 
1278  | 0  |     if (U_FAILURE(status)) { | 
1279  | 0  |         return 0;  | 
1280  | 0  |     }  | 
1281  | 0  |     int32_t year = get(UCAL_EXTENDED_YEAR, status);  | 
1282  | 0  |     if (U_FAILURE(status)) { | 
1283  | 0  |         return 0;  | 
1284  | 0  |     }  | 
1285  |  |     // modify for calendar type  | 
1286  | 0  |     ECalType type = getCalendarType(getType());  | 
1287  | 0  |     switch (type) { | 
1288  | 0  |         case CALTYPE_PERSIAN:  | 
1289  | 0  |             year += 622; break;  | 
1290  | 0  |         case CALTYPE_HEBREW:  | 
1291  | 0  |             year -= 3760; break;  | 
1292  | 0  |         case CALTYPE_CHINESE:  | 
1293  | 0  |             year -= 2637; break;  | 
1294  | 0  |         case CALTYPE_INDIAN:  | 
1295  | 0  |             year += 79; break;  | 
1296  | 0  |         case CALTYPE_COPTIC:  | 
1297  | 0  |             year += 284; break;  | 
1298  | 0  |         case CALTYPE_ETHIOPIC:  | 
1299  | 0  |             year += 8; break;  | 
1300  | 0  |         case CALTYPE_ETHIOPIC_AMETE_ALEM:  | 
1301  | 0  |             year -=5492; break;  | 
1302  | 0  |         case CALTYPE_DANGI:  | 
1303  | 0  |             year -= 2333; break;  | 
1304  | 0  |         case CALTYPE_ISLAMIC_CIVIL:  | 
1305  | 0  |         case CALTYPE_ISLAMIC:  | 
1306  | 0  |         case CALTYPE_ISLAMIC_UMALQURA:  | 
1307  | 0  |         case CALTYPE_ISLAMIC_TBLA:  | 
1308  | 0  |         case CALTYPE_ISLAMIC_RGSA:  | 
1309  | 0  |             year = gregoYearFromIslamicStart(year); break;  | 
1310  | 0  |         default:  | 
1311  |  |             // CALTYPE_GREGORIAN  | 
1312  |  |             // CALTYPE_JAPANESE  | 
1313  |  |             // CALTYPE_BUDDHIST  | 
1314  |  |             // CALTYPE_ROC  | 
1315  |  |             // CALTYPE_ISO8601  | 
1316  |  |             // do nothing, EXTENDED_YEAR same as Gregorian  | 
1317  | 0  |             break;  | 
1318  | 0  |     }  | 
1319  | 0  |     return year;  | 
1320  | 0  | }  | 
1321  |  |  | 
1322  |  | // -------------------------------------  | 
1323  |  | // For now the full setRelatedYear implementation is here;  | 
1324  |  | // per #10752 move the non-default implementation to subclasses  | 
1325  |  | // (default implementation will do no year adjustment)  | 
1326  |  |  | 
1327  | 0  | static int32_t firstIslamicStartYearFromGrego(int32_t year) { | 
1328  |  |     // ad hoc conversion, improve under #10752  | 
1329  |  |     // rough est for now, ok for grego 1846-2138,  | 
1330  |  |     // otherwise occasionally wrong (for 3% of years)  | 
1331  | 0  |     int cycle, offset, shift = 0;  | 
1332  | 0  |     if (year >= 1977) { | 
1333  | 0  |         cycle = (year - 1977) / 65;  | 
1334  | 0  |         offset = (year - 1977) % 65;  | 
1335  | 0  |         shift = 2*cycle + ((offset >= 32)? 1: 0);  | 
1336  | 0  |     } else { | 
1337  | 0  |         cycle = (year - 1976) / 65 - 1;  | 
1338  | 0  |         offset = -(year - 1976) % 65;  | 
1339  | 0  |         shift = 2*cycle + ((offset <= 32)? 1: 0);  | 
1340  | 0  |     }  | 
1341  | 0  |     return year - 579 + shift;  | 
1342  | 0  | }  | 
1343  |  | void Calendar::setRelatedYear(int32_t year)  | 
1344  | 0  | { | 
1345  |  |     // modify for calendar type  | 
1346  | 0  |     ECalType type = getCalendarType(getType());  | 
1347  | 0  |     switch (type) { | 
1348  | 0  |         case CALTYPE_PERSIAN:  | 
1349  | 0  |             year -= 622; break;  | 
1350  | 0  |         case CALTYPE_HEBREW:  | 
1351  | 0  |             year += 3760; break;  | 
1352  | 0  |         case CALTYPE_CHINESE:  | 
1353  | 0  |             year += 2637; break;  | 
1354  | 0  |         case CALTYPE_INDIAN:  | 
1355  | 0  |             year -= 79; break;  | 
1356  | 0  |         case CALTYPE_COPTIC:  | 
1357  | 0  |             year -= 284; break;  | 
1358  | 0  |         case CALTYPE_ETHIOPIC:  | 
1359  | 0  |             year -= 8; break;  | 
1360  | 0  |         case CALTYPE_ETHIOPIC_AMETE_ALEM:  | 
1361  | 0  |             year +=5492; break;  | 
1362  | 0  |         case CALTYPE_DANGI:  | 
1363  | 0  |             year += 2333; break;  | 
1364  | 0  |         case CALTYPE_ISLAMIC_CIVIL:  | 
1365  | 0  |         case CALTYPE_ISLAMIC:  | 
1366  | 0  |         case CALTYPE_ISLAMIC_UMALQURA:  | 
1367  | 0  |         case CALTYPE_ISLAMIC_TBLA:  | 
1368  | 0  |         case CALTYPE_ISLAMIC_RGSA:  | 
1369  | 0  |             year = firstIslamicStartYearFromGrego(year); break;  | 
1370  | 0  |         default:  | 
1371  |  |             // CALTYPE_GREGORIAN  | 
1372  |  |             // CALTYPE_JAPANESE  | 
1373  |  |             // CALTYPE_BUDDHIST  | 
1374  |  |             // CALTYPE_ROC  | 
1375  |  |             // CALTYPE_ISO8601  | 
1376  |  |             // do nothing, EXTENDED_YEAR same as Gregorian  | 
1377  | 0  |             break;  | 
1378  | 0  |     }  | 
1379  |  |     // set extended year  | 
1380  | 0  |     set(UCAL_EXTENDED_YEAR, year);  | 
1381  | 0  | }  | 
1382  |  |  | 
1383  |  | // -------------------------------------  | 
1384  |  |  | 
1385  |  | void  | 
1386  |  | Calendar::clear()  | 
1387  | 0  | { | 
1388  | 0  |     for (int32_t i=0; i<UCAL_FIELD_COUNT; ++i) { | 
1389  | 0  |         fFields[i]     = 0; // Must do this; other code depends on it  | 
1390  | 0  |         fStamp[i]     = kUnset;  | 
1391  | 0  |         fIsSet[i]     = FALSE; // Remove later  | 
1392  | 0  |     }  | 
1393  | 0  |     fIsTimeSet = fAreFieldsSet = fAreAllFieldsSet = fAreFieldsVirtuallySet = FALSE;  | 
1394  |  |     // fTime is not 'cleared' - may be used if no fields are set.  | 
1395  | 0  | }  | 
1396  |  |  | 
1397  |  | // -------------------------------------  | 
1398  |  |  | 
1399  |  | void  | 
1400  |  | Calendar::clear(UCalendarDateFields field)  | 
1401  | 0  | { | 
1402  | 0  |     if (fAreFieldsVirtuallySet) { | 
1403  | 0  |         UErrorCode ec = U_ZERO_ERROR;  | 
1404  | 0  |         computeFields(ec);  | 
1405  | 0  |     }  | 
1406  | 0  |     fFields[field]         = 0;  | 
1407  | 0  |     fStamp[field]         = kUnset;  | 
1408  | 0  |     fIsSet[field]         = FALSE; // Remove later  | 
1409  | 0  |     fIsTimeSet = fAreFieldsSet = fAreAllFieldsSet = fAreFieldsVirtuallySet = FALSE;  | 
1410  | 0  | }  | 
1411  |  |  | 
1412  |  | // -------------------------------------  | 
1413  |  |  | 
1414  |  | UBool  | 
1415  |  | Calendar::isSet(UCalendarDateFields field) const  | 
1416  | 0  | { | 
1417  | 0  |     return fAreFieldsVirtuallySet || (fStamp[field] != kUnset);  | 
1418  | 0  | }  | 
1419  |  |  | 
1420  |  |  | 
1421  |  | int32_t Calendar::newestStamp(UCalendarDateFields first, UCalendarDateFields last, int32_t bestStampSoFar) const  | 
1422  | 0  | { | 
1423  | 0  |     int32_t bestStamp = bestStampSoFar;  | 
1424  | 0  |     for (int32_t i=(int32_t)first; i<=(int32_t)last; ++i) { | 
1425  | 0  |         if (fStamp[i] > bestStamp) { | 
1426  | 0  |             bestStamp = fStamp[i];  | 
1427  | 0  |         }  | 
1428  | 0  |     }  | 
1429  | 0  |     return bestStamp;  | 
1430  | 0  | }  | 
1431  |  |  | 
1432  |  |  | 
1433  |  | // -------------------------------------  | 
1434  |  |  | 
1435  |  | void  | 
1436  |  | Calendar::complete(UErrorCode& status)  | 
1437  | 0  | { | 
1438  | 0  |     if (!fIsTimeSet) { | 
1439  | 0  |         updateTime(status);  | 
1440  |  |         /* Test for buffer overflows */  | 
1441  | 0  |         if(U_FAILURE(status)) { | 
1442  | 0  |             return;  | 
1443  | 0  |         }  | 
1444  | 0  |     }  | 
1445  | 0  |     if (!fAreFieldsSet) { | 
1446  | 0  |         computeFields(status); // fills in unset fields  | 
1447  |  |         /* Test for buffer overflows */  | 
1448  | 0  |         if(U_FAILURE(status)) { | 
1449  | 0  |             return;  | 
1450  | 0  |         }  | 
1451  | 0  |         fAreFieldsSet         = TRUE;  | 
1452  | 0  |         fAreAllFieldsSet     = TRUE;  | 
1453  | 0  |     }  | 
1454  | 0  | }  | 
1455  |  |  | 
1456  |  | //-------------------------------------------------------------------------  | 
1457  |  | // Protected utility methods for use by subclasses.  These are very handy  | 
1458  |  | // for implementing add, roll, and computeFields.  | 
1459  |  | //-------------------------------------------------------------------------  | 
1460  |  |  | 
1461  |  | /**  | 
1462  |  | * Adjust the specified field so that it is within  | 
1463  |  | * the allowable range for the date to which this calendar is set.  | 
1464  |  | * For example, in a Gregorian calendar pinning the {@link #DAY_OF_MONTH DAY_OF_MONTH} | 
1465  |  | * field for a calendar set to April 31 would cause it to be set  | 
1466  |  | * to April 30.  | 
1467  |  | * <p>  | 
1468  |  | * <b>Subclassing:</b>  | 
1469  |  | * <br>  | 
1470  |  | * This utility method is intended for use by subclasses that need to implement  | 
1471  |  | * their own overrides of {@link #roll roll} and {@link #add add}. | 
1472  |  | * <p>  | 
1473  |  | * <b>Note:</b>  | 
1474  |  | * <code>pinField</code> is implemented in terms of  | 
1475  |  | * {@link #getActualMinimum getActualMinimum} | 
1476  |  | * and {@link #getActualMaximum getActualMaximum}.  If either of those methods uses | 
1477  |  | * a slow, iterative algorithm for a particular field, it would be  | 
1478  |  | * unwise to attempt to call <code>pinField</code> for that field.  If you  | 
1479  |  | * really do need to do so, you should override this method to do  | 
1480  |  | * something more efficient for that field.  | 
1481  |  | * <p>  | 
1482  |  | * @param field The calendar field whose value should be pinned.  | 
1483  |  | *  | 
1484  |  | * @see #getActualMinimum  | 
1485  |  | * @see #getActualMaximum  | 
1486  |  | * @stable ICU 2.0  | 
1487  |  | */  | 
1488  | 0  | void Calendar::pinField(UCalendarDateFields field, UErrorCode& status) { | 
1489  | 0  |     int32_t max = getActualMaximum(field, status);  | 
1490  | 0  |     int32_t min = getActualMinimum(field, status);  | 
1491  |  | 
  | 
1492  | 0  |     if (fFields[field] > max) { | 
1493  | 0  |         set(field, max);  | 
1494  | 0  |     } else if (fFields[field] < min) { | 
1495  | 0  |         set(field, min);  | 
1496  | 0  |     }  | 
1497  | 0  | }  | 
1498  |  |  | 
1499  |  |  | 
1500  |  | void Calendar::computeFields(UErrorCode &ec)  | 
1501  | 0  | { | 
1502  | 0  |   if (U_FAILURE(ec)) { | 
1503  | 0  |         return;  | 
1504  | 0  |     }  | 
1505  |  |     // Compute local wall millis  | 
1506  | 0  |     double localMillis = internalGetTime();  | 
1507  | 0  |     int32_t rawOffset, dstOffset;  | 
1508  | 0  |     getTimeZone().getOffset(localMillis, FALSE, rawOffset, dstOffset, ec);  | 
1509  | 0  |     localMillis += (rawOffset + dstOffset);  | 
1510  |  |  | 
1511  |  |     // Mark fields as set.  Do this before calling handleComputeFields().  | 
1512  | 0  |     uint32_t mask =   //fInternalSetMask;  | 
1513  | 0  |         (1 << UCAL_ERA) |  | 
1514  | 0  |         (1 << UCAL_YEAR) |  | 
1515  | 0  |         (1 << UCAL_MONTH) |  | 
1516  | 0  |         (1 << UCAL_DAY_OF_MONTH) | // = UCAL_DATE  | 
1517  | 0  |         (1 << UCAL_DAY_OF_YEAR) |  | 
1518  | 0  |         (1 << UCAL_EXTENDED_YEAR);  | 
1519  |  | 
  | 
1520  | 0  |     for (int32_t i=0; i<UCAL_FIELD_COUNT; ++i) { | 
1521  | 0  |         if ((mask & 1) == 0) { | 
1522  | 0  |             fStamp[i] = kInternallySet;  | 
1523  | 0  |             fIsSet[i] = TRUE; // Remove later  | 
1524  | 0  |         } else { | 
1525  | 0  |             fStamp[i] = kUnset;  | 
1526  | 0  |             fIsSet[i] = FALSE; // Remove later  | 
1527  | 0  |         }  | 
1528  | 0  |         mask >>= 1;  | 
1529  | 0  |     }  | 
1530  |  |  | 
1531  |  |     // We used to check for and correct extreme millis values (near  | 
1532  |  |     // Long.MIN_VALUE or Long.MAX_VALUE) here.  Such values would cause  | 
1533  |  |     // overflows from positive to negative (or vice versa) and had to  | 
1534  |  |     // be manually tweaked.  We no longer need to do this because we  | 
1535  |  |     // have limited the range of supported dates to those that have a  | 
1536  |  |     // Julian day that fits into an int.  This allows us to implement a  | 
1537  |  |     // JULIAN_DAY field and also removes some inelegant code. - Liu  | 
1538  |  |     // 11/6/00  | 
1539  |  | 
  | 
1540  | 0  |     int32_t days =  (int32_t)ClockMath::floorDivide(localMillis, (double)kOneDay);  | 
1541  |  | 
  | 
1542  | 0  |     internalSet(UCAL_JULIAN_DAY,days + kEpochStartAsJulianDay);  | 
1543  |  | 
  | 
1544  |  | #if defined (U_DEBUG_CAL)  | 
1545  |  |     //fprintf(stderr, "%s:%d- Hmm! Jules @ %d, as per %.0lf millis\n",  | 
1546  |  |     //__FILE__, __LINE__, fFields[UCAL_JULIAN_DAY], localMillis);  | 
1547  |  | #endif  | 
1548  |  | 
  | 
1549  | 0  |     computeGregorianAndDOWFields(fFields[UCAL_JULIAN_DAY], ec);  | 
1550  |  |  | 
1551  |  |     // Call framework method to have subclass compute its fields.  | 
1552  |  |     // These must include, at a minimum, MONTH, DAY_OF_MONTH,  | 
1553  |  |     // EXTENDED_YEAR, YEAR, DAY_OF_YEAR.  This method will call internalSet(),  | 
1554  |  |     // which will update stamp[].  | 
1555  | 0  |     handleComputeFields(fFields[UCAL_JULIAN_DAY], ec);  | 
1556  |  |  | 
1557  |  |     // Compute week-related fields, based on the subclass-computed  | 
1558  |  |     // fields computed by handleComputeFields().  | 
1559  | 0  |     computeWeekFields(ec);  | 
1560  |  |  | 
1561  |  |     // Compute time-related fields.  These are independent of the date and  | 
1562  |  |     // of the subclass algorithm.  They depend only on the local zone  | 
1563  |  |     // wall milliseconds in day.  | 
1564  | 0  |     int32_t millisInDay =  (int32_t) (localMillis - (days * kOneDay));  | 
1565  | 0  |     fFields[UCAL_MILLISECONDS_IN_DAY] = millisInDay;  | 
1566  | 0  |     fFields[UCAL_MILLISECOND] = millisInDay % 1000;  | 
1567  | 0  |     millisInDay /= 1000;  | 
1568  | 0  |     fFields[UCAL_SECOND] = millisInDay % 60;  | 
1569  | 0  |     millisInDay /= 60;  | 
1570  | 0  |     fFields[UCAL_MINUTE] = millisInDay % 60;  | 
1571  | 0  |     millisInDay /= 60;  | 
1572  | 0  |     fFields[UCAL_HOUR_OF_DAY] = millisInDay;  | 
1573  | 0  |     fFields[UCAL_AM_PM] = millisInDay / 12; // Assume AM == 0  | 
1574  | 0  |     fFields[UCAL_HOUR] = millisInDay % 12;  | 
1575  | 0  |     fFields[UCAL_ZONE_OFFSET] = rawOffset;  | 
1576  | 0  |     fFields[UCAL_DST_OFFSET] = dstOffset;  | 
1577  | 0  | }  | 
1578  |  |  | 
1579  |  | uint8_t Calendar::julianDayToDayOfWeek(double julian)  | 
1580  | 0  | { | 
1581  |  |     // If julian is negative, then julian%7 will be negative, so we adjust  | 
1582  |  |     // accordingly.  We add 1 because Julian day 0 is Monday.  | 
1583  | 0  |     int8_t dayOfWeek = (int8_t) uprv_fmod(julian + 1, 7);  | 
1584  |  | 
  | 
1585  | 0  |     uint8_t result = (uint8_t)(dayOfWeek + ((dayOfWeek < 0) ? (7+UCAL_SUNDAY ) : UCAL_SUNDAY));  | 
1586  | 0  |     return result;  | 
1587  | 0  | }  | 
1588  |  |  | 
1589  |  | /**  | 
1590  |  | * Compute the Gregorian calendar year, month, and day of month from  | 
1591  |  | * the given Julian day.  These values are not stored in fields, but in  | 
1592  |  | * member variables gregorianXxx.  Also compute the DAY_OF_WEEK and  | 
1593  |  | * DOW_LOCAL fields.  | 
1594  |  | */  | 
1595  |  | void Calendar::computeGregorianAndDOWFields(int32_t julianDay, UErrorCode &ec)  | 
1596  | 0  | { | 
1597  | 0  |     computeGregorianFields(julianDay, ec);  | 
1598  |  |  | 
1599  |  |     // Compute day of week: JD 0 = Monday  | 
1600  | 0  |     int32_t dow = julianDayToDayOfWeek(julianDay);  | 
1601  | 0  |     internalSet(UCAL_DAY_OF_WEEK,dow);  | 
1602  |  |  | 
1603  |  |     // Calculate 1-based localized day of week  | 
1604  | 0  |     int32_t dowLocal = dow - getFirstDayOfWeek() + 1;  | 
1605  | 0  |     if (dowLocal < 1) { | 
1606  | 0  |         dowLocal += 7;  | 
1607  | 0  |     }  | 
1608  | 0  |     internalSet(UCAL_DOW_LOCAL,dowLocal);  | 
1609  | 0  |     fFields[UCAL_DOW_LOCAL] = dowLocal;  | 
1610  | 0  | }  | 
1611  |  |  | 
1612  |  | /**  | 
1613  |  | * Compute the Gregorian calendar year, month, and day of month from the  | 
1614  |  | * Julian day.  These values are not stored in fields, but in member  | 
1615  |  | * variables gregorianXxx.  They are used for time zone computations and by  | 
1616  |  | * subclasses that are Gregorian derivatives.  Subclasses may call this  | 
1617  |  | * method to perform a Gregorian calendar millis->fields computation.  | 
1618  |  | */  | 
1619  | 0  | void Calendar::computeGregorianFields(int32_t julianDay, UErrorCode & /* ec */) { | 
1620  | 0  |     int32_t gregorianDayOfWeekUnused;  | 
1621  | 0  |     Grego::dayToFields(julianDay - kEpochStartAsJulianDay, fGregorianYear, fGregorianMonth, fGregorianDayOfMonth, gregorianDayOfWeekUnused, fGregorianDayOfYear);  | 
1622  | 0  | }  | 
1623  |  |  | 
1624  |  | /**  | 
1625  |  | * Compute the fields WEEK_OF_YEAR, YEAR_WOY, WEEK_OF_MONTH,  | 
1626  |  | * DAY_OF_WEEK_IN_MONTH, and DOW_LOCAL from EXTENDED_YEAR, YEAR,  | 
1627  |  | * DAY_OF_WEEK, and DAY_OF_YEAR.  The latter fields are computed by the  | 
1628  |  | * subclass based on the calendar system.  | 
1629  |  | *  | 
1630  |  | * <p>The YEAR_WOY field is computed simplistically.  It is equal to YEAR  | 
1631  |  | * most of the time, but at the year boundary it may be adjusted to YEAR-1  | 
1632  |  | * or YEAR+1 to reflect the overlap of a week into an adjacent year.  In  | 
1633  |  | * this case, a simple increment or decrement is performed on YEAR, even  | 
1634  |  | * though this may yield an invalid YEAR value.  For instance, if the YEAR  | 
1635  |  | * is part of a calendar system with an N-year cycle field CYCLE, then  | 
1636  |  | * incrementing the YEAR may involve incrementing CYCLE and setting YEAR  | 
1637  |  | * back to 0 or 1.  This is not handled by this code, and in fact cannot be  | 
1638  |  | * simply handled without having subclasses define an entire parallel set of  | 
1639  |  | * fields for fields larger than or equal to a year.  This additional  | 
1640  |  | * complexity is not warranted, since the intention of the YEAR_WOY field is  | 
1641  |  | * to support ISO 8601 notation, so it will typically be used with a  | 
1642  |  | * proleptic Gregorian calendar, which has no field larger than a year.  | 
1643  |  | */  | 
1644  | 0  | void Calendar::computeWeekFields(UErrorCode &ec) { | 
1645  | 0  |     if(U_FAILURE(ec)) { | 
1646  | 0  |         return;  | 
1647  | 0  |     }  | 
1648  | 0  |     int32_t eyear = fFields[UCAL_EXTENDED_YEAR];  | 
1649  | 0  |     int32_t dayOfWeek = fFields[UCAL_DAY_OF_WEEK];  | 
1650  | 0  |     int32_t dayOfYear = fFields[UCAL_DAY_OF_YEAR];  | 
1651  |  |  | 
1652  |  |     // WEEK_OF_YEAR start  | 
1653  |  |     // Compute the week of the year.  For the Gregorian calendar, valid week  | 
1654  |  |     // numbers run from 1 to 52 or 53, depending on the year, the first day  | 
1655  |  |     // of the week, and the minimal days in the first week.  For other  | 
1656  |  |     // calendars, the valid range may be different -- it depends on the year  | 
1657  |  |     // length.  Days at the start of the year may fall into the last week of  | 
1658  |  |     // the previous year; days at the end of the year may fall into the  | 
1659  |  |     // first week of the next year.  ASSUME that the year length is less than  | 
1660  |  |     // 7000 days.  | 
1661  | 0  |     int32_t yearOfWeekOfYear = eyear;  | 
1662  | 0  |     int32_t relDow = (dayOfWeek + 7 - getFirstDayOfWeek()) % 7; // 0..6  | 
1663  | 0  |     int32_t relDowJan1 = (dayOfWeek - dayOfYear + 7001 - getFirstDayOfWeek()) % 7; // 0..6  | 
1664  | 0  |     int32_t woy = (dayOfYear - 1 + relDowJan1) / 7; // 0..53  | 
1665  | 0  |     if ((7 - relDowJan1) >= getMinimalDaysInFirstWeek()) { | 
1666  | 0  |         ++woy;  | 
1667  | 0  |     }  | 
1668  |  |  | 
1669  |  |     // Adjust for weeks at the year end that overlap into the previous or  | 
1670  |  |     // next calendar year.  | 
1671  | 0  |     if (woy == 0) { | 
1672  |  |         // We are the last week of the previous year.  | 
1673  |  |         // Check to see if we are in the last week; if so, we need  | 
1674  |  |         // to handle the case in which we are the first week of the  | 
1675  |  |         // next year.  | 
1676  |  | 
  | 
1677  | 0  |         int32_t prevDoy = dayOfYear + handleGetYearLength(eyear - 1);  | 
1678  | 0  |         woy = weekNumber(prevDoy, dayOfWeek);  | 
1679  | 0  |         yearOfWeekOfYear--;  | 
1680  | 0  |     } else { | 
1681  | 0  |         int32_t lastDoy = handleGetYearLength(eyear);  | 
1682  |  |         // Fast check: For it to be week 1 of the next year, the DOY  | 
1683  |  |         // must be on or after L-5, where L is yearLength(), then it  | 
1684  |  |         // cannot possibly be week 1 of the next year:  | 
1685  |  |         //          L-5                  L  | 
1686  |  |         // doy: 359 360 361 362 363 364 365 001  | 
1687  |  |         // dow:      1   2   3   4   5   6   7  | 
1688  | 0  |         if (dayOfYear >= (lastDoy - 5)) { | 
1689  | 0  |             int32_t lastRelDow = (relDow + lastDoy - dayOfYear) % 7;  | 
1690  | 0  |             if (lastRelDow < 0) { | 
1691  | 0  |                 lastRelDow += 7;  | 
1692  | 0  |             }  | 
1693  | 0  |             if (((6 - lastRelDow) >= getMinimalDaysInFirstWeek()) &&  | 
1694  | 0  |                 ((dayOfYear + 7 - relDow) > lastDoy)) { | 
1695  | 0  |                     woy = 1;  | 
1696  | 0  |                     yearOfWeekOfYear++;  | 
1697  | 0  |                 }  | 
1698  | 0  |         }  | 
1699  | 0  |     }  | 
1700  | 0  |     fFields[UCAL_WEEK_OF_YEAR] = woy;  | 
1701  | 0  |     fFields[UCAL_YEAR_WOY] = yearOfWeekOfYear;  | 
1702  |  |     // WEEK_OF_YEAR end  | 
1703  |  | 
  | 
1704  | 0  |     int32_t dayOfMonth = fFields[UCAL_DAY_OF_MONTH];  | 
1705  | 0  |     fFields[UCAL_WEEK_OF_MONTH] = weekNumber(dayOfMonth, dayOfWeek);  | 
1706  | 0  |     fFields[UCAL_DAY_OF_WEEK_IN_MONTH] = (dayOfMonth-1) / 7 + 1;  | 
1707  |  | #if defined (U_DEBUG_CAL)  | 
1708  |  |     if(fFields[UCAL_DAY_OF_WEEK_IN_MONTH]==0) fprintf(stderr, "%s:%d: DOWIM %d on %g\n",  | 
1709  |  |         __FILE__, __LINE__,fFields[UCAL_DAY_OF_WEEK_IN_MONTH], fTime);  | 
1710  |  | #endif  | 
1711  | 0  | }  | 
1712  |  |  | 
1713  |  |  | 
1714  |  | int32_t Calendar::weekNumber(int32_t desiredDay, int32_t dayOfPeriod, int32_t dayOfWeek)  | 
1715  | 0  | { | 
1716  |  |     // Determine the day of the week of the first day of the period  | 
1717  |  |     // in question (either a year or a month).  Zero represents the  | 
1718  |  |     // first day of the week on this calendar.  | 
1719  | 0  |     int32_t periodStartDayOfWeek = (dayOfWeek - getFirstDayOfWeek() - dayOfPeriod + 1) % 7;  | 
1720  | 0  |     if (periodStartDayOfWeek < 0) periodStartDayOfWeek += 7;  | 
1721  |  |  | 
1722  |  |     // Compute the week number.  Initially, ignore the first week, which  | 
1723  |  |     // may be fractional (or may not be).  We add periodStartDayOfWeek in  | 
1724  |  |     // order to fill out the first week, if it is fractional.  | 
1725  | 0  |     int32_t weekNo = (desiredDay + periodStartDayOfWeek - 1)/7;  | 
1726  |  |  | 
1727  |  |     // If the first week is long enough, then count it.  If  | 
1728  |  |     // the minimal days in the first week is one, or if the period start  | 
1729  |  |     // is zero, we always increment weekNo.  | 
1730  | 0  |     if ((7 - periodStartDayOfWeek) >= getMinimalDaysInFirstWeek()) ++weekNo;  | 
1731  |  | 
  | 
1732  | 0  |     return weekNo;  | 
1733  | 0  | }  | 
1734  |  |  | 
1735  |  | void Calendar::handleComputeFields(int32_t /* julianDay */, UErrorCode &/* status */)  | 
1736  | 0  | { | 
1737  | 0  |     internalSet(UCAL_MONTH, getGregorianMonth());  | 
1738  | 0  |     internalSet(UCAL_DAY_OF_MONTH, getGregorianDayOfMonth());  | 
1739  | 0  |     internalSet(UCAL_DAY_OF_YEAR, getGregorianDayOfYear());  | 
1740  | 0  |     int32_t eyear = getGregorianYear();  | 
1741  | 0  |     internalSet(UCAL_EXTENDED_YEAR, eyear);  | 
1742  | 0  |     int32_t era = GregorianCalendar::AD;  | 
1743  | 0  |     if (eyear < 1) { | 
1744  | 0  |         era = GregorianCalendar::BC;  | 
1745  | 0  |         eyear = 1 - eyear;  | 
1746  | 0  |     }  | 
1747  | 0  |     internalSet(UCAL_ERA, era);  | 
1748  | 0  |     internalSet(UCAL_YEAR, eyear);  | 
1749  | 0  | }  | 
1750  |  | // -------------------------------------  | 
1751  |  |  | 
1752  |  |  | 
1753  |  | void Calendar::roll(EDateFields field, int32_t amount, UErrorCode& status)  | 
1754  | 0  | { | 
1755  | 0  |     roll((UCalendarDateFields)field, amount, status);  | 
1756  | 0  | }  | 
1757  |  |  | 
1758  |  | void Calendar::roll(UCalendarDateFields field, int32_t amount, UErrorCode& status)  | 
1759  | 0  | { | 
1760  | 0  |     if (amount == 0) { | 
1761  | 0  |         return; // Nothing to do  | 
1762  | 0  |     }  | 
1763  |  |  | 
1764  | 0  |     complete(status);  | 
1765  |  | 
  | 
1766  | 0  |     if(U_FAILURE(status)) { | 
1767  | 0  |         return;  | 
1768  | 0  |     }  | 
1769  | 0  |     switch (field) { | 
1770  | 0  |     case UCAL_DAY_OF_MONTH:  | 
1771  | 0  |     case UCAL_AM_PM:  | 
1772  | 0  |     case UCAL_MINUTE:  | 
1773  | 0  |     case UCAL_SECOND:  | 
1774  | 0  |     case UCAL_MILLISECOND:  | 
1775  | 0  |     case UCAL_MILLISECONDS_IN_DAY:  | 
1776  | 0  |     case UCAL_ERA:  | 
1777  |  |         // These are the standard roll instructions.  These work for all  | 
1778  |  |         // simple cases, that is, cases in which the limits are fixed, such  | 
1779  |  |         // as the hour, the day of the month, and the era.  | 
1780  | 0  |         { | 
1781  | 0  |             int32_t min = getActualMinimum(field,status);  | 
1782  | 0  |             int32_t max = getActualMaximum(field,status);  | 
1783  | 0  |             int32_t gap = max - min + 1;  | 
1784  |  | 
  | 
1785  | 0  |             int32_t value = internalGet(field) + amount;  | 
1786  | 0  |             value = (value - min) % gap;  | 
1787  | 0  |             if (value < 0) { | 
1788  | 0  |                 value += gap;  | 
1789  | 0  |             }  | 
1790  | 0  |             value += min;  | 
1791  |  | 
  | 
1792  | 0  |             set(field, value);  | 
1793  | 0  |             return;  | 
1794  | 0  |         }  | 
1795  |  |  | 
1796  | 0  |     case UCAL_HOUR:  | 
1797  | 0  |     case UCAL_HOUR_OF_DAY:  | 
1798  |  |         // Rolling the hour is difficult on the ONSET and CEASE days of  | 
1799  |  |         // daylight savings.  For example, if the change occurs at  | 
1800  |  |         // 2 AM, we have the following progression:  | 
1801  |  |         // ONSET: 12 Std -> 1 Std -> 3 Dst -> 4 Dst  | 
1802  |  |         // CEASE: 12 Dst -> 1 Dst -> 1 Std -> 2 Std  | 
1803  |  |         // To get around this problem we don't use fields; we manipulate  | 
1804  |  |         // the time in millis directly.  | 
1805  | 0  |         { | 
1806  |  |             // Assume min == 0 in calculations below  | 
1807  | 0  |             double start = getTimeInMillis(status);  | 
1808  | 0  |             int32_t oldHour = internalGet(field);  | 
1809  | 0  |             int32_t max = getMaximum(field);  | 
1810  | 0  |             int32_t newHour = (oldHour + amount) % (max + 1);  | 
1811  | 0  |             if (newHour < 0) { | 
1812  | 0  |                 newHour += max + 1;  | 
1813  | 0  |             }  | 
1814  | 0  |             setTimeInMillis(start + kOneHour * (newHour - oldHour),status);  | 
1815  | 0  |             return;  | 
1816  | 0  |         }  | 
1817  |  |  | 
1818  | 0  |     case UCAL_MONTH:  | 
1819  |  |         // Rolling the month involves both pinning the final value  | 
1820  |  |         // and adjusting the DAY_OF_MONTH if necessary.  We only adjust the  | 
1821  |  |         // DAY_OF_MONTH if, after updating the MONTH field, it is illegal.  | 
1822  |  |         // E.g., <jan31>.roll(MONTH, 1) -> <feb28> or <feb29>.  | 
1823  | 0  |         { | 
1824  | 0  |             int32_t max = getActualMaximum(UCAL_MONTH, status);  | 
1825  | 0  |             int32_t mon = (internalGet(UCAL_MONTH) + amount) % (max+1);  | 
1826  |  | 
  | 
1827  | 0  |             if (mon < 0) { | 
1828  | 0  |                 mon += (max + 1);  | 
1829  | 0  |             }  | 
1830  | 0  |             set(UCAL_MONTH, mon);  | 
1831  |  |  | 
1832  |  |             // Keep the day of month in range.  We don't want to spill over  | 
1833  |  |             // into the next month; e.g., we don't want jan31 + 1 mo -> feb31 ->  | 
1834  |  |             // mar3.  | 
1835  | 0  |             pinField(UCAL_DAY_OF_MONTH,status);  | 
1836  | 0  |             return;  | 
1837  | 0  |         }  | 
1838  |  |  | 
1839  | 0  |     case UCAL_YEAR:  | 
1840  | 0  |     case UCAL_YEAR_WOY:  | 
1841  | 0  |         { | 
1842  |  |             // * If era==0 and years go backwards in time, change sign of amount.  | 
1843  |  |             // * Until we have new API per #9393, we temporarily hardcode knowledge of  | 
1844  |  |             //   which calendars have era 0 years that go backwards.  | 
1845  | 0  |             UBool era0WithYearsThatGoBackwards = FALSE;  | 
1846  | 0  |             int32_t era = get(UCAL_ERA, status);  | 
1847  | 0  |             if (era == 0) { | 
1848  | 0  |                 const char * calType = getType();  | 
1849  | 0  |                 if ( uprv_strcmp(calType,"gregorian")==0 || uprv_strcmp(calType,"roc")==0 || uprv_strcmp(calType,"coptic")==0 ) { | 
1850  | 0  |                     amount = -amount;  | 
1851  | 0  |                     era0WithYearsThatGoBackwards = TRUE;  | 
1852  | 0  |                 }  | 
1853  | 0  |             }  | 
1854  | 0  |             int32_t newYear = internalGet(field) + amount;  | 
1855  | 0  |             if (era > 0 || newYear >= 1) { | 
1856  | 0  |                 int32_t maxYear = getActualMaximum(field, status);  | 
1857  | 0  |                 if (maxYear < 32768) { | 
1858  |  |                     // this era has real bounds, roll should wrap years  | 
1859  | 0  |                     if (newYear < 1) { | 
1860  | 0  |                         newYear = maxYear - ((-newYear) % maxYear);  | 
1861  | 0  |                     } else if (newYear > maxYear) { | 
1862  | 0  |                         newYear = ((newYear - 1) % maxYear) + 1;  | 
1863  | 0  |                     }  | 
1864  |  |                 // else era is unbounded, just pin low year instead of wrapping  | 
1865  | 0  |                 } else if (newYear < 1) { | 
1866  | 0  |                     newYear = 1;  | 
1867  | 0  |                 }  | 
1868  |  |             // else we are in era 0 with newYear < 1;  | 
1869  |  |             // calendars with years that go backwards must pin the year value at 0,  | 
1870  |  |             // other calendars can have years < 0 in era 0  | 
1871  | 0  |             } else if (era0WithYearsThatGoBackwards) { | 
1872  | 0  |                 newYear = 1;  | 
1873  | 0  |             }  | 
1874  | 0  |             set(field, newYear);  | 
1875  | 0  |             pinField(UCAL_MONTH,status);  | 
1876  | 0  |             pinField(UCAL_DAY_OF_MONTH,status);  | 
1877  | 0  |             return;  | 
1878  | 0  |         }  | 
1879  |  |  | 
1880  | 0  |     case UCAL_EXTENDED_YEAR:  | 
1881  |  |         // Rolling the year can involve pinning the DAY_OF_MONTH.  | 
1882  | 0  |         set(field, internalGet(field) + amount);  | 
1883  | 0  |         pinField(UCAL_MONTH,status);  | 
1884  | 0  |         pinField(UCAL_DAY_OF_MONTH,status);  | 
1885  | 0  |         return;  | 
1886  |  |  | 
1887  | 0  |     case UCAL_WEEK_OF_MONTH:  | 
1888  | 0  |         { | 
1889  |  |             // This is tricky, because during the roll we may have to shift  | 
1890  |  |             // to a different day of the week.  For example:  | 
1891  |  |  | 
1892  |  |             //    s  m  t  w  r  f  s  | 
1893  |  |             //          1  2  3  4  5  | 
1894  |  |             //    6  7  8  9 10 11 12  | 
1895  |  |  | 
1896  |  |             // When rolling from the 6th or 7th back one week, we go to the  | 
1897  |  |             // 1st (assuming that the first partial week counts).  The same  | 
1898  |  |             // thing happens at the end of the month.  | 
1899  |  |  | 
1900  |  |             // The other tricky thing is that we have to figure out whether  | 
1901  |  |             // the first partial week actually counts or not, based on the  | 
1902  |  |             // minimal first days in the week.  And we have to use the  | 
1903  |  |             // correct first day of the week to delineate the week  | 
1904  |  |             // boundaries.  | 
1905  |  |  | 
1906  |  |             // Here's our algorithm.  First, we find the real boundaries of  | 
1907  |  |             // the month.  Then we discard the first partial week if it  | 
1908  |  |             // doesn't count in this locale.  Then we fill in the ends with  | 
1909  |  |             // phantom days, so that the first partial week and the last  | 
1910  |  |             // partial week are full weeks.  We then have a nice square  | 
1911  |  |             // block of weeks.  We do the usual rolling within this block,  | 
1912  |  |             // as is done elsewhere in this method.  If we wind up on one of  | 
1913  |  |             // the phantom days that we added, we recognize this and pin to  | 
1914  |  |             // the first or the last day of the month.  Easy, eh?  | 
1915  |  |  | 
1916  |  |             // Normalize the DAY_OF_WEEK so that 0 is the first day of the week  | 
1917  |  |             // in this locale.  We have dow in 0..6.  | 
1918  | 0  |             int32_t dow = internalGet(UCAL_DAY_OF_WEEK) - getFirstDayOfWeek();  | 
1919  | 0  |             if (dow < 0) dow += 7;  | 
1920  |  |  | 
1921  |  |             // Find the day of the week (normalized for locale) for the first  | 
1922  |  |             // of the month.  | 
1923  | 0  |             int32_t fdm = (dow - internalGet(UCAL_DAY_OF_MONTH) + 1) % 7;  | 
1924  | 0  |             if (fdm < 0) fdm += 7;  | 
1925  |  |  | 
1926  |  |             // Get the first day of the first full week of the month,  | 
1927  |  |             // including phantom days, if any.  Figure out if the first week  | 
1928  |  |             // counts or not; if it counts, then fill in phantom days.  If  | 
1929  |  |             // not, advance to the first real full week (skip the partial week).  | 
1930  | 0  |             int32_t start;  | 
1931  | 0  |             if ((7 - fdm) < getMinimalDaysInFirstWeek())  | 
1932  | 0  |                 start = 8 - fdm; // Skip the first partial week  | 
1933  | 0  |             else  | 
1934  | 0  |                 start = 1 - fdm; // This may be zero or negative  | 
1935  |  |  | 
1936  |  |             // Get the day of the week (normalized for locale) for the last  | 
1937  |  |             // day of the month.  | 
1938  | 0  |             int32_t monthLen = getActualMaximum(UCAL_DAY_OF_MONTH, status);  | 
1939  | 0  |             int32_t ldm = (monthLen - internalGet(UCAL_DAY_OF_MONTH) + dow) % 7;  | 
1940  |  |             // We know monthLen >= DAY_OF_MONTH so we skip the += 7 step here.  | 
1941  |  |  | 
1942  |  |             // Get the limit day for the blocked-off rectangular month; that  | 
1943  |  |             // is, the day which is one past the last day of the month,  | 
1944  |  |             // after the month has already been filled in with phantom days  | 
1945  |  |             // to fill out the last week.  This day has a normalized DOW of 0.  | 
1946  | 0  |             int32_t limit = monthLen + 7 - ldm;  | 
1947  |  |  | 
1948  |  |             // Now roll between start and (limit - 1).  | 
1949  | 0  |             int32_t gap = limit - start;  | 
1950  | 0  |             int32_t day_of_month = (internalGet(UCAL_DAY_OF_MONTH) + amount*7 -  | 
1951  | 0  |                 start) % gap;  | 
1952  | 0  |             if (day_of_month < 0) day_of_month += gap;  | 
1953  | 0  |             day_of_month += start;  | 
1954  |  |  | 
1955  |  |             // Finally, pin to the real start and end of the month.  | 
1956  | 0  |             if (day_of_month < 1) day_of_month = 1;  | 
1957  | 0  |             if (day_of_month > monthLen) day_of_month = monthLen;  | 
1958  |  |  | 
1959  |  |             // Set the DAY_OF_MONTH.  We rely on the fact that this field  | 
1960  |  |             // takes precedence over everything else (since all other fields  | 
1961  |  |             // are also set at this point).  If this fact changes (if the  | 
1962  |  |             // disambiguation algorithm changes) then we will have to unset  | 
1963  |  |             // the appropriate fields here so that DAY_OF_MONTH is attended  | 
1964  |  |             // to.  | 
1965  | 0  |             set(UCAL_DAY_OF_MONTH, day_of_month);  | 
1966  | 0  |             return;  | 
1967  | 0  |         }  | 
1968  | 0  |     case UCAL_WEEK_OF_YEAR:  | 
1969  | 0  |         { | 
1970  |  |             // This follows the outline of WEEK_OF_MONTH, except it applies  | 
1971  |  |             // to the whole year.  Please see the comment for WEEK_OF_MONTH  | 
1972  |  |             // for general notes.  | 
1973  |  |  | 
1974  |  |             // Normalize the DAY_OF_WEEK so that 0 is the first day of the week  | 
1975  |  |             // in this locale.  We have dow in 0..6.  | 
1976  | 0  |             int32_t dow = internalGet(UCAL_DAY_OF_WEEK) - getFirstDayOfWeek();  | 
1977  | 0  |             if (dow < 0) dow += 7;  | 
1978  |  |  | 
1979  |  |             // Find the day of the week (normalized for locale) for the first  | 
1980  |  |             // of the year.  | 
1981  | 0  |             int32_t fdy = (dow - internalGet(UCAL_DAY_OF_YEAR) + 1) % 7;  | 
1982  | 0  |             if (fdy < 0) fdy += 7;  | 
1983  |  |  | 
1984  |  |             // Get the first day of the first full week of the year,  | 
1985  |  |             // including phantom days, if any.  Figure out if the first week  | 
1986  |  |             // counts or not; if it counts, then fill in phantom days.  If  | 
1987  |  |             // not, advance to the first real full week (skip the partial week).  | 
1988  | 0  |             int32_t start;  | 
1989  | 0  |             if ((7 - fdy) < getMinimalDaysInFirstWeek())  | 
1990  | 0  |                 start = 8 - fdy; // Skip the first partial week  | 
1991  | 0  |             else  | 
1992  | 0  |                 start = 1 - fdy; // This may be zero or negative  | 
1993  |  |  | 
1994  |  |             // Get the day of the week (normalized for locale) for the last  | 
1995  |  |             // day of the year.  | 
1996  | 0  |             int32_t yearLen = getActualMaximum(UCAL_DAY_OF_YEAR,status);  | 
1997  | 0  |             int32_t ldy = (yearLen - internalGet(UCAL_DAY_OF_YEAR) + dow) % 7;  | 
1998  |  |             // We know yearLen >= DAY_OF_YEAR so we skip the += 7 step here.  | 
1999  |  |  | 
2000  |  |             // Get the limit day for the blocked-off rectangular year; that  | 
2001  |  |             // is, the day which is one past the last day of the year,  | 
2002  |  |             // after the year has already been filled in with phantom days  | 
2003  |  |             // to fill out the last week.  This day has a normalized DOW of 0.  | 
2004  | 0  |             int32_t limit = yearLen + 7 - ldy;  | 
2005  |  |  | 
2006  |  |             // Now roll between start and (limit - 1).  | 
2007  | 0  |             int32_t gap = limit - start;  | 
2008  | 0  |             int32_t day_of_year = (internalGet(UCAL_DAY_OF_YEAR) + amount*7 -  | 
2009  | 0  |                 start) % gap;  | 
2010  | 0  |             if (day_of_year < 0) day_of_year += gap;  | 
2011  | 0  |             day_of_year += start;  | 
2012  |  |  | 
2013  |  |             // Finally, pin to the real start and end of the month.  | 
2014  | 0  |             if (day_of_year < 1) day_of_year = 1;  | 
2015  | 0  |             if (day_of_year > yearLen) day_of_year = yearLen;  | 
2016  |  |  | 
2017  |  |             // Make sure that the year and day of year are attended to by  | 
2018  |  |             // clearing other fields which would normally take precedence.  | 
2019  |  |             // If the disambiguation algorithm is changed, this section will  | 
2020  |  |             // have to be updated as well.  | 
2021  | 0  |             set(UCAL_DAY_OF_YEAR, day_of_year);  | 
2022  | 0  |             clear(UCAL_MONTH);  | 
2023  | 0  |             return;  | 
2024  | 0  |         }  | 
2025  | 0  |     case UCAL_DAY_OF_YEAR:  | 
2026  | 0  |         { | 
2027  |  |             // Roll the day of year using millis.  Compute the millis for  | 
2028  |  |             // the start of the year, and get the length of the year.  | 
2029  | 0  |             double delta = amount * kOneDay; // Scale up from days to millis  | 
2030  | 0  |             double min2 = internalGet(UCAL_DAY_OF_YEAR)-1;  | 
2031  | 0  |             min2 *= kOneDay;  | 
2032  | 0  |             min2 = internalGetTime() - min2;  | 
2033  |  |  | 
2034  |  |             //      double min2 = internalGetTime() - (internalGet(UCAL_DAY_OF_YEAR) - 1.0) * kOneDay;  | 
2035  | 0  |             double newtime;  | 
2036  |  | 
  | 
2037  | 0  |             double yearLength = getActualMaximum(UCAL_DAY_OF_YEAR,status);  | 
2038  | 0  |             double oneYear = yearLength;  | 
2039  | 0  |             oneYear *= kOneDay;  | 
2040  | 0  |             newtime = uprv_fmod((internalGetTime() + delta - min2), oneYear);  | 
2041  | 0  |             if (newtime < 0) newtime += oneYear;  | 
2042  | 0  |             setTimeInMillis(newtime + min2, status);  | 
2043  | 0  |             return;  | 
2044  | 0  |         }  | 
2045  | 0  |     case UCAL_DAY_OF_WEEK:  | 
2046  | 0  |     case UCAL_DOW_LOCAL:  | 
2047  | 0  |         { | 
2048  |  |             // Roll the day of week using millis.  Compute the millis for  | 
2049  |  |             // the start of the week, using the first day of week setting.  | 
2050  |  |             // Restrict the millis to [start, start+7days).  | 
2051  | 0  |             double delta = amount * kOneDay; // Scale up from days to millis  | 
2052  |  |             // Compute the number of days before the current day in this  | 
2053  |  |             // week.  This will be a value 0..6.  | 
2054  | 0  |             int32_t leadDays = internalGet(field);  | 
2055  | 0  |             leadDays -= (field == UCAL_DAY_OF_WEEK) ? getFirstDayOfWeek() : 1;  | 
2056  | 0  |             if (leadDays < 0) leadDays += 7;  | 
2057  | 0  |             double min2 = internalGetTime() - leadDays * kOneDay;  | 
2058  | 0  |             double newtime = uprv_fmod((internalGetTime() + delta - min2), kOneWeek);  | 
2059  | 0  |             if (newtime < 0) newtime += kOneWeek;  | 
2060  | 0  |             setTimeInMillis(newtime + min2, status);  | 
2061  | 0  |             return;  | 
2062  | 0  |         }  | 
2063  | 0  |     case UCAL_DAY_OF_WEEK_IN_MONTH:  | 
2064  | 0  |         { | 
2065  |  |             // Roll the day of week in the month using millis.  Determine  | 
2066  |  |             // the first day of the week in the month, and then the last,  | 
2067  |  |             // and then roll within that range.  | 
2068  | 0  |             double delta = amount * kOneWeek; // Scale up from weeks to millis  | 
2069  |  |             // Find the number of same days of the week before this one  | 
2070  |  |             // in this month.  | 
2071  | 0  |             int32_t preWeeks = (internalGet(UCAL_DAY_OF_MONTH) - 1) / 7;  | 
2072  |  |             // Find the number of same days of the week after this one  | 
2073  |  |             // in this month.  | 
2074  | 0  |             int32_t postWeeks = (getActualMaximum(UCAL_DAY_OF_MONTH,status) -  | 
2075  | 0  |                 internalGet(UCAL_DAY_OF_MONTH)) / 7;  | 
2076  |  |             // From these compute the min and gap millis for rolling.  | 
2077  | 0  |             double min2 = internalGetTime() - preWeeks * kOneWeek;  | 
2078  | 0  |             double gap2 = kOneWeek * (preWeeks + postWeeks + 1); // Must add 1!  | 
2079  |  |             // Roll within this range  | 
2080  | 0  |             double newtime = uprv_fmod((internalGetTime() + delta - min2), gap2);  | 
2081  | 0  |             if (newtime < 0) newtime += gap2;  | 
2082  | 0  |             setTimeInMillis(newtime + min2, status);  | 
2083  | 0  |             return;  | 
2084  | 0  |         }  | 
2085  | 0  |     case UCAL_JULIAN_DAY:  | 
2086  | 0  |         set(field, internalGet(field) + amount);  | 
2087  | 0  |         return;  | 
2088  | 0  |     default:  | 
2089  |  |         // Other fields cannot be rolled by this method  | 
2090  |  | #if defined (U_DEBUG_CAL)  | 
2091  |  |         fprintf(stderr, "%s:%d: ILLEGAL ARG because of roll on non-rollable field %s\n",  | 
2092  |  |             __FILE__, __LINE__,fldName(field));  | 
2093  |  | #endif  | 
2094  | 0  |         status = U_ILLEGAL_ARGUMENT_ERROR;  | 
2095  | 0  |     }  | 
2096  | 0  | }  | 
2097  |  |  | 
2098  |  | void Calendar::add(EDateFields field, int32_t amount, UErrorCode& status)  | 
2099  | 0  | { | 
2100  | 0  |     Calendar::add((UCalendarDateFields)field, amount, status);  | 
2101  | 0  | }  | 
2102  |  |  | 
2103  |  | // -------------------------------------  | 
2104  |  | void Calendar::add(UCalendarDateFields field, int32_t amount, UErrorCode& status)  | 
2105  | 0  | { | 
2106  | 0  |     if (amount == 0) { | 
2107  | 0  |         return;   // Do nothing!  | 
2108  | 0  |     }  | 
2109  |  |  | 
2110  |  |     // We handle most fields in the same way.  The algorithm is to add  | 
2111  |  |     // a computed amount of millis to the current millis.  The only  | 
2112  |  |     // wrinkle is with DST (and/or a change to the zone's UTC offset, which  | 
2113  |  |     // we'll include with DST) -- for some fields, like the DAY_OF_MONTH,  | 
2114  |  |     // we don't want the wall time to shift due to changes in DST.  If the  | 
2115  |  |     // result of the add operation is to move from DST to Standard, or  | 
2116  |  |     // vice versa, we need to adjust by an hour forward or back,  | 
2117  |  |     // respectively.  For such fields we set keepWallTimeInvariant to TRUE.  | 
2118  |  |  | 
2119  |  |     // We only adjust the DST for fields larger than an hour.  For  | 
2120  |  |     // fields smaller than an hour, we cannot adjust for DST without  | 
2121  |  |     // causing problems.  for instance, if you add one hour to April 5,  | 
2122  |  |     // 1998, 1:00 AM, in PST, the time becomes "2:00 AM PDT" (an  | 
2123  |  |     // illegal value), but then the adjustment sees the change and  | 
2124  |  |     // compensates by subtracting an hour.  As a result the time  | 
2125  |  |     // doesn't advance at all.  | 
2126  |  |  | 
2127  |  |     // For some fields larger than a day, such as a UCAL_MONTH, we pin the  | 
2128  |  |     // UCAL_DAY_OF_MONTH.  This allows <March 31>.add(UCAL_MONTH, 1) to be  | 
2129  |  |     // <April 30>, rather than <April 31> => <May 1>.  | 
2130  |  |  | 
2131  | 0  |     double delta = amount; // delta in ms  | 
2132  | 0  |     UBool keepWallTimeInvariant = TRUE;  | 
2133  |  | 
  | 
2134  | 0  |     switch (field) { | 
2135  | 0  |     case UCAL_ERA:  | 
2136  | 0  |         set(field, get(field, status) + amount);  | 
2137  | 0  |         pinField(UCAL_ERA, status);  | 
2138  | 0  |         return;  | 
2139  |  |  | 
2140  | 0  |     case UCAL_YEAR:  | 
2141  | 0  |     case UCAL_YEAR_WOY:  | 
2142  | 0  |       { | 
2143  |  |         // * If era=0 and years go backwards in time, change sign of amount.  | 
2144  |  |         // * Until we have new API per #9393, we temporarily hardcode knowledge of  | 
2145  |  |         //   which calendars have era 0 years that go backwards.  | 
2146  |  |         // * Note that for UCAL_YEAR (but not UCAL_YEAR_WOY) we could instead handle  | 
2147  |  |         //   this by applying the amount to the UCAL_EXTENDED_YEAR field; but since  | 
2148  |  |         //   we would still need to handle UCAL_YEAR_WOY as below, might as well  | 
2149  |  |         //   also handle UCAL_YEAR the same way.  | 
2150  | 0  |         int32_t era = get(UCAL_ERA, status);  | 
2151  | 0  |         if (era == 0) { | 
2152  | 0  |           const char * calType = getType();  | 
2153  | 0  |           if ( uprv_strcmp(calType,"gregorian")==0 || uprv_strcmp(calType,"roc")==0 || uprv_strcmp(calType,"coptic")==0 ) { | 
2154  | 0  |             amount = -amount;  | 
2155  | 0  |           }  | 
2156  | 0  |         }  | 
2157  | 0  |       }  | 
2158  |  |       // Fall through into normal handling  | 
2159  | 0  |       U_FALLTHROUGH;  | 
2160  | 0  |     case UCAL_EXTENDED_YEAR:  | 
2161  | 0  |     case UCAL_MONTH:  | 
2162  | 0  |       { | 
2163  | 0  |         UBool oldLenient = isLenient();  | 
2164  | 0  |         setLenient(TRUE);  | 
2165  | 0  |         set(field, get(field, status) + amount);  | 
2166  | 0  |         pinField(UCAL_DAY_OF_MONTH, status);  | 
2167  | 0  |         if(oldLenient==FALSE) { | 
2168  | 0  |           complete(status); /* force recalculate */  | 
2169  | 0  |           setLenient(oldLenient);  | 
2170  | 0  |         }  | 
2171  | 0  |       }  | 
2172  | 0  |       return;  | 
2173  |  |  | 
2174  | 0  |     case UCAL_WEEK_OF_YEAR:  | 
2175  | 0  |     case UCAL_WEEK_OF_MONTH:  | 
2176  | 0  |     case UCAL_DAY_OF_WEEK_IN_MONTH:  | 
2177  | 0  |         delta *= kOneWeek;  | 
2178  | 0  |         break;  | 
2179  |  |  | 
2180  | 0  |     case UCAL_AM_PM:  | 
2181  | 0  |         delta *= 12 * kOneHour;  | 
2182  | 0  |         break;  | 
2183  |  |  | 
2184  | 0  |     case UCAL_DAY_OF_MONTH:  | 
2185  | 0  |     case UCAL_DAY_OF_YEAR:  | 
2186  | 0  |     case UCAL_DAY_OF_WEEK:  | 
2187  | 0  |     case UCAL_DOW_LOCAL:  | 
2188  | 0  |     case UCAL_JULIAN_DAY:  | 
2189  | 0  |         delta *= kOneDay;  | 
2190  | 0  |         break;  | 
2191  |  |  | 
2192  | 0  |     case UCAL_HOUR_OF_DAY:  | 
2193  | 0  |     case UCAL_HOUR:  | 
2194  | 0  |         delta *= kOneHour;  | 
2195  | 0  |         keepWallTimeInvariant = FALSE;  | 
2196  | 0  |         break;  | 
2197  |  |  | 
2198  | 0  |     case UCAL_MINUTE:  | 
2199  | 0  |         delta *= kOneMinute;  | 
2200  | 0  |         keepWallTimeInvariant = FALSE;  | 
2201  | 0  |         break;  | 
2202  |  |  | 
2203  | 0  |     case UCAL_SECOND:  | 
2204  | 0  |         delta *= kOneSecond;  | 
2205  | 0  |         keepWallTimeInvariant = FALSE;  | 
2206  | 0  |         break;  | 
2207  |  |  | 
2208  | 0  |     case UCAL_MILLISECOND:  | 
2209  | 0  |     case UCAL_MILLISECONDS_IN_DAY:  | 
2210  | 0  |         keepWallTimeInvariant = FALSE;  | 
2211  | 0  |         break;  | 
2212  |  |  | 
2213  | 0  |     default:  | 
2214  |  | #if defined (U_DEBUG_CAL)  | 
2215  |  |         fprintf(stderr, "%s:%d: ILLEGAL ARG because field %s not addable",  | 
2216  |  |             __FILE__, __LINE__, fldName(field));  | 
2217  |  | #endif  | 
2218  | 0  |         status = U_ILLEGAL_ARGUMENT_ERROR;  | 
2219  | 0  |         return;  | 
2220  |  |         //  throw new IllegalArgumentException("Calendar.add(" + fieldName(field) + | 
2221  |  |         //                                     ") not supported");  | 
2222  | 0  |     }  | 
2223  |  |  | 
2224  |  |     // In order to keep the wall time invariant (for fields where this is  | 
2225  |  |     // appropriate), check the combined DST & ZONE offset before and  | 
2226  |  |     // after the add() operation. If it changes, then adjust the millis  | 
2227  |  |     // to compensate.  | 
2228  | 0  |     int32_t prevOffset = 0;  | 
2229  | 0  |     int32_t prevWallTime = 0;  | 
2230  | 0  |     if (keepWallTimeInvariant) { | 
2231  | 0  |         prevOffset = get(UCAL_DST_OFFSET, status) + get(UCAL_ZONE_OFFSET, status);  | 
2232  | 0  |         prevWallTime = get(UCAL_MILLISECONDS_IN_DAY, status);  | 
2233  | 0  |     }  | 
2234  |  | 
  | 
2235  | 0  |     setTimeInMillis(getTimeInMillis(status) + delta, status);  | 
2236  |  | 
  | 
2237  | 0  |     if (keepWallTimeInvariant) { | 
2238  | 0  |         int32_t newWallTime = get(UCAL_MILLISECONDS_IN_DAY, status);  | 
2239  | 0  |         if (newWallTime != prevWallTime) { | 
2240  |  |             // There is at least one zone transition between the base  | 
2241  |  |             // time and the result time. As the result, wall time has  | 
2242  |  |             // changed.  | 
2243  | 0  |             UDate t = internalGetTime();  | 
2244  | 0  |             int32_t newOffset = get(UCAL_DST_OFFSET, status) + get(UCAL_ZONE_OFFSET, status);  | 
2245  | 0  |             if (newOffset != prevOffset) { | 
2246  |  |                 // When the difference of the previous UTC offset and  | 
2247  |  |                 // the new UTC offset exceeds 1 full day, we do not want  | 
2248  |  |                 // to roll over/back the date. For now, this only happens  | 
2249  |  |                 // in Samoa (Pacific/Apia) on Dec 30, 2011. See ticket:9452.  | 
2250  | 0  |                 int32_t adjAmount = prevOffset - newOffset;  | 
2251  | 0  |                 adjAmount = adjAmount >= 0 ? adjAmount % (int32_t)kOneDay : -(-adjAmount % (int32_t)kOneDay);  | 
2252  | 0  |                 if (adjAmount != 0) { | 
2253  | 0  |                     setTimeInMillis(t + adjAmount, status);  | 
2254  | 0  |                     newWallTime = get(UCAL_MILLISECONDS_IN_DAY, status);  | 
2255  | 0  |                 }  | 
2256  | 0  |                 if (newWallTime != prevWallTime) { | 
2257  |  |                     // The result wall time or adjusted wall time was shifted because  | 
2258  |  |                     // the target wall time does not exist on the result date.  | 
2259  | 0  |                     switch (fSkippedWallTime) { | 
2260  | 0  |                     case UCAL_WALLTIME_FIRST:  | 
2261  | 0  |                         if (adjAmount > 0) { | 
2262  | 0  |                             setTimeInMillis(t, status);  | 
2263  | 0  |                         }  | 
2264  | 0  |                         break;  | 
2265  | 0  |                     case UCAL_WALLTIME_LAST:  | 
2266  | 0  |                         if (adjAmount < 0) { | 
2267  | 0  |                             setTimeInMillis(t, status);  | 
2268  | 0  |                         }  | 
2269  | 0  |                         break;  | 
2270  | 0  |                     case UCAL_WALLTIME_NEXT_VALID:  | 
2271  | 0  |                         UDate tmpT = adjAmount > 0 ? internalGetTime() : t;  | 
2272  | 0  |                         UDate immediatePrevTrans;  | 
2273  | 0  |                         UBool hasTransition = getImmediatePreviousZoneTransition(tmpT, &immediatePrevTrans, status);  | 
2274  | 0  |                         if (U_SUCCESS(status) && hasTransition) { | 
2275  | 0  |                             setTimeInMillis(immediatePrevTrans, status);  | 
2276  | 0  |                         }  | 
2277  | 0  |                         break;  | 
2278  | 0  |                     }  | 
2279  | 0  |                 }  | 
2280  | 0  |             }  | 
2281  | 0  |         }  | 
2282  | 0  |     }  | 
2283  | 0  | }  | 
2284  |  |  | 
2285  |  | // -------------------------------------  | 
2286  | 0  | int32_t Calendar::fieldDifference(UDate when, EDateFields field, UErrorCode& status) { | 
2287  | 0  |     return fieldDifference(when, (UCalendarDateFields) field, status);  | 
2288  | 0  | }  | 
2289  |  |  | 
2290  | 0  | int32_t Calendar::fieldDifference(UDate targetMs, UCalendarDateFields field, UErrorCode& ec) { | 
2291  | 0  |     if (U_FAILURE(ec)) return 0;  | 
2292  | 0  |     int32_t min = 0;  | 
2293  | 0  |     double startMs = getTimeInMillis(ec);  | 
2294  |  |     // Always add from the start millis.  This accommodates  | 
2295  |  |     // operations like adding years from February 29, 2000 up to  | 
2296  |  |     // February 29, 2004.  If 1, 1, 1, 1 is added to the year  | 
2297  |  |     // field, the DOM gets pinned to 28 and stays there, giving an  | 
2298  |  |     // incorrect DOM difference of 1.  We have to add 1, reset, 2,  | 
2299  |  |     // reset, 3, reset, 4.  | 
2300  | 0  |     if (startMs < targetMs) { | 
2301  | 0  |         int32_t max = 1;  | 
2302  |  |         // Find a value that is too large  | 
2303  | 0  |         while (U_SUCCESS(ec)) { | 
2304  | 0  |             setTimeInMillis(startMs, ec);  | 
2305  | 0  |             add(field, max, ec);  | 
2306  | 0  |             double ms = getTimeInMillis(ec);  | 
2307  | 0  |             if (ms == targetMs) { | 
2308  | 0  |                 return max;  | 
2309  | 0  |             } else if (ms > targetMs) { | 
2310  | 0  |                 break;  | 
2311  | 0  |             } else if (max < INT32_MAX) { | 
2312  | 0  |                 min = max;  | 
2313  | 0  |                 max <<= 1;  | 
2314  | 0  |                 if (max < 0) { | 
2315  | 0  |                     max = INT32_MAX;  | 
2316  | 0  |                 }  | 
2317  | 0  |             } else { | 
2318  |  |                 // Field difference too large to fit into int32_t  | 
2319  |  | #if defined (U_DEBUG_CAL)  | 
2320  |  |                 fprintf(stderr, "%s:%d: ILLEGAL ARG because field %s's max too large for int32_t\n",  | 
2321  |  |                     __FILE__, __LINE__, fldName(field));  | 
2322  |  | #endif  | 
2323  | 0  |                 ec = U_ILLEGAL_ARGUMENT_ERROR;  | 
2324  | 0  |             }  | 
2325  | 0  |         }  | 
2326  |  |         // Do a binary search  | 
2327  | 0  |         while ((max - min) > 1 && U_SUCCESS(ec)) { | 
2328  | 0  |             int32_t t = min + (max - min)/2; // make sure intermediate values don't exceed INT32_MAX  | 
2329  | 0  |             setTimeInMillis(startMs, ec);  | 
2330  | 0  |             add(field, t, ec);  | 
2331  | 0  |             double ms = getTimeInMillis(ec);  | 
2332  | 0  |             if (ms == targetMs) { | 
2333  | 0  |                 return t;  | 
2334  | 0  |             } else if (ms > targetMs) { | 
2335  | 0  |                 max = t;  | 
2336  | 0  |             } else { | 
2337  | 0  |                 min = t;  | 
2338  | 0  |             }  | 
2339  | 0  |         }  | 
2340  | 0  |     } else if (startMs > targetMs) { | 
2341  | 0  |         int32_t max = -1;  | 
2342  |  |         // Find a value that is too small  | 
2343  | 0  |         while (U_SUCCESS(ec)) { | 
2344  | 0  |             setTimeInMillis(startMs, ec);  | 
2345  | 0  |             add(field, max, ec);  | 
2346  | 0  |             double ms = getTimeInMillis(ec);  | 
2347  | 0  |             if (ms == targetMs) { | 
2348  | 0  |                 return max;  | 
2349  | 0  |             } else if (ms < targetMs) { | 
2350  | 0  |                 break;  | 
2351  | 0  |             } else { | 
2352  | 0  |                 min = max;  | 
2353  | 0  |                 max <<= 1;  | 
2354  | 0  |                 if (max == 0) { | 
2355  |  |                     // Field difference too large to fit into int32_t  | 
2356  |  | #if defined (U_DEBUG_CAL)  | 
2357  |  |                     fprintf(stderr, "%s:%d: ILLEGAL ARG because field %s's max too large for int32_t\n",  | 
2358  |  |                         __FILE__, __LINE__, fldName(field));  | 
2359  |  | #endif  | 
2360  | 0  |                     ec = U_ILLEGAL_ARGUMENT_ERROR;  | 
2361  | 0  |                 }  | 
2362  | 0  |             }  | 
2363  | 0  |         }  | 
2364  |  |         // Do a binary search  | 
2365  | 0  |         while ((min - max) > 1 && U_SUCCESS(ec)) { | 
2366  | 0  |             int32_t t = min + (max - min)/2; // make sure intermediate values don't exceed INT32_MAX  | 
2367  | 0  |             setTimeInMillis(startMs, ec);  | 
2368  | 0  |             add(field, t, ec);  | 
2369  | 0  |             double ms = getTimeInMillis(ec);  | 
2370  | 0  |             if (ms == targetMs) { | 
2371  | 0  |                 return t;  | 
2372  | 0  |             } else if (ms < targetMs) { | 
2373  | 0  |                 max = t;  | 
2374  | 0  |             } else { | 
2375  | 0  |                 min = t;  | 
2376  | 0  |             }  | 
2377  | 0  |         }  | 
2378  | 0  |     }  | 
2379  |  |     // Set calendar to end point  | 
2380  | 0  |     setTimeInMillis(startMs, ec);  | 
2381  | 0  |     add(field, min, ec);  | 
2382  |  |  | 
2383  |  |     /* Test for buffer overflows */  | 
2384  | 0  |     if(U_FAILURE(ec)) { | 
2385  | 0  |         return 0;  | 
2386  | 0  |     }  | 
2387  | 0  |     return min;  | 
2388  | 0  | }  | 
2389  |  |  | 
2390  |  | // -------------------------------------  | 
2391  |  |  | 
2392  |  | void  | 
2393  |  | Calendar::adoptTimeZone(TimeZone* zone)  | 
2394  | 0  | { | 
2395  |  |     // Do nothing if passed-in zone is NULL  | 
2396  | 0  |     if (zone == NULL) return;  | 
2397  |  |  | 
2398  |  |     // fZone should always be non-null  | 
2399  | 0  |     delete fZone;  | 
2400  | 0  |     fZone = zone;  | 
2401  |  |  | 
2402  |  |     // if the zone changes, we need to recompute the time fields  | 
2403  | 0  |     fAreFieldsSet = FALSE;  | 
2404  | 0  | }  | 
2405  |  |  | 
2406  |  | // -------------------------------------  | 
2407  |  | void  | 
2408  |  | Calendar::setTimeZone(const TimeZone& zone)  | 
2409  | 0  | { | 
2410  | 0  |     adoptTimeZone(zone.clone());  | 
2411  | 0  | }  | 
2412  |  |  | 
2413  |  | // -------------------------------------  | 
2414  |  |  | 
2415  |  | const TimeZone&  | 
2416  |  | Calendar::getTimeZone() const  | 
2417  | 0  | { | 
2418  | 0  |     U_ASSERT(fZone != NULL);  | 
2419  | 0  |     return *fZone;  | 
2420  | 0  | }  | 
2421  |  |  | 
2422  |  | // -------------------------------------  | 
2423  |  |  | 
2424  |  | TimeZone*  | 
2425  |  | Calendar::orphanTimeZone()  | 
2426  | 0  | { | 
2427  |  |     // we let go of the time zone; the new time zone is the system default time zone  | 
2428  | 0  |     TimeZone *defaultZone = TimeZone::createDefault();  | 
2429  | 0  |     if (defaultZone == NULL) { | 
2430  |  |         // No error handling available. Must keep fZone non-NULL, there are many unchecked uses.  | 
2431  | 0  |         return NULL;  | 
2432  | 0  |     }  | 
2433  | 0  |     TimeZone *z = fZone;  | 
2434  | 0  |     fZone = defaultZone;  | 
2435  | 0  |     return z;  | 
2436  | 0  | }  | 
2437  |  |  | 
2438  |  | // -------------------------------------  | 
2439  |  |  | 
2440  |  | void  | 
2441  |  | Calendar::setLenient(UBool lenient)  | 
2442  | 0  | { | 
2443  | 0  |     fLenient = lenient;  | 
2444  | 0  | }  | 
2445  |  |  | 
2446  |  | // -------------------------------------  | 
2447  |  |  | 
2448  |  | UBool  | 
2449  |  | Calendar::isLenient() const  | 
2450  | 0  | { | 
2451  | 0  |     return fLenient;  | 
2452  | 0  | }  | 
2453  |  |  | 
2454  |  | // -------------------------------------  | 
2455  |  |  | 
2456  |  | void  | 
2457  |  | Calendar::setRepeatedWallTimeOption(UCalendarWallTimeOption option)  | 
2458  | 0  | { | 
2459  | 0  |     if (option == UCAL_WALLTIME_LAST || option == UCAL_WALLTIME_FIRST) { | 
2460  | 0  |         fRepeatedWallTime = option;  | 
2461  | 0  |     }  | 
2462  | 0  | }  | 
2463  |  |  | 
2464  |  | // -------------------------------------  | 
2465  |  |  | 
2466  |  | UCalendarWallTimeOption  | 
2467  |  | Calendar::getRepeatedWallTimeOption(void) const  | 
2468  | 0  | { | 
2469  | 0  |     return fRepeatedWallTime;  | 
2470  | 0  | }  | 
2471  |  |  | 
2472  |  | // -------------------------------------  | 
2473  |  |  | 
2474  |  | void  | 
2475  |  | Calendar::setSkippedWallTimeOption(UCalendarWallTimeOption option)  | 
2476  | 0  | { | 
2477  | 0  |     fSkippedWallTime = option;  | 
2478  | 0  | }  | 
2479  |  |  | 
2480  |  | // -------------------------------------  | 
2481  |  |  | 
2482  |  | UCalendarWallTimeOption  | 
2483  |  | Calendar::getSkippedWallTimeOption(void) const  | 
2484  | 0  | { | 
2485  | 0  |     return fSkippedWallTime;  | 
2486  | 0  | }  | 
2487  |  |  | 
2488  |  | // -------------------------------------  | 
2489  |  |  | 
2490  |  | void  | 
2491  |  | Calendar::setFirstDayOfWeek(UCalendarDaysOfWeek value)  | 
2492  | 0  | { | 
2493  | 0  |     if (fFirstDayOfWeek != value &&  | 
2494  | 0  |         value >= UCAL_SUNDAY && value <= UCAL_SATURDAY) { | 
2495  | 0  |             fFirstDayOfWeek = value;  | 
2496  | 0  |             fAreFieldsSet = FALSE;  | 
2497  | 0  |         }  | 
2498  | 0  | }  | 
2499  |  |  | 
2500  |  | // -------------------------------------  | 
2501  |  |  | 
2502  |  | Calendar::EDaysOfWeek  | 
2503  |  | Calendar::getFirstDayOfWeek() const  | 
2504  | 0  | { | 
2505  | 0  |     return (Calendar::EDaysOfWeek)fFirstDayOfWeek;  | 
2506  | 0  | }  | 
2507  |  |  | 
2508  |  | UCalendarDaysOfWeek  | 
2509  |  | Calendar::getFirstDayOfWeek(UErrorCode & /*status*/) const  | 
2510  | 0  | { | 
2511  | 0  |     return fFirstDayOfWeek;  | 
2512  | 0  | }  | 
2513  |  | // -------------------------------------  | 
2514  |  |  | 
2515  |  | void  | 
2516  |  | Calendar::setMinimalDaysInFirstWeek(uint8_t value)  | 
2517  | 0  | { | 
2518  |  |     // Values less than 1 have the same effect as 1; values greater  | 
2519  |  |     // than 7 have the same effect as 7. However, we normalize values  | 
2520  |  |     // so operator== and so forth work.  | 
2521  | 0  |     if (value < 1) { | 
2522  | 0  |         value = 1;  | 
2523  | 0  |     } else if (value > 7) { | 
2524  | 0  |         value = 7;  | 
2525  | 0  |     }  | 
2526  | 0  |     if (fMinimalDaysInFirstWeek != value) { | 
2527  | 0  |         fMinimalDaysInFirstWeek = value;  | 
2528  | 0  |         fAreFieldsSet = FALSE;  | 
2529  | 0  |     }  | 
2530  | 0  | }  | 
2531  |  |  | 
2532  |  | // -------------------------------------  | 
2533  |  |  | 
2534  |  | uint8_t  | 
2535  |  | Calendar::getMinimalDaysInFirstWeek() const  | 
2536  | 0  | { | 
2537  | 0  |     return fMinimalDaysInFirstWeek;  | 
2538  | 0  | }  | 
2539  |  |  | 
2540  |  | // -------------------------------------  | 
2541  |  | // weekend functions, just dummy implementations for now (for API freeze)  | 
2542  |  |  | 
2543  |  | UCalendarWeekdayType  | 
2544  |  | Calendar::getDayOfWeekType(UCalendarDaysOfWeek dayOfWeek, UErrorCode &status) const  | 
2545  | 0  | { | 
2546  | 0  |     if (U_FAILURE(status)) { | 
2547  | 0  |         return UCAL_WEEKDAY;  | 
2548  | 0  |     }  | 
2549  | 0  |     if (dayOfWeek < UCAL_SUNDAY || dayOfWeek > UCAL_SATURDAY) { | 
2550  | 0  |         status = U_ILLEGAL_ARGUMENT_ERROR;  | 
2551  | 0  |         return UCAL_WEEKDAY;  | 
2552  | 0  |     }  | 
2553  | 0  |     if (fWeekendOnset == fWeekendCease) { | 
2554  | 0  |         if (dayOfWeek != fWeekendOnset)  | 
2555  | 0  |             return UCAL_WEEKDAY;  | 
2556  | 0  |         return (fWeekendOnsetMillis == 0) ? UCAL_WEEKEND : UCAL_WEEKEND_ONSET;  | 
2557  | 0  |     }  | 
2558  | 0  |     if (fWeekendOnset < fWeekendCease) { | 
2559  | 0  |         if (dayOfWeek < fWeekendOnset || dayOfWeek > fWeekendCease) { | 
2560  | 0  |             return UCAL_WEEKDAY;  | 
2561  | 0  |         }  | 
2562  | 0  |     } else { | 
2563  | 0  |         if (dayOfWeek > fWeekendCease && dayOfWeek < fWeekendOnset) { | 
2564  | 0  |             return UCAL_WEEKDAY;  | 
2565  | 0  |         }  | 
2566  | 0  |     }  | 
2567  | 0  |     if (dayOfWeek == fWeekendOnset) { | 
2568  | 0  |         return (fWeekendOnsetMillis == 0) ? UCAL_WEEKEND : UCAL_WEEKEND_ONSET;  | 
2569  | 0  |     }  | 
2570  | 0  |     if (dayOfWeek == fWeekendCease) { | 
2571  | 0  |         return (fWeekendCeaseMillis >= 86400000) ? UCAL_WEEKEND : UCAL_WEEKEND_CEASE;  | 
2572  | 0  |     }  | 
2573  | 0  |     return UCAL_WEEKEND;  | 
2574  | 0  | }  | 
2575  |  |  | 
2576  |  | int32_t  | 
2577  |  | Calendar::getWeekendTransition(UCalendarDaysOfWeek dayOfWeek, UErrorCode &status) const  | 
2578  | 0  | { | 
2579  | 0  |     if (U_FAILURE(status)) { | 
2580  | 0  |         return 0;  | 
2581  | 0  |     }  | 
2582  | 0  |     if (dayOfWeek == fWeekendOnset) { | 
2583  | 0  |         return fWeekendOnsetMillis;  | 
2584  | 0  |     } else if (dayOfWeek == fWeekendCease) { | 
2585  | 0  |         return fWeekendCeaseMillis;  | 
2586  | 0  |     }  | 
2587  | 0  |     status = U_ILLEGAL_ARGUMENT_ERROR;  | 
2588  | 0  |     return 0;  | 
2589  | 0  | }  | 
2590  |  |  | 
2591  |  | UBool  | 
2592  |  | Calendar::isWeekend(UDate date, UErrorCode &status) const  | 
2593  | 0  | { | 
2594  | 0  |     if (U_FAILURE(status)) { | 
2595  | 0  |         return FALSE;  | 
2596  | 0  |     }  | 
2597  |  |     // clone the calendar so we don't mess with the real one.  | 
2598  | 0  |     Calendar *work = this->clone();  | 
2599  | 0  |     if (work == NULL) { | 
2600  | 0  |         status = U_MEMORY_ALLOCATION_ERROR;  | 
2601  | 0  |         return FALSE;  | 
2602  | 0  |     }  | 
2603  | 0  |     UBool result = FALSE;  | 
2604  | 0  |     work->setTime(date, status);  | 
2605  | 0  |     if (U_SUCCESS(status)) { | 
2606  | 0  |         result = work->isWeekend();  | 
2607  | 0  |     }  | 
2608  | 0  |     delete work;  | 
2609  | 0  |     return result;  | 
2610  | 0  | }  | 
2611  |  |  | 
2612  |  | UBool  | 
2613  |  | Calendar::isWeekend(void) const  | 
2614  | 0  | { | 
2615  | 0  |     UErrorCode status = U_ZERO_ERROR;  | 
2616  | 0  |     UCalendarDaysOfWeek dayOfWeek = (UCalendarDaysOfWeek)get(UCAL_DAY_OF_WEEK, status);  | 
2617  | 0  |     UCalendarWeekdayType dayType = getDayOfWeekType(dayOfWeek, status);  | 
2618  | 0  |     if (U_SUCCESS(status)) { | 
2619  | 0  |         switch (dayType) { | 
2620  | 0  |             case UCAL_WEEKDAY:  | 
2621  | 0  |                 return FALSE;  | 
2622  | 0  |             case UCAL_WEEKEND:  | 
2623  | 0  |                 return TRUE;  | 
2624  | 0  |             case UCAL_WEEKEND_ONSET:  | 
2625  | 0  |             case UCAL_WEEKEND_CEASE:  | 
2626  |  |                 // Use internalGet() because the above call to get() populated all fields.  | 
2627  | 0  |                 { | 
2628  | 0  |                     int32_t millisInDay = internalGet(UCAL_MILLISECONDS_IN_DAY);  | 
2629  | 0  |                     int32_t transitionMillis = getWeekendTransition(dayOfWeek, status);  | 
2630  | 0  |                     if (U_SUCCESS(status)) { | 
2631  | 0  |                         return (dayType == UCAL_WEEKEND_ONSET)?  | 
2632  | 0  |                             (millisInDay >= transitionMillis):  | 
2633  | 0  |                             (millisInDay <  transitionMillis);  | 
2634  | 0  |                     }  | 
2635  |  |                     // else fall through, return FALSE  | 
2636  | 0  |                     U_FALLTHROUGH;  | 
2637  | 0  |                 }  | 
2638  | 0  |             default:  | 
2639  | 0  |                 break;  | 
2640  | 0  |         }  | 
2641  | 0  |     }  | 
2642  | 0  |     return FALSE;  | 
2643  | 0  | }  | 
2644  |  |  | 
2645  |  | // ------------------------------------- limits  | 
2646  |  |  | 
2647  |  | int32_t  | 
2648  | 0  | Calendar::getMinimum(EDateFields field) const { | 
2649  | 0  |     return getLimit((UCalendarDateFields) field,UCAL_LIMIT_MINIMUM);  | 
2650  | 0  | }  | 
2651  |  |  | 
2652  |  | int32_t  | 
2653  |  | Calendar::getMinimum(UCalendarDateFields field) const  | 
2654  | 0  | { | 
2655  | 0  |     return getLimit(field,UCAL_LIMIT_MINIMUM);  | 
2656  | 0  | }  | 
2657  |  |  | 
2658  |  | // -------------------------------------  | 
2659  |  | int32_t  | 
2660  |  | Calendar::getMaximum(EDateFields field) const  | 
2661  | 0  | { | 
2662  | 0  |     return getLimit((UCalendarDateFields) field,UCAL_LIMIT_MAXIMUM);  | 
2663  | 0  | }  | 
2664  |  |  | 
2665  |  | int32_t  | 
2666  |  | Calendar::getMaximum(UCalendarDateFields field) const  | 
2667  | 0  | { | 
2668  | 0  |     return getLimit(field,UCAL_LIMIT_MAXIMUM);  | 
2669  | 0  | }  | 
2670  |  |  | 
2671  |  | // -------------------------------------  | 
2672  |  | int32_t  | 
2673  |  | Calendar::getGreatestMinimum(EDateFields field) const  | 
2674  | 0  | { | 
2675  | 0  |     return getLimit((UCalendarDateFields)field,UCAL_LIMIT_GREATEST_MINIMUM);  | 
2676  | 0  | }  | 
2677  |  |  | 
2678  |  | int32_t  | 
2679  |  | Calendar::getGreatestMinimum(UCalendarDateFields field) const  | 
2680  | 0  | { | 
2681  | 0  |     return getLimit(field,UCAL_LIMIT_GREATEST_MINIMUM);  | 
2682  | 0  | }  | 
2683  |  |  | 
2684  |  | // -------------------------------------  | 
2685  |  | int32_t  | 
2686  |  | Calendar::getLeastMaximum(EDateFields field) const  | 
2687  | 0  | { | 
2688  | 0  |     return getLimit((UCalendarDateFields) field,UCAL_LIMIT_LEAST_MAXIMUM);  | 
2689  | 0  | }  | 
2690  |  |  | 
2691  |  | int32_t  | 
2692  |  | Calendar::getLeastMaximum(UCalendarDateFields field) const  | 
2693  | 0  | { | 
2694  | 0  |     return getLimit( field,UCAL_LIMIT_LEAST_MAXIMUM);  | 
2695  | 0  | }  | 
2696  |  |  | 
2697  |  | // -------------------------------------  | 
2698  |  | int32_t  | 
2699  |  | Calendar::getActualMinimum(EDateFields field, UErrorCode& status) const  | 
2700  | 0  | { | 
2701  | 0  |     return getActualMinimum((UCalendarDateFields) field, status);  | 
2702  | 0  | }  | 
2703  |  |  | 
2704  | 0  | int32_t Calendar::getLimit(UCalendarDateFields field, ELimitType limitType) const { | 
2705  | 0  |     switch (field) { | 
2706  | 0  |     case UCAL_DAY_OF_WEEK:  | 
2707  | 0  |     case UCAL_AM_PM:  | 
2708  | 0  |     case UCAL_HOUR:  | 
2709  | 0  |     case UCAL_HOUR_OF_DAY:  | 
2710  | 0  |     case UCAL_MINUTE:  | 
2711  | 0  |     case UCAL_SECOND:  | 
2712  | 0  |     case UCAL_MILLISECOND:  | 
2713  | 0  |     case UCAL_ZONE_OFFSET:  | 
2714  | 0  |     case UCAL_DST_OFFSET:  | 
2715  | 0  |     case UCAL_DOW_LOCAL:  | 
2716  | 0  |     case UCAL_JULIAN_DAY:  | 
2717  | 0  |     case UCAL_MILLISECONDS_IN_DAY:  | 
2718  | 0  |     case UCAL_IS_LEAP_MONTH:  | 
2719  | 0  |         return kCalendarLimits[field][limitType];  | 
2720  |  |  | 
2721  | 0  |     case UCAL_WEEK_OF_MONTH:  | 
2722  | 0  |         { | 
2723  | 0  |             int32_t limit;  | 
2724  | 0  |             if (limitType == UCAL_LIMIT_MINIMUM) { | 
2725  | 0  |                 limit = getMinimalDaysInFirstWeek() == 1 ? 1 : 0;  | 
2726  | 0  |             } else if (limitType == UCAL_LIMIT_GREATEST_MINIMUM) { | 
2727  | 0  |                 limit = 1;  | 
2728  | 0  |             } else { | 
2729  | 0  |                 int32_t minDaysInFirst = getMinimalDaysInFirstWeek();  | 
2730  | 0  |                 int32_t daysInMonth = handleGetLimit(UCAL_DAY_OF_MONTH, limitType);  | 
2731  | 0  |                 if (limitType == UCAL_LIMIT_LEAST_MAXIMUM) { | 
2732  | 0  |                     limit = (daysInMonth + (7 - minDaysInFirst)) / 7;  | 
2733  | 0  |                 } else { // limitType == UCAL_LIMIT_MAXIMUM | 
2734  | 0  |                     limit = (daysInMonth + 6 + (7 - minDaysInFirst)) / 7;  | 
2735  | 0  |                 }  | 
2736  | 0  |             }  | 
2737  | 0  |             return limit;  | 
2738  | 0  |         }  | 
2739  | 0  |     default:  | 
2740  | 0  |         return handleGetLimit(field, limitType);  | 
2741  | 0  |     }  | 
2742  | 0  | }  | 
2743  |  |  | 
2744  |  |  | 
2745  |  | int32_t  | 
2746  |  | Calendar::getActualMinimum(UCalendarDateFields field, UErrorCode& status) const  | 
2747  | 0  | { | 
2748  | 0  |     int32_t fieldValue = getGreatestMinimum(field);  | 
2749  | 0  |     int32_t endValue = getMinimum(field);  | 
2750  |  |  | 
2751  |  |     // if we know that the minimum value is always the same, just return it  | 
2752  | 0  |     if (fieldValue == endValue) { | 
2753  | 0  |         return fieldValue;  | 
2754  | 0  |     }  | 
2755  |  |  | 
2756  |  |     // clone the calendar so we don't mess with the real one, and set it to  | 
2757  |  |     // accept anything for the field values  | 
2758  | 0  |     Calendar *work = this->clone();  | 
2759  | 0  |     if (work == NULL) { | 
2760  | 0  |         status = U_MEMORY_ALLOCATION_ERROR;  | 
2761  | 0  |         return 0;  | 
2762  | 0  |     }  | 
2763  | 0  |     work->setLenient(TRUE);  | 
2764  |  |  | 
2765  |  |     // now try each value from getLeastMaximum() to getMaximum() one by one until  | 
2766  |  |     // we get a value that normalizes to another value.  The last value that  | 
2767  |  |     // normalizes to itself is the actual minimum for the current date  | 
2768  | 0  |     int32_t result = fieldValue;  | 
2769  |  | 
  | 
2770  | 0  |     do { | 
2771  | 0  |         work->set(field, fieldValue);  | 
2772  | 0  |         if (work->get(field, status) != fieldValue) { | 
2773  | 0  |             break;  | 
2774  | 0  |         }  | 
2775  | 0  |         else { | 
2776  | 0  |             result = fieldValue;  | 
2777  | 0  |             fieldValue--;  | 
2778  | 0  |         }  | 
2779  | 0  |     } while (fieldValue >= endValue);  | 
2780  |  |  | 
2781  | 0  |     delete work;  | 
2782  |  |  | 
2783  |  |     /* Test for buffer overflows */  | 
2784  | 0  |     if(U_FAILURE(status)) { | 
2785  | 0  |         return 0;  | 
2786  | 0  |     }  | 
2787  | 0  |     return result;  | 
2788  | 0  | }  | 
2789  |  |  | 
2790  |  | // -------------------------------------  | 
2791  |  |  | 
2792  |  |  | 
2793  |  |  | 
2794  |  | /**  | 
2795  |  | * Ensure that each field is within its valid range by calling {@link | 
2796  |  | * #validateField(int)} on each field that has been set.  This method  | 
2797  |  | * should only be called if this calendar is not lenient.  | 
2798  |  | * @see #isLenient  | 
2799  |  | * @see #validateField(int)  | 
2800  |  | */  | 
2801  | 0  | void Calendar::validateFields(UErrorCode &status) { | 
2802  | 0  |     for (int32_t field = 0; U_SUCCESS(status) && (field < UCAL_FIELD_COUNT); field++) { | 
2803  | 0  |         if (fStamp[field] >= kMinimumUserStamp) { | 
2804  | 0  |             validateField((UCalendarDateFields)field, status);  | 
2805  | 0  |         }  | 
2806  | 0  |     }  | 
2807  | 0  | }  | 
2808  |  |  | 
2809  |  | /**  | 
2810  |  | * Validate a single field of this calendar.  Subclasses should  | 
2811  |  | * override this method to validate any calendar-specific fields.  | 
2812  |  | * Generic fields can be handled by  | 
2813  |  | * <code>Calendar.validateField()</code>.  | 
2814  |  | * @see #validateField(int, int, int)  | 
2815  |  | */  | 
2816  | 0  | void Calendar::validateField(UCalendarDateFields field, UErrorCode &status) { | 
2817  | 0  |     int32_t y;  | 
2818  | 0  |     switch (field) { | 
2819  | 0  |     case UCAL_DAY_OF_MONTH:  | 
2820  | 0  |         y = handleGetExtendedYear();  | 
2821  | 0  |         validateField(field, 1, handleGetMonthLength(y, internalGet(UCAL_MONTH)), status);  | 
2822  | 0  |         break;  | 
2823  | 0  |     case UCAL_DAY_OF_YEAR:  | 
2824  | 0  |         y = handleGetExtendedYear();  | 
2825  | 0  |         validateField(field, 1, handleGetYearLength(y), status);  | 
2826  | 0  |         break;  | 
2827  | 0  |     case UCAL_DAY_OF_WEEK_IN_MONTH:  | 
2828  | 0  |         if (internalGet(field) == 0) { | 
2829  |  | #if defined (U_DEBUG_CAL)  | 
2830  |  |             fprintf(stderr, "%s:%d: ILLEGAL ARG because DOW in month cannot be 0\n",  | 
2831  |  |                 __FILE__, __LINE__);  | 
2832  |  | #endif  | 
2833  | 0  |             status = U_ILLEGAL_ARGUMENT_ERROR; // "DAY_OF_WEEK_IN_MONTH cannot be zero"  | 
2834  | 0  |             return;  | 
2835  | 0  |         }  | 
2836  | 0  |         validateField(field, getMinimum(field), getMaximum(field), status);  | 
2837  | 0  |         break;  | 
2838  | 0  |     default:  | 
2839  | 0  |         validateField(field, getMinimum(field), getMaximum(field), status);  | 
2840  | 0  |         break;  | 
2841  | 0  |     }  | 
2842  | 0  | }  | 
2843  |  |  | 
2844  |  | /**  | 
2845  |  | * Validate a single field of this calendar given its minimum and  | 
2846  |  | * maximum allowed value.  If the field is out of range, throw a  | 
2847  |  | * descriptive <code>IllegalArgumentException</code>.  Subclasses may  | 
2848  |  | * use this method in their implementation of {@link | 
2849  |  | * #validateField(int)}.  | 
2850  |  | */  | 
2851  |  | void Calendar::validateField(UCalendarDateFields field, int32_t min, int32_t max, UErrorCode& status)  | 
2852  | 0  | { | 
2853  | 0  |     int32_t value = fFields[field];  | 
2854  | 0  |     if (value < min || value > max) { | 
2855  |  | #if defined (U_DEBUG_CAL)  | 
2856  |  |         fprintf(stderr, "%s:%d: ILLEGAL ARG because of field %s out of range %d..%d  at %d\n",  | 
2857  |  |             __FILE__, __LINE__,fldName(field),min,max,value);  | 
2858  |  | #endif  | 
2859  | 0  |         status = U_ILLEGAL_ARGUMENT_ERROR;  | 
2860  | 0  |         return;  | 
2861  | 0  |     }  | 
2862  | 0  | }  | 
2863  |  |  | 
2864  |  | // -------------------------  | 
2865  |  |  | 
2866  | 0  | const UFieldResolutionTable* Calendar::getFieldResolutionTable() const { | 
2867  | 0  |     return kDatePrecedence;  | 
2868  | 0  | }  | 
2869  |  |  | 
2870  |  |  | 
2871  |  | UCalendarDateFields Calendar::newerField(UCalendarDateFields defaultField, UCalendarDateFields alternateField) const  | 
2872  | 0  | { | 
2873  | 0  |     if (fStamp[alternateField] > fStamp[defaultField]) { | 
2874  | 0  |         return alternateField;  | 
2875  | 0  |     }  | 
2876  | 0  |     return defaultField;  | 
2877  | 0  | }  | 
2878  |  |  | 
2879  | 0  | UCalendarDateFields Calendar::resolveFields(const UFieldResolutionTable* precedenceTable) { | 
2880  | 0  |     int32_t bestField = UCAL_FIELD_COUNT;  | 
2881  | 0  |     int32_t tempBestField;  | 
2882  | 0  |     for (int32_t g=0; precedenceTable[g][0][0] != -1 && (bestField == UCAL_FIELD_COUNT); ++g) { | 
2883  | 0  |         int32_t bestStamp = kUnset;  | 
2884  | 0  |         for (int32_t l=0; precedenceTable[g][l][0] != -1; ++l) { | 
2885  | 0  |             int32_t lineStamp = kUnset;  | 
2886  |  |             // Skip over first entry if it is negative  | 
2887  | 0  |             for (int32_t i=((precedenceTable[g][l][0]>=kResolveRemap)?1:0); precedenceTable[g][l][i]!=-1; ++i) { | 
2888  | 0  |                 U_ASSERT(precedenceTable[g][l][i] < UCAL_FIELD_COUNT);  | 
2889  | 0  |                 int32_t s = fStamp[precedenceTable[g][l][i]];  | 
2890  |  |                 // If any field is unset then don't use this line  | 
2891  | 0  |                 if (s == kUnset) { | 
2892  | 0  |                     goto linesInGroup;  | 
2893  | 0  |                 } else if(s > lineStamp) { | 
2894  | 0  |                     lineStamp = s;  | 
2895  | 0  |                 }  | 
2896  | 0  |             }  | 
2897  |  |             // Record new maximum stamp & field no.  | 
2898  | 0  |             if (lineStamp > bestStamp) { | 
2899  | 0  |                 tempBestField = precedenceTable[g][l][0]; // First field refers to entire line  | 
2900  | 0  |                 if (tempBestField >= kResolveRemap) { | 
2901  | 0  |                     tempBestField &= (kResolveRemap-1);  | 
2902  |  |                     // This check is needed to resolve some issues with UCAL_YEAR precedence mapping  | 
2903  | 0  |                     if (tempBestField != UCAL_DATE || (fStamp[UCAL_WEEK_OF_MONTH] < fStamp[tempBestField])) { | 
2904  | 0  |                         bestField = tempBestField;  | 
2905  | 0  |                     }  | 
2906  | 0  |                 } else { | 
2907  | 0  |                     bestField = tempBestField;  | 
2908  | 0  |                 }  | 
2909  |  | 
  | 
2910  | 0  |                 if (bestField == tempBestField) { | 
2911  | 0  |                     bestStamp = lineStamp;  | 
2912  | 0  |                 }  | 
2913  | 0  |             }  | 
2914  | 0  | linesInGroup:  | 
2915  | 0  |             ;  | 
2916  | 0  |         }  | 
2917  | 0  |     }  | 
2918  | 0  |     return (UCalendarDateFields)bestField;  | 
2919  | 0  | }  | 
2920  |  |  | 
2921  |  | const UFieldResolutionTable Calendar::kDatePrecedence[] =  | 
2922  |  | { | 
2923  |  |     { | 
2924  |  |         { UCAL_DAY_OF_MONTH, kResolveSTOP }, | 
2925  |  |         { UCAL_WEEK_OF_YEAR, UCAL_DAY_OF_WEEK, kResolveSTOP }, | 
2926  |  |         { UCAL_WEEK_OF_MONTH, UCAL_DAY_OF_WEEK, kResolveSTOP }, | 
2927  |  |         { UCAL_DAY_OF_WEEK_IN_MONTH, UCAL_DAY_OF_WEEK, kResolveSTOP }, | 
2928  |  |         { UCAL_WEEK_OF_YEAR, UCAL_DOW_LOCAL, kResolveSTOP }, | 
2929  |  |         { UCAL_WEEK_OF_MONTH, UCAL_DOW_LOCAL, kResolveSTOP }, | 
2930  |  |         { UCAL_DAY_OF_WEEK_IN_MONTH, UCAL_DOW_LOCAL, kResolveSTOP }, | 
2931  |  |         { UCAL_DAY_OF_YEAR, kResolveSTOP }, | 
2932  |  |         { kResolveRemap | UCAL_DAY_OF_MONTH, UCAL_YEAR, kResolveSTOP },  // if YEAR is set over YEAR_WOY use DAY_OF_MONTH | 
2933  |  |         { kResolveRemap | UCAL_WEEK_OF_YEAR, UCAL_YEAR_WOY, kResolveSTOP },  // if YEAR_WOY is set,  calc based on WEEK_OF_YEAR | 
2934  |  |         { kResolveSTOP } | 
2935  |  |     },  | 
2936  |  |     { | 
2937  |  |         { UCAL_WEEK_OF_YEAR, kResolveSTOP }, | 
2938  |  |         { UCAL_WEEK_OF_MONTH, kResolveSTOP }, | 
2939  |  |         { UCAL_DAY_OF_WEEK_IN_MONTH, kResolveSTOP }, | 
2940  |  |         { kResolveRemap | UCAL_DAY_OF_WEEK_IN_MONTH, UCAL_DAY_OF_WEEK, kResolveSTOP }, | 
2941  |  |         { kResolveRemap | UCAL_DAY_OF_WEEK_IN_MONTH, UCAL_DOW_LOCAL, kResolveSTOP }, | 
2942  |  |         { kResolveSTOP } | 
2943  |  |     },  | 
2944  |  |     {{kResolveSTOP}} | 
2945  |  | };  | 
2946  |  |  | 
2947  |  |  | 
2948  |  | const UFieldResolutionTable Calendar::kDOWPrecedence[] =  | 
2949  |  | { | 
2950  |  |     { | 
2951  |  |         { UCAL_DAY_OF_WEEK,kResolveSTOP, kResolveSTOP }, | 
2952  |  |         { UCAL_DOW_LOCAL,kResolveSTOP, kResolveSTOP }, | 
2953  |  |         {kResolveSTOP} | 
2954  |  |     },  | 
2955  |  |     {{kResolveSTOP}} | 
2956  |  | };  | 
2957  |  |  | 
2958  |  | // precedence for calculating a year  | 
2959  |  | const UFieldResolutionTable Calendar::kYearPrecedence[] =  | 
2960  |  | { | 
2961  |  |     { | 
2962  |  |         { UCAL_YEAR, kResolveSTOP }, | 
2963  |  |         { UCAL_EXTENDED_YEAR, kResolveSTOP }, | 
2964  |  |         { UCAL_YEAR_WOY, UCAL_WEEK_OF_YEAR, kResolveSTOP },  // YEAR_WOY is useless without WEEK_OF_YEAR | 
2965  |  |         { kResolveSTOP } | 
2966  |  |     },  | 
2967  |  |     {{kResolveSTOP}} | 
2968  |  | };  | 
2969  |  |  | 
2970  |  |  | 
2971  |  | // -------------------------  | 
2972  |  |  | 
2973  |  |  | 
2974  | 0  | void Calendar::computeTime(UErrorCode& status) { | 
2975  | 0  |     if (!isLenient()) { | 
2976  | 0  |         validateFields(status);  | 
2977  | 0  |         if (U_FAILURE(status)) { | 
2978  | 0  |             return;  | 
2979  | 0  |         }  | 
2980  | 0  |     }  | 
2981  |  |  | 
2982  |  |     // Compute the Julian day  | 
2983  | 0  |     int32_t julianDay = computeJulianDay();  | 
2984  |  | 
  | 
2985  | 0  |     double millis = Grego::julianDayToMillis(julianDay);  | 
2986  |  | 
  | 
2987  |  | #if defined (U_DEBUG_CAL)  | 
2988  |  |     //  int32_t julianInsanityCheck =  (int32_t)ClockMath::floorDivide(millis, kOneDay);  | 
2989  |  |     //  julianInsanityCheck += kEpochStartAsJulianDay;  | 
2990  |  |     //  if(1 || julianInsanityCheck != julianDay) { | 
2991  |  |     //    fprintf(stderr, "%s:%d- D'oh- computed jules %d, to mills (%s)%.lf, recomputed %d\n",  | 
2992  |  |     //            __FILE__, __LINE__, julianDay, millis<0.0?"NEG":"", millis, julianInsanityCheck);  | 
2993  |  |     //  }  | 
2994  |  | #endif  | 
2995  |  | 
  | 
2996  | 0  |     double millisInDay;  | 
2997  |  |  | 
2998  |  |     // We only use MILLISECONDS_IN_DAY if it has been set by the user.  | 
2999  |  |     // This makes it possible for the caller to set the calendar to a  | 
3000  |  |     // time and call clear(MONTH) to reset the MONTH to January.  This  | 
3001  |  |     // is legacy behavior.  Without this, clear(MONTH) has no effect,  | 
3002  |  |     // since the internally set JULIAN_DAY is used.  | 
3003  | 0  |     if (fStamp[UCAL_MILLISECONDS_IN_DAY] >= ((int32_t)kMinimumUserStamp) &&  | 
3004  | 0  |             newestStamp(UCAL_AM_PM, UCAL_MILLISECOND, kUnset) <= fStamp[UCAL_MILLISECONDS_IN_DAY]) { | 
3005  | 0  |         millisInDay = internalGet(UCAL_MILLISECONDS_IN_DAY);  | 
3006  | 0  |     } else { | 
3007  | 0  |         millisInDay = computeMillisInDay();  | 
3008  | 0  |     }  | 
3009  |  | 
  | 
3010  | 0  |     UDate t = 0;  | 
3011  | 0  |     if (fStamp[UCAL_ZONE_OFFSET] >= ((int32_t)kMinimumUserStamp) || fStamp[UCAL_DST_OFFSET] >= ((int32_t)kMinimumUserStamp)) { | 
3012  | 0  |         t = millis + millisInDay - (internalGet(UCAL_ZONE_OFFSET) + internalGet(UCAL_DST_OFFSET));  | 
3013  | 0  |     } else { | 
3014  |  |         // Compute the time zone offset and DST offset.  There are two potential  | 
3015  |  |         // ambiguities here.  We'll assume a 2:00 am (wall time) switchover time  | 
3016  |  |         // for discussion purposes here.  | 
3017  |  |         //  | 
3018  |  |         // 1. The positive offset change such as transition into DST.  | 
3019  |  |         //    Here, a designated time of 2:00 am - 2:59 am does not actually exist.  | 
3020  |  |         //    For this case, skippedWallTime option specifies the behavior.  | 
3021  |  |         //    For example, 2:30 am is interpreted as;  | 
3022  |  |         //      - WALLTIME_LAST(default): 3:30 am (DST) (interpreting 2:30 am as 31 minutes after 1:59 am (STD))  | 
3023  |  |         //      - WALLTIME_FIRST: 1:30 am (STD) (interpreting 2:30 am as 30 minutes before 3:00 am (DST))  | 
3024  |  |         //      - WALLTIME_NEXT_VALID: 3:00 am (DST) (next valid time after 2:30 am on a wall clock)  | 
3025  |  |         // 2. The negative offset change such as transition out of DST.  | 
3026  |  |         //    Here, a designated time of 1:00 am - 1:59 am can be in standard or DST.  Both are valid  | 
3027  |  |         //    representations (the rep jumps from 1:59:59 DST to 1:00:00 Std).  | 
3028  |  |         //    For this case, repeatedWallTime option specifies the behavior.  | 
3029  |  |         //    For example, 1:30 am is interpreted as;  | 
3030  |  |         //      - WALLTIME_LAST(default): 1:30 am (STD) - latter occurrence  | 
3031  |  |         //      - WALLTIME_FIRST: 1:30 am (DST) - former occurrence  | 
3032  |  |         //  | 
3033  |  |         // In addition to above, when calendar is strict (not default), wall time falls into  | 
3034  |  |         // the skipped time range will be processed as an error case.  | 
3035  |  |         //  | 
3036  |  |         // These special cases are mostly handled in #computeZoneOffset(long), except WALLTIME_NEXT_VALID  | 
3037  |  |         // at positive offset change. The protected method computeZoneOffset(long) is exposed to Calendar  | 
3038  |  |         // subclass implementations and marked as @stable. Strictly speaking, WALLTIME_NEXT_VALID  | 
3039  |  |         // should be also handled in the same place, but we cannot change the code flow without deprecating  | 
3040  |  |         // the protected method.  | 
3041  |  |         //  | 
3042  |  |         // We use the TimeZone object, unless the user has explicitly set the ZONE_OFFSET  | 
3043  |  |         // or DST_OFFSET fields; then we use those fields.  | 
3044  |  | 
  | 
3045  | 0  |         if (!isLenient() || fSkippedWallTime == UCAL_WALLTIME_NEXT_VALID) { | 
3046  |  |             // When strict, invalidate a wall time falls into a skipped wall time range.  | 
3047  |  |             // When lenient and skipped wall time option is WALLTIME_NEXT_VALID,  | 
3048  |  |             // the result time will be adjusted to the next valid time (on wall clock).  | 
3049  | 0  |             int32_t zoneOffset = computeZoneOffset(millis, millisInDay, status);  | 
3050  | 0  |             UDate tmpTime = millis + millisInDay - zoneOffset;  | 
3051  |  | 
  | 
3052  | 0  |             int32_t raw, dst;  | 
3053  | 0  |             fZone->getOffset(tmpTime, FALSE, raw, dst, status);  | 
3054  |  | 
  | 
3055  | 0  |             if (U_SUCCESS(status)) { | 
3056  |  |                 // zoneOffset != (raw + dst) only when the given wall time fall into  | 
3057  |  |                 // a skipped wall time range caused by positive zone offset transition.  | 
3058  | 0  |                 if (zoneOffset != (raw + dst)) { | 
3059  | 0  |                     if (!isLenient()) { | 
3060  | 0  |                         status = U_ILLEGAL_ARGUMENT_ERROR;  | 
3061  | 0  |                     } else { | 
3062  | 0  |                         U_ASSERT(fSkippedWallTime == UCAL_WALLTIME_NEXT_VALID);  | 
3063  |  |                         // Adjust time to the next valid wall clock time.  | 
3064  |  |                         // At this point, tmpTime is on or after the zone offset transition causing  | 
3065  |  |                         // the skipped time range.  | 
3066  | 0  |                         UDate immediatePrevTransition;  | 
3067  | 0  |                         UBool hasTransition = getImmediatePreviousZoneTransition(tmpTime, &immediatePrevTransition, status);  | 
3068  | 0  |                         if (U_SUCCESS(status) && hasTransition) { | 
3069  | 0  |                             t = immediatePrevTransition;  | 
3070  | 0  |                         }  | 
3071  | 0  |                     }  | 
3072  | 0  |                 } else { | 
3073  | 0  |                     t = tmpTime;  | 
3074  | 0  |                 }  | 
3075  | 0  |             }  | 
3076  | 0  |         } else { | 
3077  | 0  |             t = millis + millisInDay - computeZoneOffset(millis, millisInDay, status);  | 
3078  | 0  |         }  | 
3079  | 0  |     }  | 
3080  | 0  |     if (U_SUCCESS(status)) { | 
3081  | 0  |         internalSetTime(t);  | 
3082  | 0  |     }  | 
3083  | 0  | }  | 
3084  |  |  | 
3085  |  | /**  | 
3086  |  |  * Find the previous zone transition near the given time.  | 
3087  |  |  */  | 
3088  | 0  | UBool Calendar::getImmediatePreviousZoneTransition(UDate base, UDate *transitionTime, UErrorCode& status) const { | 
3089  | 0  |     BasicTimeZone *btz = getBasicTimeZone();  | 
3090  | 0  |     if (btz) { | 
3091  | 0  |         TimeZoneTransition trans;  | 
3092  | 0  |         UBool hasTransition = btz->getPreviousTransition(base, TRUE, trans);  | 
3093  | 0  |         if (hasTransition) { | 
3094  | 0  |             *transitionTime = trans.getTime();  | 
3095  | 0  |             return TRUE;  | 
3096  | 0  |         } else { | 
3097  |  |             // Could not find any transitions.  | 
3098  |  |             // Note: This should never happen.  | 
3099  | 0  |             status = U_INTERNAL_PROGRAM_ERROR;  | 
3100  | 0  |         }  | 
3101  | 0  |     } else { | 
3102  |  |         // If not BasicTimeZone, return unsupported error for now.  | 
3103  |  |         // TODO: We may support non-BasicTimeZone in future.  | 
3104  | 0  |         status = U_UNSUPPORTED_ERROR;  | 
3105  | 0  |     }  | 
3106  | 0  |     return FALSE;  | 
3107  | 0  | }  | 
3108  |  |  | 
3109  |  | /**  | 
3110  |  | * Compute the milliseconds in the day from the fields.  This is a  | 
3111  |  | * value from 0 to 23:59:59.999 inclusive, unless fields are out of  | 
3112  |  | * range, in which case it can be an arbitrary value.  This value  | 
3113  |  | * reflects local zone wall time.  | 
3114  |  | * @stable ICU 2.0  | 
3115  |  | */  | 
3116  | 0  | double Calendar::computeMillisInDay() { | 
3117  |  |   // Do the time portion of the conversion.  | 
3118  |  | 
  | 
3119  | 0  |     double millisInDay = 0;  | 
3120  |  |  | 
3121  |  |     // Find the best set of fields specifying the time of day.  There  | 
3122  |  |     // are only two possibilities here; the HOUR_OF_DAY or the  | 
3123  |  |     // AM_PM and the HOUR.  | 
3124  | 0  |     int32_t hourOfDayStamp = fStamp[UCAL_HOUR_OF_DAY];  | 
3125  | 0  |     int32_t hourStamp = (fStamp[UCAL_HOUR] > fStamp[UCAL_AM_PM])?fStamp[UCAL_HOUR]:fStamp[UCAL_AM_PM];  | 
3126  | 0  |     int32_t bestStamp = (hourStamp > hourOfDayStamp) ? hourStamp : hourOfDayStamp;  | 
3127  |  |  | 
3128  |  |     // Hours  | 
3129  | 0  |     if (bestStamp != kUnset) { | 
3130  | 0  |         if (bestStamp == hourOfDayStamp) { | 
3131  |  |             // Don't normalize here; let overflow bump into the next period.  | 
3132  |  |             // This is consistent with how we handle other fields.  | 
3133  | 0  |             millisInDay += internalGet(UCAL_HOUR_OF_DAY);  | 
3134  | 0  |         } else { | 
3135  |  |             // Don't normalize here; let overflow bump into the next period.  | 
3136  |  |             // This is consistent with how we handle other fields.  | 
3137  | 0  |             millisInDay += internalGet(UCAL_HOUR);  | 
3138  | 0  |             millisInDay += 12 * internalGet(UCAL_AM_PM); // Default works for unset AM_PM  | 
3139  | 0  |         }  | 
3140  | 0  |     }  | 
3141  |  |  | 
3142  |  |     // We use the fact that unset == 0; we start with millisInDay  | 
3143  |  |     // == HOUR_OF_DAY.  | 
3144  | 0  |     millisInDay *= 60;  | 
3145  | 0  |     millisInDay += internalGet(UCAL_MINUTE); // now have minutes  | 
3146  | 0  |     millisInDay *= 60;  | 
3147  | 0  |     millisInDay += internalGet(UCAL_SECOND); // now have seconds  | 
3148  | 0  |     millisInDay *= 1000;  | 
3149  | 0  |     millisInDay += internalGet(UCAL_MILLISECOND); // now have millis  | 
3150  |  | 
  | 
3151  | 0  |     return millisInDay;  | 
3152  | 0  | }  | 
3153  |  |  | 
3154  |  | /**  | 
3155  |  | * This method can assume EXTENDED_YEAR has been set.  | 
3156  |  | * @param millis milliseconds of the date fields  | 
3157  |  | * @param millisInDay milliseconds of the time fields; may be out  | 
3158  |  | * or range.  | 
3159  |  | * @stable ICU 2.0  | 
3160  |  | */  | 
3161  | 0  | int32_t Calendar::computeZoneOffset(double millis, double millisInDay, UErrorCode &ec) { | 
3162  | 0  |     int32_t rawOffset, dstOffset;  | 
3163  | 0  |     UDate wall = millis + millisInDay;  | 
3164  | 0  |     BasicTimeZone* btz = getBasicTimeZone();  | 
3165  | 0  |     if (btz) { | 
3166  | 0  |         UTimeZoneLocalOption duplicatedTimeOpt = (fRepeatedWallTime == UCAL_WALLTIME_FIRST) ? UCAL_TZ_LOCAL_FORMER : UCAL_TZ_LOCAL_LATTER;  | 
3167  | 0  |         UTimeZoneLocalOption nonExistingTimeOpt = (fSkippedWallTime == UCAL_WALLTIME_FIRST) ? UCAL_TZ_LOCAL_LATTER : UCAL_TZ_LOCAL_FORMER;  | 
3168  | 0  |         btz->getOffsetFromLocal(wall, nonExistingTimeOpt, duplicatedTimeOpt, rawOffset, dstOffset, ec);  | 
3169  | 0  |     } else { | 
3170  | 0  |         const TimeZone& tz = getTimeZone();  | 
3171  |  |         // By default, TimeZone::getOffset behaves UCAL_WALLTIME_LAST for both.  | 
3172  | 0  |         tz.getOffset(wall, TRUE, rawOffset, dstOffset, ec);  | 
3173  |  | 
  | 
3174  | 0  |         UBool sawRecentNegativeShift = FALSE;  | 
3175  | 0  |         if (fRepeatedWallTime == UCAL_WALLTIME_FIRST) { | 
3176  |  |             // Check if the given wall time falls into repeated time range  | 
3177  | 0  |             UDate tgmt = wall - (rawOffset + dstOffset);  | 
3178  |  |  | 
3179  |  |             // Any negative zone transition within last 6 hours?  | 
3180  |  |             // Note: The maximum historic negative zone transition is -3 hours in the tz database.  | 
3181  |  |             // 6 hour window would be sufficient for this purpose.  | 
3182  | 0  |             int32_t tmpRaw, tmpDst;  | 
3183  | 0  |             tz.getOffset(tgmt - 6*60*60*1000, FALSE, tmpRaw, tmpDst, ec);  | 
3184  | 0  |             int32_t offsetDelta = (rawOffset + dstOffset) - (tmpRaw + tmpDst);  | 
3185  |  | 
  | 
3186  | 0  |             U_ASSERT(offsetDelta < -6*60*60*1000);  | 
3187  | 0  |             if (offsetDelta < 0) { | 
3188  | 0  |                 sawRecentNegativeShift = TRUE;  | 
3189  |  |                 // Negative shift within last 6 hours. When UCAL_WALLTIME_FIRST is used and the given wall time falls  | 
3190  |  |                 // into the repeated time range, use offsets before the transition.  | 
3191  |  |                 // Note: If it does not fall into the repeated time range, offsets remain unchanged below.  | 
3192  | 0  |                 tz.getOffset(wall + offsetDelta, TRUE, rawOffset, dstOffset, ec);  | 
3193  | 0  |             }  | 
3194  | 0  |         }  | 
3195  | 0  |         if (!sawRecentNegativeShift && fSkippedWallTime == UCAL_WALLTIME_FIRST) { | 
3196  |  |             // When skipped wall time option is WALLTIME_FIRST,  | 
3197  |  |             // recalculate offsets from the resolved time (non-wall).  | 
3198  |  |             // When the given wall time falls into skipped wall time,  | 
3199  |  |             // the offsets will be based on the zone offsets AFTER  | 
3200  |  |             // the transition (which means, earliest possible interpretation).  | 
3201  | 0  |             UDate tgmt = wall - (rawOffset + dstOffset);  | 
3202  | 0  |             tz.getOffset(tgmt, FALSE, rawOffset, dstOffset, ec);  | 
3203  | 0  |         }  | 
3204  | 0  |     }  | 
3205  | 0  |     return rawOffset + dstOffset;  | 
3206  | 0  | }  | 
3207  |  |  | 
3208  |  | int32_t Calendar::computeJulianDay()  | 
3209  | 0  | { | 
3210  |  |     // We want to see if any of the date fields is newer than the  | 
3211  |  |     // JULIAN_DAY.  If not, then we use JULIAN_DAY.  If so, then we do  | 
3212  |  |     // the normal resolution.  We only use JULIAN_DAY if it has been  | 
3213  |  |     // set by the user.  This makes it possible for the caller to set  | 
3214  |  |     // the calendar to a time and call clear(MONTH) to reset the MONTH  | 
3215  |  |     // to January.  This is legacy behavior.  Without this,  | 
3216  |  |     // clear(MONTH) has no effect, since the internally set JULIAN_DAY  | 
3217  |  |     // is used.  | 
3218  | 0  |     if (fStamp[UCAL_JULIAN_DAY] >= (int32_t)kMinimumUserStamp) { | 
3219  | 0  |         int32_t bestStamp = newestStamp(UCAL_ERA, UCAL_DAY_OF_WEEK_IN_MONTH, kUnset);  | 
3220  | 0  |         bestStamp = newestStamp(UCAL_YEAR_WOY, UCAL_EXTENDED_YEAR, bestStamp);  | 
3221  | 0  |         if (bestStamp <= fStamp[UCAL_JULIAN_DAY]) { | 
3222  | 0  |             return internalGet(UCAL_JULIAN_DAY);  | 
3223  | 0  |         }  | 
3224  | 0  |     }  | 
3225  |  |  | 
3226  | 0  |     UCalendarDateFields bestField = resolveFields(getFieldResolutionTable());  | 
3227  | 0  |     if (bestField == UCAL_FIELD_COUNT) { | 
3228  | 0  |         bestField = UCAL_DAY_OF_MONTH;  | 
3229  | 0  |     }  | 
3230  |  | 
  | 
3231  | 0  |     return handleComputeJulianDay(bestField);  | 
3232  | 0  | }  | 
3233  |  |  | 
3234  |  | // -------------------------------------------  | 
3235  |  |  | 
3236  | 0  | int32_t Calendar::handleComputeJulianDay(UCalendarDateFields bestField)  { | 
3237  | 0  |     UBool useMonth = (bestField == UCAL_DAY_OF_MONTH ||  | 
3238  | 0  |         bestField == UCAL_WEEK_OF_MONTH ||  | 
3239  | 0  |         bestField == UCAL_DAY_OF_WEEK_IN_MONTH);  | 
3240  | 0  |     int32_t year;  | 
3241  |  | 
  | 
3242  | 0  |     if (bestField == UCAL_WEEK_OF_YEAR && newerField(UCAL_YEAR_WOY, UCAL_YEAR) == UCAL_YEAR_WOY) { | 
3243  | 0  |         year = internalGet(UCAL_YEAR_WOY);  | 
3244  | 0  |     } else { | 
3245  | 0  |         year = handleGetExtendedYear();  | 
3246  | 0  |     }  | 
3247  |  | 
  | 
3248  | 0  |     internalSet(UCAL_EXTENDED_YEAR, year);  | 
3249  |  | 
  | 
3250  |  | #if defined (U_DEBUG_CAL)  | 
3251  |  |     fprintf(stderr, "%s:%d: bestField= %s - y=%d\n", __FILE__, __LINE__, fldName(bestField), year);  | 
3252  |  | #endif  | 
3253  |  |  | 
3254  |  |     // Get the Julian day of the day BEFORE the start of this year.  | 
3255  |  |     // If useMonth is true, get the day before the start of the month.  | 
3256  |  |  | 
3257  |  |     // give calendar subclass a chance to have a default 'first' month  | 
3258  | 0  |     int32_t month;  | 
3259  |  | 
  | 
3260  | 0  |     if(isSet(UCAL_MONTH)) { | 
3261  | 0  |         month = internalGet(UCAL_MONTH);  | 
3262  | 0  |     } else { | 
3263  | 0  |         month = getDefaultMonthInYear(year);  | 
3264  | 0  |     }  | 
3265  |  | 
  | 
3266  | 0  |     int32_t julianDay = handleComputeMonthStart(year, useMonth ? month : 0, useMonth);  | 
3267  |  | 
  | 
3268  | 0  |     if (bestField == UCAL_DAY_OF_MONTH) { | 
3269  |  |  | 
3270  |  |         // give calendar subclass a chance to have a default 'first' dom  | 
3271  | 0  |         int32_t dayOfMonth;  | 
3272  | 0  |         if(isSet(UCAL_DAY_OF_MONTH)) { | 
3273  | 0  |             dayOfMonth = internalGet(UCAL_DAY_OF_MONTH,1);  | 
3274  | 0  |         } else { | 
3275  | 0  |             dayOfMonth = getDefaultDayInMonth(year, month);  | 
3276  | 0  |         }  | 
3277  | 0  |         return julianDay + dayOfMonth;  | 
3278  | 0  |     }  | 
3279  |  |  | 
3280  | 0  |     if (bestField == UCAL_DAY_OF_YEAR) { | 
3281  | 0  |         return julianDay + internalGet(UCAL_DAY_OF_YEAR);  | 
3282  | 0  |     }  | 
3283  |  |  | 
3284  | 0  |     int32_t firstDayOfWeek = getFirstDayOfWeek(); // Localized fdw  | 
3285  |  |  | 
3286  |  |     // At this point julianDay is the 0-based day BEFORE the first day of  | 
3287  |  |     // January 1, year 1 of the given calendar.  If julianDay == 0, it  | 
3288  |  |     // specifies (Jan. 1, 1) - 1, in whatever calendar we are using (Julian  | 
3289  |  |     // or Gregorian). (or it is before the month we are in, if useMonth is True)  | 
3290  |  |  | 
3291  |  |     // At this point we need to process the WEEK_OF_MONTH or  | 
3292  |  |     // WEEK_OF_YEAR, which are similar, or the DAY_OF_WEEK_IN_MONTH.  | 
3293  |  |     // First, perform initial shared computations.  These locate the  | 
3294  |  |     // first week of the period.  | 
3295  |  |  | 
3296  |  |     // Get the 0-based localized DOW of day one of the month or year.  | 
3297  |  |     // Valid range 0..6.  | 
3298  | 0  |     int32_t first = julianDayToDayOfWeek(julianDay + 1) - firstDayOfWeek;  | 
3299  | 0  |     if (first < 0) { | 
3300  | 0  |         first += 7;  | 
3301  | 0  |     }  | 
3302  |  | 
  | 
3303  | 0  |     int32_t dowLocal = getLocalDOW();  | 
3304  |  |  | 
3305  |  |     // Find the first target DOW (dowLocal) in the month or year.  | 
3306  |  |     // Actually, it may be just before the first of the month or year.  | 
3307  |  |     // It will be an integer from -5..7.  | 
3308  | 0  |     int32_t date = 1 - first + dowLocal;  | 
3309  |  | 
  | 
3310  | 0  |     if (bestField == UCAL_DAY_OF_WEEK_IN_MONTH) { | 
3311  |  |         // Adjust the target DOW to be in the month or year.  | 
3312  | 0  |         if (date < 1) { | 
3313  | 0  |             date += 7;  | 
3314  | 0  |         }  | 
3315  |  |  | 
3316  |  |         // The only trickiness occurs if the day-of-week-in-month is  | 
3317  |  |         // negative.  | 
3318  | 0  |         int32_t dim = internalGet(UCAL_DAY_OF_WEEK_IN_MONTH, 1);  | 
3319  | 0  |         if (dim >= 0) { | 
3320  | 0  |             date += 7*(dim - 1);  | 
3321  |  | 
  | 
3322  | 0  |         } else { | 
3323  |  |             // Move date to the last of this day-of-week in this month,  | 
3324  |  |             // then back up as needed.  If dim==-1, we don't back up at  | 
3325  |  |             // all.  If dim==-2, we back up once, etc.  Don't back up  | 
3326  |  |             // past the first of the given day-of-week in this month.  | 
3327  |  |             // Note that we handle -2, -3, etc. correctly, even though  | 
3328  |  |             // values < -1 are technically disallowed.  | 
3329  | 0  |             int32_t m = internalGet(UCAL_MONTH, UCAL_JANUARY);  | 
3330  | 0  |             int32_t monthLength = handleGetMonthLength(year, m);  | 
3331  | 0  |             date += ((monthLength - date) / 7 + dim + 1) * 7;  | 
3332  | 0  |         }  | 
3333  | 0  |     } else { | 
3334  |  | #if defined (U_DEBUG_CAL)  | 
3335  |  |         fprintf(stderr, "%s:%d - bf= %s\n", __FILE__, __LINE__, fldName(bestField));  | 
3336  |  | #endif  | 
3337  |  | 
  | 
3338  | 0  |         if(bestField == UCAL_WEEK_OF_YEAR) {  // ------------------------------------- WOY ------------- | 
3339  | 0  |             if(!isSet(UCAL_YEAR_WOY) ||  // YWOY not set at all or  | 
3340  | 0  |                 ( (resolveFields(kYearPrecedence) != UCAL_YEAR_WOY) // YWOY doesn't have precedence  | 
3341  | 0  |                 && (fStamp[UCAL_YEAR_WOY]!=kInternallySet) ) ) // (excluding where all fields are internally set - then YWOY is used)  | 
3342  | 0  |             { | 
3343  |  |                 // need to be sure to stay in 'real' year.  | 
3344  | 0  |                 int32_t woy = internalGet(bestField);  | 
3345  |  | 
  | 
3346  | 0  |                 int32_t nextJulianDay = handleComputeMonthStart(year+1, 0, FALSE); // jd of day before jan 1  | 
3347  | 0  |                 int32_t nextFirst = julianDayToDayOfWeek(nextJulianDay + 1) - firstDayOfWeek;  | 
3348  |  | 
  | 
3349  | 0  |                 if (nextFirst < 0) { // 0..6 ldow of Jan 1 | 
3350  | 0  |                     nextFirst += 7;  | 
3351  | 0  |                 }  | 
3352  |  | 
  | 
3353  | 0  |                 if(woy==1) {  // FIRST WEEK --------------------------------- | 
3354  |  | #if defined (U_DEBUG_CAL)  | 
3355  |  |                     fprintf(stderr, "%s:%d - woy=%d, yp=%d, nj(%d)=%d, nf=%d", __FILE__, __LINE__,  | 
3356  |  |                         internalGet(bestField), resolveFields(kYearPrecedence), year+1,  | 
3357  |  |                         nextJulianDay, nextFirst);  | 
3358  |  |  | 
3359  |  |                     fprintf(stderr, " next: %d DFW,  min=%d   \n", (7-nextFirst), getMinimalDaysInFirstWeek() );  | 
3360  |  | #endif  | 
3361  |  |  | 
3362  |  |                     // nextFirst is now the localized DOW of Jan 1  of y-woy+1  | 
3363  | 0  |                     if((nextFirst > 0) &&   // Jan 1 starts on FDOW  | 
3364  | 0  |                         (7-nextFirst) >= getMinimalDaysInFirstWeek()) // or enough days in the week  | 
3365  | 0  |                     { | 
3366  |  |                         // Jan 1 of (yearWoy+1) is in yearWoy+1 - recalculate JD to next year  | 
3367  |  | #if defined (U_DEBUG_CAL)  | 
3368  |  |                         fprintf(stderr, "%s:%d - was going to move JD from %d to %d [d%d]\n", __FILE__, __LINE__,  | 
3369  |  |                             julianDay, nextJulianDay, (nextJulianDay-julianDay));  | 
3370  |  | #endif  | 
3371  | 0  |                         julianDay = nextJulianDay;  | 
3372  |  |  | 
3373  |  |                         // recalculate 'first' [0-based local dow of jan 1]  | 
3374  | 0  |                         first = julianDayToDayOfWeek(julianDay + 1) - firstDayOfWeek;  | 
3375  | 0  |                         if (first < 0) { | 
3376  | 0  |                             first += 7;  | 
3377  | 0  |                         }  | 
3378  |  |                         // recalculate date.  | 
3379  | 0  |                         date = 1 - first + dowLocal;  | 
3380  | 0  |                     }  | 
3381  | 0  |                 } else if(woy>=getLeastMaximum(bestField)) { | 
3382  |  |                     // could be in the last week- find out if this JD would overstep  | 
3383  | 0  |                     int32_t testDate = date;  | 
3384  | 0  |                     if ((7 - first) < getMinimalDaysInFirstWeek()) { | 
3385  | 0  |                         testDate += 7;  | 
3386  | 0  |                     }  | 
3387  |  |  | 
3388  |  |                     // Now adjust for the week number.  | 
3389  | 0  |                     testDate += 7 * (woy - 1);  | 
3390  |  | 
  | 
3391  |  | #if defined (U_DEBUG_CAL)  | 
3392  |  |                     fprintf(stderr, "%s:%d - y=%d, y-1=%d doy%d, njd%d (C.F. %d)\n",  | 
3393  |  |                         __FILE__, __LINE__, year, year-1, testDate, julianDay+testDate, nextJulianDay);  | 
3394  |  | #endif  | 
3395  | 0  |                     if(julianDay+testDate > nextJulianDay) { // is it past Dec 31?  (nextJulianDay is day BEFORE year+1's  Jan 1) | 
3396  |  |                         // Fire up the calculating engines.. retry YWOY = (year-1)  | 
3397  | 0  |                         julianDay = handleComputeMonthStart(year-1, 0, FALSE); // jd before Jan 1 of previous year  | 
3398  | 0  |                         first = julianDayToDayOfWeek(julianDay + 1) - firstDayOfWeek; // 0 based local dow   of first week  | 
3399  |  | 
  | 
3400  | 0  |                         if(first < 0) { // 0..6 | 
3401  | 0  |                             first += 7;  | 
3402  | 0  |                         }  | 
3403  | 0  |                         date = 1 - first + dowLocal;  | 
3404  |  | 
  | 
3405  |  | #if defined (U_DEBUG_CAL)  | 
3406  |  |                         fprintf(stderr, "%s:%d - date now %d, jd%d, ywoy%d\n",  | 
3407  |  |                             __FILE__, __LINE__, date, julianDay, year-1);  | 
3408  |  | #endif  | 
3409  |  |  | 
3410  |  | 
  | 
3411  | 0  |                     } /* correction needed */  | 
3412  | 0  |                 } /* leastmaximum */  | 
3413  | 0  |             } /* resolvefields(year) != year_woy */  | 
3414  | 0  |         } /* bestfield != week_of_year */  | 
3415  |  |  | 
3416  |  |         // assert(bestField == WEEK_OF_MONTH || bestField == WEEK_OF_YEAR)  | 
3417  |  |         // Adjust for minimal days in first week  | 
3418  | 0  |         if ((7 - first) < getMinimalDaysInFirstWeek()) { | 
3419  | 0  |             date += 7;  | 
3420  | 0  |         }  | 
3421  |  |  | 
3422  |  |         // Now adjust for the week number.  | 
3423  | 0  |         date += 7 * (internalGet(bestField) - 1);  | 
3424  | 0  |     }  | 
3425  |  | 
  | 
3426  | 0  |     return julianDay + date;  | 
3427  | 0  | }  | 
3428  |  |  | 
3429  |  | int32_t  | 
3430  |  | Calendar::getDefaultMonthInYear(int32_t /*eyear*/)  | 
3431  | 0  | { | 
3432  | 0  |     return 0;  | 
3433  | 0  | }  | 
3434  |  |  | 
3435  |  | int32_t  | 
3436  |  | Calendar::getDefaultDayInMonth(int32_t /*eyear*/, int32_t /*month*/)  | 
3437  | 0  | { | 
3438  | 0  |     return 1;  | 
3439  | 0  | }  | 
3440  |  |  | 
3441  |  |  | 
3442  |  | int32_t Calendar::getLocalDOW()  | 
3443  | 0  | { | 
3444  |  |   // Get zero-based localized DOW, valid range 0..6.  This is the DOW  | 
3445  |  |     // we are looking for.  | 
3446  | 0  |     int32_t dowLocal = 0;  | 
3447  | 0  |     switch (resolveFields(kDOWPrecedence)) { | 
3448  | 0  |     case UCAL_DAY_OF_WEEK:  | 
3449  | 0  |         dowLocal = internalGet(UCAL_DAY_OF_WEEK) - fFirstDayOfWeek;  | 
3450  | 0  |         break;  | 
3451  | 0  |     case UCAL_DOW_LOCAL:  | 
3452  | 0  |         dowLocal = internalGet(UCAL_DOW_LOCAL) - 1;  | 
3453  | 0  |         break;  | 
3454  | 0  |     default:  | 
3455  | 0  |         break;  | 
3456  | 0  |     }  | 
3457  | 0  |     dowLocal = dowLocal % 7;  | 
3458  | 0  |     if (dowLocal < 0) { | 
3459  | 0  |         dowLocal += 7;  | 
3460  | 0  |     }  | 
3461  | 0  |     return dowLocal;  | 
3462  | 0  | }  | 
3463  |  |  | 
3464  |  | int32_t Calendar::handleGetExtendedYearFromWeekFields(int32_t yearWoy, int32_t woy)  | 
3465  | 0  | { | 
3466  |  |     // We have UCAL_YEAR_WOY and UCAL_WEEK_OF_YEAR - from those, determine  | 
3467  |  |     // what year we fall in, so that other code can set it properly.  | 
3468  |  |     // (code borrowed from computeWeekFields and handleComputeJulianDay)  | 
3469  |  |     //return yearWoy;  | 
3470  |  |  | 
3471  |  |     // First, we need a reliable DOW.  | 
3472  | 0  |     UCalendarDateFields bestField = resolveFields(kDatePrecedence); // !! Note: if subclasses have a different table, they should override handleGetExtendedYearFromWeekFields  | 
3473  |  |  | 
3474  |  |     // Now, a local DOW  | 
3475  | 0  |     int32_t dowLocal = getLocalDOW(); // 0..6  | 
3476  | 0  |     int32_t firstDayOfWeek = getFirstDayOfWeek(); // Localized fdw  | 
3477  | 0  |     int32_t jan1Start = handleComputeMonthStart(yearWoy, 0, FALSE);  | 
3478  | 0  |     int32_t nextJan1Start = handleComputeMonthStart(yearWoy+1, 0, FALSE); // next year's Jan1 start  | 
3479  |  |  | 
3480  |  |     // At this point julianDay is the 0-based day BEFORE the first day of  | 
3481  |  |     // January 1, year 1 of the given calendar.  If julianDay == 0, it  | 
3482  |  |     // specifies (Jan. 1, 1) - 1, in whatever calendar we are using (Julian  | 
3483  |  |     // or Gregorian). (or it is before the month we are in, if useMonth is True)  | 
3484  |  |  | 
3485  |  |     // At this point we need to process the WEEK_OF_MONTH or  | 
3486  |  |     // WEEK_OF_YEAR, which are similar, or the DAY_OF_WEEK_IN_MONTH.  | 
3487  |  |     // First, perform initial shared computations.  These locate the  | 
3488  |  |     // first week of the period.  | 
3489  |  |  | 
3490  |  |     // Get the 0-based localized DOW of day one of the month or year.  | 
3491  |  |     // Valid range 0..6.  | 
3492  | 0  |     int32_t first = julianDayToDayOfWeek(jan1Start + 1) - firstDayOfWeek;  | 
3493  | 0  |     if (first < 0) { | 
3494  | 0  |         first += 7;  | 
3495  | 0  |     }  | 
3496  |  |  | 
3497  |  |     //// (nextFirst was not used below)  | 
3498  |  |     // int32_t nextFirst = julianDayToDayOfWeek(nextJan1Start + 1) - firstDayOfWeek;  | 
3499  |  |     // if (nextFirst < 0) { | 
3500  |  |     //     nextFirst += 7;  | 
3501  |  |     //}  | 
3502  |  | 
  | 
3503  | 0  |     int32_t minDays = getMinimalDaysInFirstWeek();  | 
3504  | 0  |     UBool jan1InPrevYear = FALSE;  // January 1st in the year of WOY is the 1st week?  (i.e. first week is < minimal )  | 
3505  |  |     //UBool nextJan1InPrevYear = FALSE; // January 1st of Year of WOY + 1 is in the first week?  | 
3506  |  | 
  | 
3507  | 0  |     if((7 - first) < minDays) { | 
3508  | 0  |         jan1InPrevYear = TRUE;  | 
3509  | 0  |     }  | 
3510  |  |  | 
3511  |  |     //   if((7 - nextFirst) < minDays) { | 
3512  |  |     //     nextJan1InPrevYear = TRUE;  | 
3513  |  |     //   }  | 
3514  |  | 
  | 
3515  | 0  |     switch(bestField) { | 
3516  | 0  |     case UCAL_WEEK_OF_YEAR:  | 
3517  | 0  |         if(woy == 1) { | 
3518  | 0  |             if(jan1InPrevYear == TRUE) { | 
3519  |  |                 // the first week of January is in the previous year  | 
3520  |  |                 // therefore WOY1 is always solidly within yearWoy  | 
3521  | 0  |                 return yearWoy;  | 
3522  | 0  |             } else { | 
3523  |  |                 // First WOY is split between two years  | 
3524  | 0  |                 if( dowLocal < first) { // we are prior to Jan 1 | 
3525  | 0  |                     return yearWoy-1; // previous year  | 
3526  | 0  |                 } else { | 
3527  | 0  |                     return yearWoy; // in this year  | 
3528  | 0  |                 }  | 
3529  | 0  |             }  | 
3530  | 0  |         } else if(woy >= getLeastMaximum(bestField)) { | 
3531  |  |             // we _might_ be in the last week..  | 
3532  | 0  |             int32_t jd =  // Calculate JD of our target day:  | 
3533  | 0  |                 jan1Start +  // JD of Jan 1  | 
3534  | 0  |                 (7-first) + //  days in the first week (Jan 1.. )  | 
3535  | 0  |                 (woy-1)*7 + // add the weeks of the year  | 
3536  | 0  |                 dowLocal;   // the local dow (0..6) of last week  | 
3537  | 0  |             if(jan1InPrevYear==FALSE) { | 
3538  | 0  |                 jd -= 7; // woy already includes Jan 1's week.  | 
3539  | 0  |             }  | 
3540  |  | 
  | 
3541  | 0  |             if( (jd+1) >= nextJan1Start ) { | 
3542  |  |                 // we are in week 52 or 53 etc. - actual year is yearWoy+1  | 
3543  | 0  |                 return yearWoy+1;  | 
3544  | 0  |             } else { | 
3545  |  |                 // still in yearWoy;  | 
3546  | 0  |                 return yearWoy;  | 
3547  | 0  |             }  | 
3548  | 0  |         } else { | 
3549  |  |             // we're not possibly in the last week -must be ywoy  | 
3550  | 0  |             return yearWoy;  | 
3551  | 0  |         }  | 
3552  |  |  | 
3553  | 0  |     case UCAL_DATE:  | 
3554  | 0  |         if((internalGet(UCAL_MONTH)==0) &&  | 
3555  | 0  |             (woy >= getLeastMaximum(UCAL_WEEK_OF_YEAR))) { | 
3556  | 0  |                 return yearWoy+1; // month 0, late woy = in the next year  | 
3557  | 0  |             } else if(woy==1) { | 
3558  |  |                 //if(nextJan1InPrevYear) { | 
3559  | 0  |                 if(internalGet(UCAL_MONTH)==0) { | 
3560  | 0  |                     return yearWoy;  | 
3561  | 0  |                 } else { | 
3562  | 0  |                     return yearWoy-1;  | 
3563  | 0  |                 }  | 
3564  |  |                 //}  | 
3565  | 0  |             }  | 
3566  |  |  | 
3567  |  |             //(internalGet(UCAL_DATE) <= (7-first)) /* && in minDow  */ ) { | 
3568  |  |             //within 1st week and in this month..  | 
3569  |  |             //return yearWoy+1;  | 
3570  | 0  |             return yearWoy;  | 
3571  |  |  | 
3572  | 0  |     default: // assume the year is appropriate  | 
3573  | 0  |         return yearWoy;  | 
3574  | 0  |     }  | 
3575  | 0  | }  | 
3576  |  |  | 
3577  |  | int32_t Calendar::handleGetMonthLength(int32_t extendedYear, int32_t month) const  | 
3578  | 0  | { | 
3579  | 0  |     return handleComputeMonthStart(extendedYear, month+1, TRUE) -  | 
3580  | 0  |         handleComputeMonthStart(extendedYear, month, TRUE);  | 
3581  | 0  | }  | 
3582  |  |  | 
3583  | 0  | int32_t Calendar::handleGetYearLength(int32_t eyear) const  { | 
3584  | 0  |     return handleComputeMonthStart(eyear+1, 0, FALSE) -  | 
3585  | 0  |         handleComputeMonthStart(eyear, 0, FALSE);  | 
3586  | 0  | }  | 
3587  |  |  | 
3588  |  | int32_t  | 
3589  |  | Calendar::getActualMaximum(UCalendarDateFields field, UErrorCode& status) const  | 
3590  | 0  | { | 
3591  | 0  |     int32_t result;  | 
3592  | 0  |     switch (field) { | 
3593  | 0  |     case UCAL_DATE:  | 
3594  | 0  |         { | 
3595  | 0  |             if(U_FAILURE(status)) return 0;  | 
3596  | 0  |             Calendar *cal = clone();  | 
3597  | 0  |             if(!cal) { status = U_MEMORY_ALLOCATION_ERROR; return 0; } | 
3598  | 0  |             cal->setLenient(TRUE);  | 
3599  | 0  |             cal->prepareGetActual(field,FALSE,status);  | 
3600  | 0  |             result = handleGetMonthLength(cal->get(UCAL_EXTENDED_YEAR, status), cal->get(UCAL_MONTH, status));  | 
3601  | 0  |             delete cal;  | 
3602  | 0  |         }  | 
3603  | 0  |         break;  | 
3604  |  |  | 
3605  | 0  |     case UCAL_DAY_OF_YEAR:  | 
3606  | 0  |         { | 
3607  | 0  |             if(U_FAILURE(status)) return 0;  | 
3608  | 0  |             Calendar *cal = clone();  | 
3609  | 0  |             if(!cal) { status = U_MEMORY_ALLOCATION_ERROR; return 0; } | 
3610  | 0  |             cal->setLenient(TRUE);  | 
3611  | 0  |             cal->prepareGetActual(field,FALSE,status);  | 
3612  | 0  |             result = handleGetYearLength(cal->get(UCAL_EXTENDED_YEAR, status));  | 
3613  | 0  |             delete cal;  | 
3614  | 0  |         }  | 
3615  | 0  |         break;  | 
3616  |  |  | 
3617  | 0  |     case UCAL_DAY_OF_WEEK:  | 
3618  | 0  |     case UCAL_AM_PM:  | 
3619  | 0  |     case UCAL_HOUR:  | 
3620  | 0  |     case UCAL_HOUR_OF_DAY:  | 
3621  | 0  |     case UCAL_MINUTE:  | 
3622  | 0  |     case UCAL_SECOND:  | 
3623  | 0  |     case UCAL_MILLISECOND:  | 
3624  | 0  |     case UCAL_ZONE_OFFSET:  | 
3625  | 0  |     case UCAL_DST_OFFSET:  | 
3626  | 0  |     case UCAL_DOW_LOCAL:  | 
3627  | 0  |     case UCAL_JULIAN_DAY:  | 
3628  | 0  |     case UCAL_MILLISECONDS_IN_DAY:  | 
3629  |  |         // These fields all have fixed minima/maxima  | 
3630  | 0  |         result = getMaximum(field);  | 
3631  | 0  |         break;  | 
3632  |  |  | 
3633  | 0  |     default:  | 
3634  |  |         // For all other fields, do it the hard way....  | 
3635  | 0  |         result = getActualHelper(field, getLeastMaximum(field), getMaximum(field),status);  | 
3636  | 0  |         break;  | 
3637  | 0  |     }  | 
3638  | 0  |     return result;  | 
3639  | 0  | }  | 
3640  |  |  | 
3641  |  |  | 
3642  |  | /**  | 
3643  |  | * Prepare this calendar for computing the actual minimum or maximum.  | 
3644  |  | * This method modifies this calendar's fields; it is called on a  | 
3645  |  | * temporary calendar.  | 
3646  |  | *  | 
3647  |  | * <p>Rationale: The semantics of getActualXxx() is to return the  | 
3648  |  | * maximum or minimum value that the given field can take, taking into  | 
3649  |  | * account other relevant fields.  In general these other fields are  | 
3650  |  | * larger fields.  For example, when computing the actual maximum  | 
3651  |  | * DATE, the current value of DATE itself is ignored,  | 
3652  |  | * as is the value of any field smaller.  | 
3653  |  | *  | 
3654  |  | * <p>The time fields all have fixed minima and maxima, so we don't  | 
3655  |  | * need to worry about them.  This also lets us set the  | 
3656  |  | * MILLISECONDS_IN_DAY to zero to erase any effects the time fields  | 
3657  |  | * might have when computing date fields.  | 
3658  |  | *  | 
3659  |  | * <p>DAY_OF_WEEK is adjusted specially for the WEEK_OF_MONTH and  | 
3660  |  | * WEEK_OF_YEAR fields to ensure that they are computed correctly.  | 
3661  |  | * @internal  | 
3662  |  | */  | 
3663  |  | void Calendar::prepareGetActual(UCalendarDateFields field, UBool isMinimum, UErrorCode &status)  | 
3664  | 0  | { | 
3665  | 0  |     set(UCAL_MILLISECONDS_IN_DAY, 0);  | 
3666  |  | 
  | 
3667  | 0  |     switch (field) { | 
3668  | 0  |     case UCAL_YEAR:  | 
3669  | 0  |     case UCAL_EXTENDED_YEAR:  | 
3670  | 0  |         set(UCAL_DAY_OF_YEAR, getGreatestMinimum(UCAL_DAY_OF_YEAR));  | 
3671  | 0  |         break;  | 
3672  |  |  | 
3673  | 0  |     case UCAL_YEAR_WOY:  | 
3674  | 0  |         set(UCAL_WEEK_OF_YEAR, getGreatestMinimum(UCAL_WEEK_OF_YEAR));  | 
3675  | 0  |         U_FALLTHROUGH;  | 
3676  | 0  |     case UCAL_MONTH:  | 
3677  | 0  |         set(UCAL_DATE, getGreatestMinimum(UCAL_DATE));  | 
3678  | 0  |         break;  | 
3679  |  |  | 
3680  | 0  |     case UCAL_DAY_OF_WEEK_IN_MONTH:  | 
3681  |  |         // For dowim, the maximum occurs for the DOW of the first of the  | 
3682  |  |         // month.  | 
3683  | 0  |         set(UCAL_DATE, 1);  | 
3684  | 0  |         set(UCAL_DAY_OF_WEEK, get(UCAL_DAY_OF_WEEK, status)); // Make this user set  | 
3685  | 0  |         break;  | 
3686  |  |  | 
3687  | 0  |     case UCAL_WEEK_OF_MONTH:  | 
3688  | 0  |     case UCAL_WEEK_OF_YEAR:  | 
3689  |  |         // If we're counting weeks, set the day of the week to either the  | 
3690  |  |         // first or last localized DOW.  We know the last week of a month  | 
3691  |  |         // or year will contain the first day of the week, and that the  | 
3692  |  |         // first week will contain the last DOW.  | 
3693  | 0  |         { | 
3694  | 0  |             int32_t dow = fFirstDayOfWeek;  | 
3695  | 0  |             if (isMinimum) { | 
3696  | 0  |                 dow = (dow + 6) % 7; // set to last DOW  | 
3697  | 0  |                 if (dow < UCAL_SUNDAY) { | 
3698  | 0  |                     dow += 7;  | 
3699  | 0  |                 }  | 
3700  | 0  |             }  | 
3701  |  | #if defined (U_DEBUG_CAL)  | 
3702  |  |             fprintf(stderr, "prepareGetActualHelper(WOM/WOY) - dow=%d\n", dow);  | 
3703  |  | #endif  | 
3704  | 0  |             set(UCAL_DAY_OF_WEEK, dow);  | 
3705  | 0  |         }  | 
3706  | 0  |         break;  | 
3707  | 0  |     default:  | 
3708  | 0  |         break;  | 
3709  | 0  |     }  | 
3710  |  |  | 
3711  |  |     // Do this last to give it the newest time stamp  | 
3712  | 0  |     set(field, getGreatestMinimum(field));  | 
3713  | 0  | }  | 
3714  |  |  | 
3715  |  | int32_t Calendar::getActualHelper(UCalendarDateFields field, int32_t startValue, int32_t endValue, UErrorCode &status) const  | 
3716  | 0  | { | 
3717  |  | #if defined (U_DEBUG_CAL)  | 
3718  |  |     fprintf(stderr, "getActualHelper(%d,%d .. %d, %s)\n", field, startValue, endValue, u_errorName(status));  | 
3719  |  | #endif  | 
3720  | 0  |     if (startValue == endValue) { | 
3721  |  |         // if we know that the maximum value is always the same, just return it  | 
3722  | 0  |         return startValue;  | 
3723  | 0  |     }  | 
3724  |  |  | 
3725  | 0  |     int32_t delta = (endValue > startValue) ? 1 : -1;  | 
3726  |  |  | 
3727  |  |     // clone the calendar so we don't mess with the real one, and set it to  | 
3728  |  |     // accept anything for the field values  | 
3729  | 0  |     if(U_FAILURE(status)) return startValue;  | 
3730  | 0  |     Calendar *work = clone();  | 
3731  | 0  |     if(!work) { status = U_MEMORY_ALLOCATION_ERROR; return startValue; } | 
3732  |  |  | 
3733  |  |     // need to resolve time here, otherwise, fields set for actual limit  | 
3734  |  |     // may cause conflict with fields previously set (but not yet resolved).  | 
3735  | 0  |     work->complete(status);  | 
3736  |  | 
  | 
3737  | 0  |     work->setLenient(TRUE);  | 
3738  | 0  |     work->prepareGetActual(field, delta < 0, status);  | 
3739  |  |  | 
3740  |  |     // now try each value from the start to the end one by one until  | 
3741  |  |     // we get a value that normalizes to another value.  The last value that  | 
3742  |  |     // normalizes to itself is the actual maximum for the current date  | 
3743  | 0  |     work->set(field, startValue);  | 
3744  |  |  | 
3745  |  |     // prepareGetActual sets the first day of week in the same week with  | 
3746  |  |     // the first day of a month.  Unlike WEEK_OF_YEAR, week number for the  | 
3747  |  |     // week which contains days from both previous and current month is  | 
3748  |  |     // not unique.  For example, last several days in the previous month  | 
3749  |  |     // is week 5, and the rest of week is week 1.  | 
3750  | 0  |     int32_t result = startValue;  | 
3751  | 0  |     if ((work->get(field, status) != startValue  | 
3752  | 0  |          && field != UCAL_WEEK_OF_MONTH && delta > 0 ) || U_FAILURE(status)) { | 
3753  |  | #if defined (U_DEBUG_CAL)  | 
3754  |  |         fprintf(stderr, "getActualHelper(fld %d) - got  %d (not %d) - %s\n", field, work->get(field,status), startValue, u_errorName(status));  | 
3755  |  | #endif  | 
3756  | 0  |     } else { | 
3757  | 0  |         do { | 
3758  | 0  |             startValue += delta;  | 
3759  | 0  |             work->add(field, delta, status);  | 
3760  | 0  |             if (work->get(field, status) != startValue || U_FAILURE(status)) { | 
3761  |  | #if defined (U_DEBUG_CAL)  | 
3762  |  |                 fprintf(stderr, "getActualHelper(fld %d) - got  %d (not %d), BREAK - %s\n", field, work->get(field,status), startValue, u_errorName(status));  | 
3763  |  | #endif  | 
3764  | 0  |                 break;  | 
3765  | 0  |             }  | 
3766  | 0  |             result = startValue;  | 
3767  | 0  |         } while (startValue != endValue);  | 
3768  | 0  |     }  | 
3769  | 0  |     delete work;  | 
3770  |  | #if defined (U_DEBUG_CAL)  | 
3771  |  |     fprintf(stderr, "getActualHelper(%d) = %d\n", field, result);  | 
3772  |  | #endif  | 
3773  | 0  |     return result;  | 
3774  | 0  | }  | 
3775  |  |  | 
3776  |  |  | 
3777  |  |  | 
3778  |  |  | 
3779  |  | // -------------------------------------  | 
3780  |  |  | 
3781  |  | void  | 
3782  |  | Calendar::setWeekData(const Locale& desiredLocale, const char *type, UErrorCode& status)  | 
3783  | 0  | { | 
3784  |  | 
  | 
3785  | 0  |     if (U_FAILURE(status)) return;  | 
3786  |  |  | 
3787  | 0  |     fFirstDayOfWeek = UCAL_SUNDAY;  | 
3788  | 0  |     fMinimalDaysInFirstWeek = 1;  | 
3789  | 0  |     fWeekendOnset = UCAL_SATURDAY;  | 
3790  | 0  |     fWeekendOnsetMillis = 0;  | 
3791  | 0  |     fWeekendCease = UCAL_SUNDAY;  | 
3792  | 0  |     fWeekendCeaseMillis = 86400000; // 24*60*60*1000  | 
3793  |  |  | 
3794  |  |     // Since week and weekend data is territory based instead of language based,  | 
3795  |  |     // we may need to tweak the locale that we are using to try to get the appropriate  | 
3796  |  |     // values, using the following logic:  | 
3797  |  |     // 1). If the locale has a language but no territory, use the territory as defined by  | 
3798  |  |     //     the likely subtags.  | 
3799  |  |     // 2). If the locale has a script designation then we ignore it,  | 
3800  |  |     //     then remove it ( i.e. "en_Latn_US" becomes "en_US" )  | 
3801  |  | 
  | 
3802  | 0  |     UErrorCode myStatus = U_ZERO_ERROR;  | 
3803  |  | 
  | 
3804  | 0  |     Locale min(desiredLocale);  | 
3805  | 0  |     min.minimizeSubtags(myStatus);  | 
3806  | 0  |     Locale useLocale;  | 
3807  | 0  |     if ( uprv_strlen(desiredLocale.getCountry()) == 0 ||  | 
3808  | 0  |          (uprv_strlen(desiredLocale.getScript()) > 0 && uprv_strlen(min.getScript()) == 0) ) { | 
3809  | 0  |         myStatus = U_ZERO_ERROR;  | 
3810  | 0  |         Locale max(desiredLocale);  | 
3811  | 0  |         max.addLikelySubtags(myStatus);  | 
3812  | 0  |         useLocale = Locale(max.getLanguage(),max.getCountry());  | 
3813  | 0  |     } else { | 
3814  | 0  |         useLocale = desiredLocale;  | 
3815  | 0  |     }  | 
3816  |  |  | 
3817  |  |     /* The code here is somewhat of a hack, since week data and weekend data aren't really tied to  | 
3818  |  |        a specific calendar, they aren't truly locale data.  But this is the only place where valid and  | 
3819  |  |        actual locale can be set, so we take a shot at it here by loading a representative resource  | 
3820  |  |        from the calendar data.  The code used to use the dateTimeElements resource to get first day  | 
3821  |  |        of week data, but this was moved to supplemental data under ticket 7755. (JCE) */  | 
3822  |  |  | 
3823  |  |     // Get the monthNames resource bundle for the calendar 'type'. Fallback to gregorian if the resource is not  | 
3824  |  |     // found.  | 
3825  | 0  |     LocalUResourceBundlePointer calData(ures_open(NULL, useLocale.getBaseName(), &status));  | 
3826  | 0  |     ures_getByKey(calData.getAlias(), gCalendar, calData.getAlias(), &status);  | 
3827  |  | 
  | 
3828  | 0  |     LocalUResourceBundlePointer monthNames;  | 
3829  | 0  |     if (type != NULL && *type != '\0' && uprv_strcmp(type, gGregorian) != 0) { | 
3830  | 0  |         monthNames.adoptInstead(ures_getByKeyWithFallback(calData.getAlias(), type, NULL, &status));  | 
3831  | 0  |         ures_getByKeyWithFallback(monthNames.getAlias(), gMonthNames,  | 
3832  | 0  |                                   monthNames.getAlias(), &status);  | 
3833  | 0  |     }  | 
3834  |  | 
  | 
3835  | 0  |     if (monthNames.isNull() || status == U_MISSING_RESOURCE_ERROR) { | 
3836  | 0  |         status = U_ZERO_ERROR;  | 
3837  | 0  |         monthNames.adoptInstead(ures_getByKeyWithFallback(calData.getAlias(), gGregorian,  | 
3838  | 0  |                                                           monthNames.orphan(), &status));  | 
3839  | 0  |         ures_getByKeyWithFallback(monthNames.getAlias(), gMonthNames,  | 
3840  | 0  |                                   monthNames.getAlias(), &status);  | 
3841  | 0  |     }  | 
3842  |  | 
  | 
3843  | 0  |     if (U_SUCCESS(status)) { | 
3844  | 0  |         U_LOCALE_BASED(locBased,*this);  | 
3845  | 0  |         locBased.setLocaleIDs(ures_getLocaleByType(monthNames.getAlias(), ULOC_VALID_LOCALE, &status),  | 
3846  | 0  |                               ures_getLocaleByType(monthNames.getAlias(), ULOC_ACTUAL_LOCALE, &status));  | 
3847  | 0  |     } else { | 
3848  | 0  |         status = U_USING_FALLBACK_WARNING;  | 
3849  | 0  |         return;  | 
3850  | 0  |     }  | 
3851  |  |  | 
3852  | 0  |     char region[ULOC_COUNTRY_CAPACITY];  | 
3853  | 0  |     (void)ulocimp_getRegionForSupplementalData(desiredLocale.getName(), TRUE, region, sizeof(region), &status);  | 
3854  |  |  | 
3855  |  |     // Read week data values from supplementalData week data  | 
3856  | 0  |     UResourceBundle *rb = ures_openDirect(NULL, "supplementalData", &status);  | 
3857  | 0  |     ures_getByKey(rb, "weekData", rb, &status);  | 
3858  | 0  |     UResourceBundle *weekData = ures_getByKey(rb, region, NULL, &status);  | 
3859  | 0  |     if (status == U_MISSING_RESOURCE_ERROR && rb != NULL) { | 
3860  | 0  |         status = U_ZERO_ERROR;  | 
3861  | 0  |         weekData = ures_getByKey(rb, "001", NULL, &status);  | 
3862  | 0  |     }  | 
3863  |  | 
  | 
3864  | 0  |     if (U_FAILURE(status)) { | 
3865  | 0  |         status = U_USING_FALLBACK_WARNING;  | 
3866  | 0  |     } else { | 
3867  | 0  |         int32_t arrLen;  | 
3868  | 0  |         const int32_t *weekDataArr = ures_getIntVector(weekData,&arrLen,&status);  | 
3869  | 0  |         if( U_SUCCESS(status) && arrLen == 6  | 
3870  | 0  |                 && 1 <= weekDataArr[0] && weekDataArr[0] <= 7  | 
3871  | 0  |                 && 1 <= weekDataArr[1] && weekDataArr[1] <= 7  | 
3872  | 0  |                 && 1 <= weekDataArr[2] && weekDataArr[2] <= 7  | 
3873  | 0  |                 && 1 <= weekDataArr[4] && weekDataArr[4] <= 7) { | 
3874  | 0  |             fFirstDayOfWeek = (UCalendarDaysOfWeek)weekDataArr[0];  | 
3875  | 0  |             fMinimalDaysInFirstWeek = (uint8_t)weekDataArr[1];  | 
3876  | 0  |             fWeekendOnset = (UCalendarDaysOfWeek)weekDataArr[2];  | 
3877  | 0  |             fWeekendOnsetMillis = weekDataArr[3];  | 
3878  | 0  |             fWeekendCease = (UCalendarDaysOfWeek)weekDataArr[4];  | 
3879  | 0  |             fWeekendCeaseMillis = weekDataArr[5];  | 
3880  | 0  |         } else { | 
3881  | 0  |             status = U_INVALID_FORMAT_ERROR;  | 
3882  | 0  |         }  | 
3883  | 0  |     }  | 
3884  | 0  |     ures_close(weekData);  | 
3885  | 0  |     ures_close(rb);  | 
3886  | 0  | }  | 
3887  |  |  | 
3888  |  | /**  | 
3889  |  | * Recompute the time and update the status fields isTimeSet  | 
3890  |  | * and areFieldsSet.  Callers should check isTimeSet and only  | 
3891  |  | * call this method if isTimeSet is false.  | 
3892  |  | */  | 
3893  |  | void  | 
3894  |  | Calendar::updateTime(UErrorCode& status)  | 
3895  | 0  | { | 
3896  | 0  |     computeTime(status);  | 
3897  | 0  |     if(U_FAILURE(status))  | 
3898  | 0  |         return;  | 
3899  |  |  | 
3900  |  |     // If we are lenient, we need to recompute the fields to normalize  | 
3901  |  |     // the values.  Also, if we haven't set all the fields yet (i.e.,  | 
3902  |  |     // in a newly-created object), we need to fill in the fields. [LIU]  | 
3903  | 0  |     if (isLenient() || ! fAreAllFieldsSet)  | 
3904  | 0  |         fAreFieldsSet = FALSE;  | 
3905  |  | 
  | 
3906  | 0  |     fIsTimeSet = TRUE;  | 
3907  | 0  |     fAreFieldsVirtuallySet = FALSE;  | 
3908  | 0  | }  | 
3909  |  |  | 
3910  |  | Locale  | 
3911  | 0  | Calendar::getLocale(ULocDataLocaleType type, UErrorCode& status) const { | 
3912  | 0  |     U_LOCALE_BASED(locBased, *this);  | 
3913  | 0  |     return locBased.getLocale(type, status);  | 
3914  | 0  | }  | 
3915  |  |  | 
3916  |  | const char *  | 
3917  | 0  | Calendar::getLocaleID(ULocDataLocaleType type, UErrorCode& status) const { | 
3918  | 0  |     U_LOCALE_BASED(locBased, *this);  | 
3919  | 0  |     return locBased.getLocaleID(type, status);  | 
3920  | 0  | }  | 
3921  |  |  | 
3922  |  | void  | 
3923  | 0  | Calendar::recalculateStamp() { | 
3924  | 0  |     int32_t index;  | 
3925  | 0  |     int32_t currentValue;  | 
3926  | 0  |     int32_t j, i;  | 
3927  |  | 
  | 
3928  | 0  |     fNextStamp = 1;  | 
3929  |  | 
  | 
3930  | 0  |     for (j = 0; j < UCAL_FIELD_COUNT; j++) { | 
3931  | 0  |         currentValue = STAMP_MAX;  | 
3932  | 0  |         index = -1;  | 
3933  | 0  |         for (i = 0; i < UCAL_FIELD_COUNT; i++) { | 
3934  | 0  |             if (fStamp[i] > fNextStamp && fStamp[i] < currentValue) { | 
3935  | 0  |                 currentValue = fStamp[i];  | 
3936  | 0  |                 index = i;  | 
3937  | 0  |             }  | 
3938  | 0  |         }  | 
3939  |  | 
  | 
3940  | 0  |         if (index >= 0) { | 
3941  | 0  |             fStamp[index] = ++fNextStamp;  | 
3942  | 0  |         } else { | 
3943  | 0  |             break;  | 
3944  | 0  |         }  | 
3945  | 0  |     }  | 
3946  | 0  |     fNextStamp++;  | 
3947  | 0  | }  | 
3948  |  |  | 
3949  |  | // Deprecated function. This doesn't need to be inline.  | 
3950  |  | void  | 
3951  |  | Calendar::internalSet(EDateFields field, int32_t value)  | 
3952  | 0  | { | 
3953  | 0  |     internalSet((UCalendarDateFields) field, value);  | 
3954  | 0  | }  | 
3955  |  |  | 
3956  |  | BasicTimeZone*  | 
3957  | 0  | Calendar::getBasicTimeZone(void) const { | 
3958  | 0  |     if (dynamic_cast<const OlsonTimeZone *>(fZone) != NULL  | 
3959  | 0  |         || dynamic_cast<const SimpleTimeZone *>(fZone) != NULL  | 
3960  | 0  |         || dynamic_cast<const RuleBasedTimeZone *>(fZone) != NULL  | 
3961  | 0  |         || dynamic_cast<const VTimeZone *>(fZone) != NULL) { | 
3962  | 0  |         return (BasicTimeZone*)fZone;  | 
3963  | 0  |     }  | 
3964  | 0  |     return NULL;  | 
3965  | 0  | }  | 
3966  |  |  | 
3967  |  | U_NAMESPACE_END  | 
3968  |  |  | 
3969  |  | #endif /* #if !UCONFIG_NO_FORMATTING */  | 
3970  |  |  | 
3971  |  |  | 
3972  |  | //eof  |