LCOV - code coverage report
Current view: top level - intl/icu/source/i18n - calendar.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 1499 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 139 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13