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