intl/icu/source/i18n/calendar.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/intl/icu/source/i18n/calendar.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,3699 @@
     1.4 +/*
     1.5 +*******************************************************************************
     1.6 +* Copyright (C) 1997-2013, International Business Machines Corporation and    *
     1.7 +* others. All Rights Reserved.                                                *
     1.8 +*******************************************************************************
     1.9 +*
    1.10 +* File CALENDAR.CPP
    1.11 +*
    1.12 +* Modification History: 
    1.13 +*
    1.14 +*   Date        Name        Description
    1.15 +*   02/03/97    clhuang     Creation.
    1.16 +*   04/22/97    aliu        Cleaned up, fixed memory leak, made 
    1.17 +*                           setWeekCountData() more robust.  
    1.18 +*                           Moved platform code to TPlatformUtilities.
    1.19 +*   05/01/97    aliu        Made equals(), before(), after() arguments const.
    1.20 +*   05/20/97    aliu        Changed logic of when to compute fields and time
    1.21 +*                           to fix bugs.
    1.22 +*   08/12/97    aliu        Added equivalentTo.  Misc other fixes.
    1.23 +*   07/28/98    stephen     Sync up with JDK 1.2
    1.24 +*   09/02/98    stephen     Sync with JDK 1.2 8/31 build (getActualMin/Max)
    1.25 +*   03/17/99    stephen     Changed adoptTimeZone() - now fAreFieldsSet is
    1.26 +*                           set to FALSE to force update of time.
    1.27 +*******************************************************************************
    1.28 +*/
    1.29 +
    1.30 +#include "utypeinfo.h"  // for 'typeid' to work 
    1.31 +
    1.32 +#include "unicode/utypes.h"
    1.33 +
    1.34 +#if !UCONFIG_NO_FORMATTING
    1.35 +
    1.36 +#include "unicode/gregocal.h"
    1.37 +#include "unicode/basictz.h"
    1.38 +#include "unicode/simpletz.h"
    1.39 +#include "unicode/rbtz.h"
    1.40 +#include "unicode/vtzone.h"
    1.41 +#include "gregoimp.h"
    1.42 +#include "buddhcal.h"
    1.43 +#include "taiwncal.h"
    1.44 +#include "japancal.h"
    1.45 +#include "islamcal.h"
    1.46 +#include "hebrwcal.h"
    1.47 +#include "persncal.h"
    1.48 +#include "indiancal.h"
    1.49 +#include "chnsecal.h"
    1.50 +#include "coptccal.h"
    1.51 +#include "dangical.h"
    1.52 +#include "ethpccal.h"
    1.53 +#include "unicode/calendar.h"
    1.54 +#include "cpputils.h"
    1.55 +#include "servloc.h"
    1.56 +#include "ucln_in.h"
    1.57 +#include "cstring.h"
    1.58 +#include "locbased.h"
    1.59 +#include "uresimp.h"
    1.60 +#include "ustrenum.h"
    1.61 +#include "uassert.h"
    1.62 +#include "olsontz.h"
    1.63 +
    1.64 +#if !UCONFIG_NO_SERVICE
    1.65 +static icu::ICULocaleService* gService = NULL;
    1.66 +static icu::UInitOnce gServiceInitOnce = U_INITONCE_INITIALIZER;
    1.67 +#endif
    1.68 +
    1.69 +// INTERNAL - for cleanup
    1.70 +
    1.71 +U_CDECL_BEGIN
    1.72 +static UBool calendar_cleanup(void) {
    1.73 +#if !UCONFIG_NO_SERVICE
    1.74 +    if (gService) {
    1.75 +        delete gService;
    1.76 +        gService = NULL;
    1.77 +    }
    1.78 +    gServiceInitOnce.reset();
    1.79 +#endif
    1.80 +    return TRUE;
    1.81 +}
    1.82 +U_CDECL_END
    1.83 +
    1.84 +// ------------------------------------------
    1.85 +//
    1.86 +// Registration
    1.87 +//
    1.88 +//-------------------------------------------
    1.89 +//#define U_DEBUG_CALSVC 1
    1.90 +//
    1.91 +
    1.92 +#if defined( U_DEBUG_CALSVC ) || defined (U_DEBUG_CAL)
    1.93 +
    1.94 +/** 
    1.95 + * fldName was removed as a duplicate implementation. 
    1.96 + * use  udbg_ services instead, 
    1.97 + * which depend on include files and library from ../tools/toolutil, the following circular link:
    1.98 + *   CPPFLAGS+=-I$(top_srcdir)/tools/toolutil
    1.99 + *   LIBS+=$(LIBICUTOOLUTIL)
   1.100 + */
   1.101 +#include "udbgutil.h"
   1.102 +#include <stdio.h>
   1.103 +
   1.104 +/**
   1.105 +* convert a UCalendarDateFields into a string - for debugging
   1.106 +* @param f field enum
   1.107 +* @return static string to the field name
   1.108 +* @internal
   1.109 +*/
   1.110 +
   1.111 +const char* fldName(UCalendarDateFields f) {
   1.112 +	return udbg_enumName(UDBG_UCalendarDateFields, (int32_t)f);
   1.113 +}
   1.114 +
   1.115 +#if UCAL_DEBUG_DUMP
   1.116 +// from CalendarTest::calToStr - but doesn't modify contents.
   1.117 +void ucal_dump(const Calendar &cal) {
   1.118 +    cal.dump();
   1.119 +}
   1.120 +
   1.121 +void Calendar::dump() const {
   1.122 +    int i;
   1.123 +    fprintf(stderr, "@calendar=%s, timeset=%c, fieldset=%c, allfields=%c, virtualset=%c, t=%.2f",
   1.124 +        getType(), fIsTimeSet?'y':'n',  fAreFieldsSet?'y':'n',  fAreAllFieldsSet?'y':'n',  
   1.125 +        fAreFieldsVirtuallySet?'y':'n',
   1.126 +        fTime);
   1.127 +
   1.128 +    // can add more things here: DST, zone, etc.
   1.129 +    fprintf(stderr, "\n");
   1.130 +    for(i = 0;i<UCAL_FIELD_COUNT;i++) {
   1.131 +        int n;
   1.132 +        const char *f = fldName((UCalendarDateFields)i);
   1.133 +        fprintf(stderr, "  %25s: %-11ld", f, fFields[i]);
   1.134 +        if(fStamp[i] == kUnset) {
   1.135 +            fprintf(stderr, " (unset) ");
   1.136 +        } else if(fStamp[i] == kInternallySet) { 
   1.137 +            fprintf(stderr, " (internally set) ");
   1.138 +            //} else if(fStamp[i] == kInternalDefault) { 
   1.139 +            //    fprintf(stderr, " (internal default) ");
   1.140 +        } else {
   1.141 +            fprintf(stderr, " %%%d ", fStamp[i]);
   1.142 +        }
   1.143 +        fprintf(stderr, "\n");
   1.144 +
   1.145 +    }
   1.146 +}
   1.147 +
   1.148 +U_CFUNC void ucal_dump(UCalendar* cal) {
   1.149 +    ucal_dump( *((Calendar*)cal)  );
   1.150 +}
   1.151 +#endif
   1.152 +
   1.153 +#endif
   1.154 +
   1.155 +/* Max value for stamp allowable before recalculation */
   1.156 +#define STAMP_MAX 10000
   1.157 +
   1.158 +static const char * const gCalTypes[] = {
   1.159 +    "gregorian",
   1.160 +    "japanese",
   1.161 +    "buddhist",
   1.162 +    "roc",
   1.163 +    "persian",
   1.164 +    "islamic-civil",
   1.165 +    "islamic",
   1.166 +    "hebrew",
   1.167 +    "chinese",
   1.168 +    "indian",
   1.169 +    "coptic",
   1.170 +    "ethiopic",
   1.171 +    "ethiopic-amete-alem",
   1.172 +    "iso8601",
   1.173 +    "dangi",
   1.174 +    "islamic-umalqura",
   1.175 +    "islamic-tbla",
   1.176 +    "islamic-rgsa",
   1.177 +    NULL
   1.178 +};
   1.179 +
   1.180 +// Must be in the order of gCalTypes above
   1.181 +typedef enum ECalType {
   1.182 +    CALTYPE_UNKNOWN = -1,
   1.183 +    CALTYPE_GREGORIAN = 0,
   1.184 +    CALTYPE_JAPANESE,
   1.185 +    CALTYPE_BUDDHIST,
   1.186 +    CALTYPE_ROC,
   1.187 +    CALTYPE_PERSIAN,
   1.188 +    CALTYPE_ISLAMIC_CIVIL,
   1.189 +    CALTYPE_ISLAMIC,
   1.190 +    CALTYPE_HEBREW,
   1.191 +    CALTYPE_CHINESE,
   1.192 +    CALTYPE_INDIAN,
   1.193 +    CALTYPE_COPTIC,
   1.194 +    CALTYPE_ETHIOPIC,
   1.195 +    CALTYPE_ETHIOPIC_AMETE_ALEM,
   1.196 +    CALTYPE_ISO8601,
   1.197 +    CALTYPE_DANGI,
   1.198 +    CALTYPE_ISLAMIC_UMALQURA,
   1.199 +    CALTYPE_ISLAMIC_TBLA,
   1.200 +    CALTYPE_ISLAMIC_RGSA
   1.201 +} ECalType;
   1.202 +
   1.203 +U_NAMESPACE_BEGIN
   1.204 +
   1.205 +static ECalType getCalendarType(const char *s) {
   1.206 +    for (int i = 0; gCalTypes[i] != NULL; i++) {
   1.207 +        if (uprv_stricmp(s, gCalTypes[i]) == 0) {
   1.208 +            return (ECalType)i;
   1.209 +        }
   1.210 +    }
   1.211 +    return CALTYPE_UNKNOWN;
   1.212 +}
   1.213 +
   1.214 +static UBool isStandardSupportedKeyword(const char *keyword, UErrorCode& status) { 
   1.215 +    if(U_FAILURE(status)) {
   1.216 +        return FALSE;
   1.217 +    }
   1.218 +    ECalType calType = getCalendarType(keyword);
   1.219 +    return (calType != CALTYPE_UNKNOWN);
   1.220 +}
   1.221 +
   1.222 +static void getCalendarKeyword(const UnicodeString &id, char *targetBuffer, int32_t targetBufferSize) {
   1.223 +    UnicodeString calendarKeyword = UNICODE_STRING_SIMPLE("calendar=");
   1.224 +    int32_t calKeyLen = calendarKeyword.length();
   1.225 +    int32_t keyLen = 0;
   1.226 +
   1.227 +    int32_t keywordIdx = id.indexOf((UChar)0x003D); /* '=' */
   1.228 +    if (id[0] == 0x40/*'@'*/
   1.229 +        && id.compareBetween(1, keywordIdx+1, calendarKeyword, 0, calKeyLen) == 0)
   1.230 +    {
   1.231 +        keyLen = id.extract(keywordIdx+1, id.length(), targetBuffer, targetBufferSize, US_INV);
   1.232 +    }
   1.233 +    targetBuffer[keyLen] = 0;
   1.234 +}
   1.235 +
   1.236 +static ECalType getCalendarTypeForLocale(const char *locid) {
   1.237 +    UErrorCode status = U_ZERO_ERROR;
   1.238 +    ECalType calType = CALTYPE_UNKNOWN;
   1.239 +
   1.240 +    //TODO: ULOC_FULL_NAME is out of date and too small..
   1.241 +    char canonicalName[256];
   1.242 +
   1.243 +    // canonicalize, so grandfathered variant will be transformed to keywords
   1.244 +    // e.g ja_JP_TRADITIONAL -> ja_JP@calendar=japanese
   1.245 +    int32_t canonicalLen = uloc_canonicalize(locid, canonicalName, sizeof(canonicalName) - 1, &status);
   1.246 +    if (U_FAILURE(status)) {
   1.247 +        return CALTYPE_GREGORIAN;
   1.248 +    }
   1.249 +    canonicalName[canonicalLen] = 0;    // terminate
   1.250 +
   1.251 +    char calTypeBuf[32];
   1.252 +    int32_t calTypeBufLen;
   1.253 +
   1.254 +    calTypeBufLen = uloc_getKeywordValue(canonicalName, "calendar", calTypeBuf, sizeof(calTypeBuf) - 1, &status);
   1.255 +    if (U_SUCCESS(status)) {
   1.256 +        calTypeBuf[calTypeBufLen] = 0;
   1.257 +        calType = getCalendarType(calTypeBuf);
   1.258 +        if (calType != CALTYPE_UNKNOWN) {
   1.259 +            return calType;
   1.260 +        }
   1.261 +    }
   1.262 +    status = U_ZERO_ERROR;
   1.263 +
   1.264 +    // when calendar keyword is not available or not supported, read supplementalData
   1.265 +    // to get the default calendar type for the locale's region
   1.266 +    char region[ULOC_COUNTRY_CAPACITY];
   1.267 +    int32_t regionLen = 0;
   1.268 +    regionLen = uloc_getCountry(canonicalName, region, sizeof(region) - 1, &status);
   1.269 +    if (regionLen == 0) {
   1.270 +        char fullLoc[256];
   1.271 +        uloc_addLikelySubtags(locid, fullLoc, sizeof(fullLoc) - 1, &status);
   1.272 +        regionLen = uloc_getCountry(fullLoc, region, sizeof(region) - 1, &status);
   1.273 +    }
   1.274 +    if (U_FAILURE(status)) {
   1.275 +        return CALTYPE_GREGORIAN;
   1.276 +    }
   1.277 +    region[regionLen] = 0;
   1.278 +    
   1.279 +    // Read preferred calendar values from supplementalData calendarPreference
   1.280 +    UResourceBundle *rb = ures_openDirect(NULL, "supplementalData", &status);
   1.281 +    ures_getByKey(rb, "calendarPreferenceData", rb, &status);
   1.282 +    UResourceBundle *order = ures_getByKey(rb, region, NULL, &status);
   1.283 +    if (status == U_MISSING_RESOURCE_ERROR && rb != NULL) {
   1.284 +        status = U_ZERO_ERROR;
   1.285 +        order = ures_getByKey(rb, "001", NULL, &status);
   1.286 +    }
   1.287 +
   1.288 +    calTypeBuf[0] = 0;
   1.289 +    if (U_SUCCESS(status) && order != NULL) {
   1.290 +        // the first calender type is the default for the region
   1.291 +        int32_t len = 0;
   1.292 +        const UChar *uCalType = ures_getStringByIndex(order, 0, &len, &status);
   1.293 +        if (len < (int32_t)sizeof(calTypeBuf)) {
   1.294 +            u_UCharsToChars(uCalType, calTypeBuf, len);
   1.295 +            *(calTypeBuf + len) = 0; // terminate;
   1.296 +            calType = getCalendarType(calTypeBuf);
   1.297 +        }
   1.298 +    }
   1.299 +
   1.300 +    ures_close(order);
   1.301 +    ures_close(rb);
   1.302 +
   1.303 +    if (calType == CALTYPE_UNKNOWN) {
   1.304 +        // final fallback
   1.305 +        calType = CALTYPE_GREGORIAN;
   1.306 +    }
   1.307 +    return calType;
   1.308 +}
   1.309 +
   1.310 +static Calendar *createStandardCalendar(ECalType calType, const Locale &loc, UErrorCode& status) {
   1.311 +    Calendar *cal = NULL;
   1.312 +
   1.313 +    switch (calType) {
   1.314 +        case CALTYPE_GREGORIAN:
   1.315 +            cal = new GregorianCalendar(loc, status);
   1.316 +            break;
   1.317 +        case CALTYPE_JAPANESE:
   1.318 +            cal = new JapaneseCalendar(loc, status);
   1.319 +            break;
   1.320 +        case CALTYPE_BUDDHIST:
   1.321 +            cal = new BuddhistCalendar(loc, status);
   1.322 +            break;
   1.323 +        case CALTYPE_ROC:
   1.324 +            cal = new TaiwanCalendar(loc, status);
   1.325 +            break;
   1.326 +        case CALTYPE_PERSIAN:
   1.327 +            cal = new PersianCalendar(loc, status);
   1.328 +            break;
   1.329 +        case CALTYPE_ISLAMIC_TBLA:
   1.330 +            cal = new IslamicCalendar(loc, status, IslamicCalendar::TBLA);
   1.331 +            break;
   1.332 +        case CALTYPE_ISLAMIC_CIVIL:
   1.333 +            cal = new IslamicCalendar(loc, status, IslamicCalendar::CIVIL);
   1.334 +            break;
   1.335 +        case CALTYPE_ISLAMIC_RGSA:
   1.336 +            // default any region specific not handled individually to islamic
   1.337 +        case CALTYPE_ISLAMIC:
   1.338 +            cal = new IslamicCalendar(loc, status, IslamicCalendar::ASTRONOMICAL);
   1.339 +            break;
   1.340 +        case CALTYPE_ISLAMIC_UMALQURA:
   1.341 +            cal = new IslamicCalendar(loc, status, IslamicCalendar::UMALQURA);
   1.342 +            break;
   1.343 +        case CALTYPE_HEBREW:
   1.344 +            cal = new HebrewCalendar(loc, status);
   1.345 +            break;
   1.346 +        case CALTYPE_CHINESE:
   1.347 +            cal = new ChineseCalendar(loc, status);
   1.348 +            break;
   1.349 +        case CALTYPE_INDIAN:
   1.350 +            cal = new IndianCalendar(loc, status);
   1.351 +            break;
   1.352 +        case CALTYPE_COPTIC:
   1.353 +            cal = new CopticCalendar(loc, status);
   1.354 +            break;
   1.355 +        case CALTYPE_ETHIOPIC:
   1.356 +            cal = new EthiopicCalendar(loc, status, EthiopicCalendar::AMETE_MIHRET_ERA);
   1.357 +            break;
   1.358 +        case CALTYPE_ETHIOPIC_AMETE_ALEM:
   1.359 +            cal = new EthiopicCalendar(loc, status, EthiopicCalendar::AMETE_ALEM_ERA);
   1.360 +            break;
   1.361 +        case CALTYPE_ISO8601:
   1.362 +            cal = new GregorianCalendar(loc, status);
   1.363 +            cal->setFirstDayOfWeek(UCAL_MONDAY);
   1.364 +            cal->setMinimalDaysInFirstWeek(4);
   1.365 +            break;
   1.366 +        case CALTYPE_DANGI:
   1.367 +            cal = new DangiCalendar(loc, status);
   1.368 +            break;
   1.369 +        default:
   1.370 +            status = U_UNSUPPORTED_ERROR;
   1.371 +    }
   1.372 +    return cal;
   1.373 +}
   1.374 +
   1.375 +
   1.376 +#if !UCONFIG_NO_SERVICE
   1.377 +
   1.378 +// -------------------------------------
   1.379 +
   1.380 +/**
   1.381 +* a Calendar Factory which creates the "basic" calendar types, that is, those 
   1.382 +* shipped with ICU.
   1.383 +*/
   1.384 +class BasicCalendarFactory : public LocaleKeyFactory {
   1.385 +public:
   1.386 +    /**
   1.387 +    * @param calendarType static const string (caller owns storage - will be aliased) to calendar type
   1.388 +    */
   1.389 +    BasicCalendarFactory()
   1.390 +        : LocaleKeyFactory(LocaleKeyFactory::INVISIBLE) { }
   1.391 +
   1.392 +    virtual ~BasicCalendarFactory();
   1.393 +
   1.394 +protected:
   1.395 +    //virtual UBool isSupportedID( const UnicodeString& id, UErrorCode& status) const { 
   1.396 +    //  if(U_FAILURE(status)) {
   1.397 +    //    return FALSE;
   1.398 +    //  }
   1.399 +    //  char keyword[ULOC_FULLNAME_CAPACITY];
   1.400 +    //  getCalendarKeyword(id, keyword, (int32_t)sizeof(keyword));
   1.401 +    //  return isStandardSupportedKeyword(keyword, status);
   1.402 +    //}
   1.403 +
   1.404 +    virtual void updateVisibleIDs(Hashtable& result, UErrorCode& status) const
   1.405 +    {
   1.406 +        if (U_SUCCESS(status)) {
   1.407 +            for(int32_t i=0;gCalTypes[i] != NULL;i++) {
   1.408 +                UnicodeString id((UChar)0x40); /* '@' a variant character */
   1.409 +                id.append(UNICODE_STRING_SIMPLE("calendar="));
   1.410 +                id.append(UnicodeString(gCalTypes[i], -1, US_INV));
   1.411 +                result.put(id, (void*)this, status);
   1.412 +            }
   1.413 +        }
   1.414 +    }
   1.415 +
   1.416 +    virtual UObject* create(const ICUServiceKey& key, const ICUService* /*service*/, UErrorCode& status) const {
   1.417 +#ifdef U_DEBUG_CALSVC
   1.418 +        if(dynamic_cast<const LocaleKey*>(&key) == NULL) {
   1.419 +            fprintf(stderr, "::create - not a LocaleKey!\n");
   1.420 +        }
   1.421 +#endif
   1.422 +        const LocaleKey& lkey = (LocaleKey&)key;
   1.423 +        Locale curLoc;  // current locale
   1.424 +        Locale canLoc;  // Canonical locale
   1.425 +
   1.426 +        lkey.currentLocale(curLoc);
   1.427 +        lkey.canonicalLocale(canLoc);
   1.428 +
   1.429 +        char keyword[ULOC_FULLNAME_CAPACITY];
   1.430 +        UnicodeString str;
   1.431 +
   1.432 +        key.currentID(str);
   1.433 +        getCalendarKeyword(str, keyword, (int32_t) sizeof(keyword));
   1.434 +
   1.435 +#ifdef U_DEBUG_CALSVC
   1.436 +        fprintf(stderr, "BasicCalendarFactory::create() - cur %s, can %s\n", (const char*)curLoc.getName(), (const char*)canLoc.getName());
   1.437 +#endif
   1.438 +
   1.439 +        if(!isStandardSupportedKeyword(keyword,status)) {  // Do we handle this type?
   1.440 +#ifdef U_DEBUG_CALSVC
   1.441 +
   1.442 +            fprintf(stderr, "BasicCalendarFactory - not handling %s.[%s]\n", (const char*) curLoc.getName(), tmp );
   1.443 +#endif
   1.444 +            return NULL;
   1.445 +        }
   1.446 +
   1.447 +        return createStandardCalendar(getCalendarType(keyword), canLoc, status);
   1.448 +    }
   1.449 +};
   1.450 +
   1.451 +BasicCalendarFactory::~BasicCalendarFactory() {}
   1.452 +
   1.453 +/** 
   1.454 +* A factory which looks up the DefaultCalendar resource to determine which class of calendar to use
   1.455 +*/
   1.456 +
   1.457 +class DefaultCalendarFactory : public ICUResourceBundleFactory {
   1.458 +public:
   1.459 +    DefaultCalendarFactory() : ICUResourceBundleFactory() { }
   1.460 +    virtual ~DefaultCalendarFactory();
   1.461 +protected:
   1.462 +    virtual UObject* create(const ICUServiceKey& key, const ICUService* /*service*/, UErrorCode& status) const  {
   1.463 +
   1.464 +        LocaleKey &lkey = (LocaleKey&)key;
   1.465 +        Locale loc;
   1.466 +        lkey.currentLocale(loc);
   1.467 +
   1.468 +        UnicodeString *ret = new UnicodeString();
   1.469 +        if (ret == NULL) {
   1.470 +            status = U_MEMORY_ALLOCATION_ERROR;
   1.471 +        } else {
   1.472 +            ret->append((UChar)0x40); // '@' is a variant character
   1.473 +            ret->append(UNICODE_STRING("calendar=", 9));
   1.474 +            ret->append(UnicodeString(gCalTypes[getCalendarTypeForLocale(loc.getName())], -1, US_INV));
   1.475 +        }
   1.476 +        return ret;
   1.477 +    }
   1.478 +};
   1.479 +
   1.480 +DefaultCalendarFactory::~DefaultCalendarFactory() {}
   1.481 +
   1.482 +// -------------------------------------
   1.483 +class CalendarService : public ICULocaleService {
   1.484 +public:
   1.485 +    CalendarService()
   1.486 +        : ICULocaleService(UNICODE_STRING_SIMPLE("Calendar"))
   1.487 +    {
   1.488 +        UErrorCode status = U_ZERO_ERROR;
   1.489 +        registerFactory(new DefaultCalendarFactory(), status);
   1.490 +    }
   1.491 +
   1.492 +    virtual ~CalendarService();
   1.493 +
   1.494 +    virtual UObject* cloneInstance(UObject* instance) const {
   1.495 +        UnicodeString *s = dynamic_cast<UnicodeString *>(instance);
   1.496 +        if(s != NULL) {
   1.497 +            return s->clone(); 
   1.498 +        } else {
   1.499 +#ifdef U_DEBUG_CALSVC_F
   1.500 +            UErrorCode status2 = U_ZERO_ERROR;
   1.501 +            fprintf(stderr, "Cloning a %s calendar with tz=%ld\n", ((Calendar*)instance)->getType(), ((Calendar*)instance)->get(UCAL_ZONE_OFFSET, status2));
   1.502 +#endif
   1.503 +            return ((Calendar*)instance)->clone();
   1.504 +        }
   1.505 +    }
   1.506 +
   1.507 +    virtual UObject* handleDefault(const ICUServiceKey& key, UnicodeString* /*actualID*/, UErrorCode& status) const {
   1.508 +        LocaleKey& lkey = (LocaleKey&)key;
   1.509 +        //int32_t kind = lkey.kind();
   1.510 +
   1.511 +        Locale loc;
   1.512 +        lkey.canonicalLocale(loc);
   1.513 +
   1.514 +#ifdef U_DEBUG_CALSVC
   1.515 +        Locale loc2;
   1.516 +        lkey.currentLocale(loc2);
   1.517 +        fprintf(stderr, "CalSvc:handleDefault for currentLoc %s, canloc %s\n", (const char*)loc.getName(),  (const char*)loc2.getName());
   1.518 +#endif
   1.519 +        Calendar *nc =  new GregorianCalendar(loc, status);
   1.520 +
   1.521 +#ifdef U_DEBUG_CALSVC
   1.522 +        UErrorCode status2 = U_ZERO_ERROR;
   1.523 +        fprintf(stderr, "New default calendar has tz=%d\n", ((Calendar*)nc)->get(UCAL_ZONE_OFFSET, status2));
   1.524 +#endif
   1.525 +        return nc;
   1.526 +    }
   1.527 +
   1.528 +    virtual UBool isDefault() const {
   1.529 +        return countFactories() == 1;
   1.530 +    }
   1.531 +};
   1.532 +
   1.533 +CalendarService::~CalendarService() {}
   1.534 +
   1.535 +// -------------------------------------
   1.536 +
   1.537 +static inline UBool
   1.538 +isCalendarServiceUsed() {
   1.539 +    return !gServiceInitOnce.isReset();
   1.540 +}
   1.541 +
   1.542 +// -------------------------------------
   1.543 +
   1.544 +static void U_CALLCONV
   1.545 +initCalendarService(UErrorCode &status)
   1.546 +{
   1.547 +#ifdef U_DEBUG_CALSVC
   1.548 +        fprintf(stderr, "Spinning up Calendar Service\n");
   1.549 +#endif
   1.550 +    ucln_i18n_registerCleanup(UCLN_I18N_CALENDAR, calendar_cleanup);
   1.551 +    gService = new CalendarService();
   1.552 +    if (gService == NULL) {
   1.553 +            status = U_MEMORY_ALLOCATION_ERROR;
   1.554 +        return;
   1.555 +        }
   1.556 +#ifdef U_DEBUG_CALSVC
   1.557 +        fprintf(stderr, "Registering classes..\n");
   1.558 +#endif
   1.559 +
   1.560 +        // Register all basic instances. 
   1.561 +    gService->registerFactory(new BasicCalendarFactory(),status);
   1.562 +
   1.563 +#ifdef U_DEBUG_CALSVC
   1.564 +        fprintf(stderr, "Done..\n");
   1.565 +#endif
   1.566 +
   1.567 +        if(U_FAILURE(status)) {
   1.568 +#ifdef U_DEBUG_CALSVC
   1.569 +            fprintf(stderr, "err (%s) registering classes, deleting service.....\n", u_errorName(status));
   1.570 +#endif
   1.571 +        delete gService;
   1.572 +        gService = NULL;
   1.573 +    }
   1.574 +        }
   1.575 +
   1.576 +static ICULocaleService* 
   1.577 +getCalendarService(UErrorCode &status)
   1.578 +{
   1.579 +    umtx_initOnce(gServiceInitOnce, &initCalendarService, status);
   1.580 +    return gService;
   1.581 +}
   1.582 +
   1.583 +URegistryKey Calendar::registerFactory(ICUServiceFactory* toAdopt, UErrorCode& status)
   1.584 +{
   1.585 +    return getCalendarService(status)->registerFactory(toAdopt, status);
   1.586 +}
   1.587 +
   1.588 +UBool Calendar::unregister(URegistryKey key, UErrorCode& status) {
   1.589 +    return getCalendarService(status)->unregister(key, status);
   1.590 +}
   1.591 +#endif /* UCONFIG_NO_SERVICE */
   1.592 +
   1.593 +// -------------------------------------
   1.594 +
   1.595 +static const int32_t kCalendarLimits[UCAL_FIELD_COUNT][4] = {
   1.596 +    //    Minimum  Greatest min      Least max   Greatest max
   1.597 +    {/*N/A*/-1,       /*N/A*/-1,     /*N/A*/-1,       /*N/A*/-1}, // ERA
   1.598 +    {/*N/A*/-1,       /*N/A*/-1,     /*N/A*/-1,       /*N/A*/-1}, // YEAR
   1.599 +    {/*N/A*/-1,       /*N/A*/-1,     /*N/A*/-1,       /*N/A*/-1}, // MONTH
   1.600 +    {/*N/A*/-1,       /*N/A*/-1,     /*N/A*/-1,       /*N/A*/-1}, // WEEK_OF_YEAR
   1.601 +    {/*N/A*/-1,       /*N/A*/-1,     /*N/A*/-1,       /*N/A*/-1}, // WEEK_OF_MONTH
   1.602 +    {/*N/A*/-1,       /*N/A*/-1,     /*N/A*/-1,       /*N/A*/-1}, // DAY_OF_MONTH
   1.603 +    {/*N/A*/-1,       /*N/A*/-1,     /*N/A*/-1,       /*N/A*/-1}, // DAY_OF_YEAR
   1.604 +    {           1,            1,             7,             7  }, // DAY_OF_WEEK
   1.605 +    {/*N/A*/-1,       /*N/A*/-1,     /*N/A*/-1,       /*N/A*/-1}, // DAY_OF_WEEK_IN_MONTH
   1.606 +    {           0,            0,             1,             1  }, // AM_PM
   1.607 +    {           0,            0,            11,            11  }, // HOUR
   1.608 +    {           0,            0,            23,            23  }, // HOUR_OF_DAY
   1.609 +    {           0,            0,            59,            59  }, // MINUTE
   1.610 +    {           0,            0,            59,            59  }, // SECOND
   1.611 +    {           0,            0,           999,           999  }, // MILLISECOND
   1.612 +    {-12*kOneHour, -12*kOneHour,   12*kOneHour,   15*kOneHour  }, // ZONE_OFFSET
   1.613 +    {           0,            0,    1*kOneHour,    1*kOneHour  }, // DST_OFFSET
   1.614 +    {/*N/A*/-1,       /*N/A*/-1,     /*N/A*/-1,       /*N/A*/-1}, // YEAR_WOY
   1.615 +    {           1,            1,             7,             7  }, // DOW_LOCAL
   1.616 +    {/*N/A*/-1,       /*N/A*/-1,     /*N/A*/-1,       /*N/A*/-1}, // EXTENDED_YEAR
   1.617 +    { -0x7F000000,  -0x7F000000,    0x7F000000,    0x7F000000  }, // JULIAN_DAY
   1.618 +    {           0,            0, 24*kOneHour-1, 24*kOneHour-1  },  // MILLISECONDS_IN_DAY
   1.619 +    {           0,            0,             1,             1  },  // IS_LEAP_MONTH
   1.620 +};
   1.621 +
   1.622 +// Resource bundle tags read by this class
   1.623 +static const char gMonthNames[] = "monthNames";
   1.624 +
   1.625 +// Data flow in Calendar
   1.626 +// ---------------------
   1.627 +
   1.628 +// The current time is represented in two ways by Calendar: as UTC
   1.629 +// milliseconds from the epoch start (1 January 1970 0:00 UTC), and as local
   1.630 +// fields such as MONTH, HOUR, AM_PM, etc.  It is possible to compute the
   1.631 +// millis from the fields, and vice versa.  The data needed to do this
   1.632 +// conversion is encapsulated by a TimeZone object owned by the Calendar.
   1.633 +// The data provided by the TimeZone object may also be overridden if the
   1.634 +// user sets the ZONE_OFFSET and/or DST_OFFSET fields directly. The class
   1.635 +// keeps track of what information was most recently set by the caller, and
   1.636 +// uses that to compute any other information as needed.
   1.637 +
   1.638 +// If the user sets the fields using set(), the data flow is as follows.
   1.639 +// This is implemented by the Calendar subclass's computeTime() method.
   1.640 +// During this process, certain fields may be ignored.  The disambiguation
   1.641 +// algorithm for resolving which fields to pay attention to is described
   1.642 +// above.
   1.643 +
   1.644 +//   local fields (YEAR, MONTH, DATE, HOUR, MINUTE, etc.)
   1.645 +//           |
   1.646 +//           | Using Calendar-specific algorithm
   1.647 +//           V
   1.648 +//   local standard millis
   1.649 +//           |
   1.650 +//           | Using TimeZone or user-set ZONE_OFFSET / DST_OFFSET
   1.651 +//           V
   1.652 +//   UTC millis (in time data member)
   1.653 +
   1.654 +// If the user sets the UTC millis using setTime(), the data flow is as
   1.655 +// follows.  This is implemented by the Calendar subclass's computeFields()
   1.656 +// method.
   1.657 +
   1.658 +//   UTC millis (in time data member)
   1.659 +//           |
   1.660 +//           | Using TimeZone getOffset()
   1.661 +//           V
   1.662 +//   local standard millis
   1.663 +//           |
   1.664 +//           | Using Calendar-specific algorithm
   1.665 +//           V
   1.666 +//   local fields (YEAR, MONTH, DATE, HOUR, MINUTE, etc.)
   1.667 +
   1.668 +// In general, a round trip from fields, through local and UTC millis, and
   1.669 +// back out to fields is made when necessary.  This is implemented by the
   1.670 +// complete() method.  Resolving a partial set of fields into a UTC millis
   1.671 +// value allows all remaining fields to be generated from that value.  If
   1.672 +// the Calendar is lenient, the fields are also renormalized to standard
   1.673 +// ranges when they are regenerated.
   1.674 +
   1.675 +// -------------------------------------
   1.676 +
   1.677 +Calendar::Calendar(UErrorCode& success)
   1.678 +:   UObject(),
   1.679 +fIsTimeSet(FALSE),
   1.680 +fAreFieldsSet(FALSE),
   1.681 +fAreAllFieldsSet(FALSE),
   1.682 +fAreFieldsVirtuallySet(FALSE),
   1.683 +fNextStamp((int32_t)kMinimumUserStamp),
   1.684 +fTime(0),
   1.685 +fLenient(TRUE),
   1.686 +fZone(0),
   1.687 +fRepeatedWallTime(UCAL_WALLTIME_LAST),
   1.688 +fSkippedWallTime(UCAL_WALLTIME_LAST)
   1.689 +{
   1.690 +    clear();
   1.691 +    fZone = TimeZone::createDefault();
   1.692 +    if (fZone == NULL) {
   1.693 +        success = U_MEMORY_ALLOCATION_ERROR;
   1.694 +    }
   1.695 +    setWeekData(Locale::getDefault(), NULL, success);
   1.696 +}
   1.697 +
   1.698 +// -------------------------------------
   1.699 +
   1.700 +Calendar::Calendar(TimeZone* zone, const Locale& aLocale, UErrorCode& success)
   1.701 +:   UObject(),
   1.702 +fIsTimeSet(FALSE),
   1.703 +fAreFieldsSet(FALSE),
   1.704 +fAreAllFieldsSet(FALSE),
   1.705 +fAreFieldsVirtuallySet(FALSE),
   1.706 +fNextStamp((int32_t)kMinimumUserStamp),
   1.707 +fTime(0),
   1.708 +fLenient(TRUE),
   1.709 +fZone(0),
   1.710 +fRepeatedWallTime(UCAL_WALLTIME_LAST),
   1.711 +fSkippedWallTime(UCAL_WALLTIME_LAST)
   1.712 +{
   1.713 +    if(zone == 0) {
   1.714 +#if defined (U_DEBUG_CAL)
   1.715 +        fprintf(stderr, "%s:%d: ILLEGAL ARG because timezone cannot be 0\n",
   1.716 +            __FILE__, __LINE__);
   1.717 +#endif
   1.718 +        success = U_ILLEGAL_ARGUMENT_ERROR;
   1.719 +        return;
   1.720 +    }
   1.721 +
   1.722 +    clear();    
   1.723 +    fZone = zone;
   1.724 +
   1.725 +    setWeekData(aLocale, NULL, success);
   1.726 +}
   1.727 +
   1.728 +// -------------------------------------
   1.729 +
   1.730 +Calendar::Calendar(const TimeZone& zone, const Locale& aLocale, UErrorCode& success)
   1.731 +:   UObject(),
   1.732 +fIsTimeSet(FALSE),
   1.733 +fAreFieldsSet(FALSE),
   1.734 +fAreAllFieldsSet(FALSE),
   1.735 +fAreFieldsVirtuallySet(FALSE),
   1.736 +fNextStamp((int32_t)kMinimumUserStamp),
   1.737 +fTime(0),
   1.738 +fLenient(TRUE),
   1.739 +fZone(0),
   1.740 +fRepeatedWallTime(UCAL_WALLTIME_LAST),
   1.741 +fSkippedWallTime(UCAL_WALLTIME_LAST)
   1.742 +{
   1.743 +    clear();
   1.744 +    fZone = zone.clone();
   1.745 +    if (fZone == NULL) {
   1.746 +    	success = U_MEMORY_ALLOCATION_ERROR;
   1.747 +    }
   1.748 +    setWeekData(aLocale, NULL, success);
   1.749 +}
   1.750 +
   1.751 +// -------------------------------------
   1.752 +
   1.753 +Calendar::~Calendar()
   1.754 +{
   1.755 +    delete fZone;
   1.756 +}
   1.757 +
   1.758 +// -------------------------------------
   1.759 +
   1.760 +Calendar::Calendar(const Calendar &source)
   1.761 +:   UObject(source)
   1.762 +{
   1.763 +    fZone = 0;
   1.764 +    *this = source;
   1.765 +}
   1.766 +
   1.767 +// -------------------------------------
   1.768 +
   1.769 +Calendar &
   1.770 +Calendar::operator=(const Calendar &right)
   1.771 +{
   1.772 +    if (this != &right) {
   1.773 +        uprv_arrayCopy(right.fFields, fFields, UCAL_FIELD_COUNT);
   1.774 +        uprv_arrayCopy(right.fIsSet, fIsSet, UCAL_FIELD_COUNT);
   1.775 +        uprv_arrayCopy(right.fStamp, fStamp, UCAL_FIELD_COUNT);
   1.776 +        fTime                    = right.fTime;
   1.777 +        fIsTimeSet               = right.fIsTimeSet;
   1.778 +        fAreAllFieldsSet         = right.fAreAllFieldsSet;
   1.779 +        fAreFieldsSet            = right.fAreFieldsSet;
   1.780 +        fAreFieldsVirtuallySet   = right.fAreFieldsVirtuallySet;
   1.781 +        fLenient                 = right.fLenient;
   1.782 +        fRepeatedWallTime        = right.fRepeatedWallTime;
   1.783 +        fSkippedWallTime         = right.fSkippedWallTime;
   1.784 +        if (fZone != NULL) {
   1.785 +            delete fZone;
   1.786 +        }
   1.787 +        if (right.fZone != NULL) {
   1.788 +            fZone                = right.fZone->clone();
   1.789 +        }
   1.790 +        fFirstDayOfWeek          = right.fFirstDayOfWeek;
   1.791 +        fMinimalDaysInFirstWeek  = right.fMinimalDaysInFirstWeek;
   1.792 +        fWeekendOnset            = right.fWeekendOnset;
   1.793 +        fWeekendOnsetMillis      = right.fWeekendOnsetMillis;
   1.794 +        fWeekendCease            = right.fWeekendCease;
   1.795 +        fWeekendCeaseMillis      = right.fWeekendCeaseMillis;
   1.796 +        fNextStamp               = right.fNextStamp;
   1.797 +        uprv_strcpy(validLocale, right.validLocale);
   1.798 +        uprv_strcpy(actualLocale, right.actualLocale);
   1.799 +    }
   1.800 +
   1.801 +    return *this;
   1.802 +}
   1.803 +
   1.804 +// -------------------------------------
   1.805 +
   1.806 +Calendar* U_EXPORT2
   1.807 +Calendar::createInstance(UErrorCode& success)
   1.808 +{
   1.809 +    return createInstance(TimeZone::createDefault(), Locale::getDefault(), success);
   1.810 +}
   1.811 +
   1.812 +// -------------------------------------
   1.813 +
   1.814 +Calendar* U_EXPORT2
   1.815 +Calendar::createInstance(const TimeZone& zone, UErrorCode& success)
   1.816 +{
   1.817 +    return createInstance(zone, Locale::getDefault(), success);
   1.818 +}
   1.819 +
   1.820 +// -------------------------------------
   1.821 +
   1.822 +Calendar* U_EXPORT2
   1.823 +Calendar::createInstance(const Locale& aLocale, UErrorCode& success)
   1.824 +{
   1.825 +    return createInstance(TimeZone::createDefault(), aLocale, success);
   1.826 +}
   1.827 +
   1.828 +// ------------------------------------- Adopting 
   1.829 +
   1.830 +// Note: this is the bottleneck that actually calls the service routines.
   1.831 +
   1.832 +Calendar* U_EXPORT2
   1.833 +Calendar::createInstance(TimeZone* zone, const Locale& aLocale, UErrorCode& success)
   1.834 +{
   1.835 +    if (U_FAILURE(success)) {
   1.836 +        return NULL;
   1.837 +    }
   1.838 +
   1.839 +    Locale actualLoc;
   1.840 +    UObject* u = NULL;
   1.841 +
   1.842 +#if !UCONFIG_NO_SERVICE
   1.843 +    if (isCalendarServiceUsed()) {
   1.844 +        u = getCalendarService(success)->get(aLocale, LocaleKey::KIND_ANY, &actualLoc, success);
   1.845 +    }
   1.846 +    else
   1.847 +#endif
   1.848 +    {
   1.849 +        u = createStandardCalendar(getCalendarTypeForLocale(aLocale.getName()), aLocale, success);
   1.850 +    }
   1.851 +    Calendar* c = NULL;
   1.852 +
   1.853 +    if(U_FAILURE(success) || !u) {
   1.854 +        delete zone;
   1.855 +        if(U_SUCCESS(success)) { // Propagate some kind of err
   1.856 +            success = U_INTERNAL_PROGRAM_ERROR;
   1.857 +        }
   1.858 +        return NULL;
   1.859 +    }
   1.860 +
   1.861 +#if !UCONFIG_NO_SERVICE
   1.862 +    const UnicodeString* str = dynamic_cast<const UnicodeString*>(u);
   1.863 +    if(str != NULL) {
   1.864 +        // It's a unicode string telling us what type of calendar to load ("gregorian", etc)
   1.865 +        // Create a Locale over this string
   1.866 +        Locale l("");
   1.867 +        LocaleUtility::initLocaleFromName(*str, l);
   1.868 +
   1.869 +#ifdef U_DEBUG_CALSVC
   1.870 +        fprintf(stderr, "Calendar::createInstance(%s), looking up [%s]\n", aLocale.getName(), l.getName());
   1.871 +#endif
   1.872 +
   1.873 +        Locale actualLoc2;
   1.874 +        delete u;
   1.875 +        u = NULL;
   1.876 +
   1.877 +        // Don't overwrite actualLoc, since the actual loc from this call
   1.878 +        // may be something like "@calendar=gregorian" -- TODO investigate
   1.879 +        // further...
   1.880 +        c = (Calendar*)getCalendarService(success)->get(l, LocaleKey::KIND_ANY, &actualLoc2, success);
   1.881 +
   1.882 +        if(U_FAILURE(success) || !c) {
   1.883 +            delete zone;
   1.884 +            if(U_SUCCESS(success)) { 
   1.885 +                success = U_INTERNAL_PROGRAM_ERROR; // Propagate some err
   1.886 +            }
   1.887 +            return NULL;
   1.888 +        }
   1.889 +
   1.890 +        str = dynamic_cast<const UnicodeString*>(c);
   1.891 +        if(str != NULL) {
   1.892 +            // recursed! Second lookup returned a UnicodeString. 
   1.893 +            // Perhaps DefaultCalendar{} was set to another locale.
   1.894 +#ifdef U_DEBUG_CALSVC
   1.895 +            char tmp[200];
   1.896 +            // Extract a char* out of it..
   1.897 +            int32_t len = str->length();
   1.898 +            int32_t actLen = sizeof(tmp)-1;
   1.899 +            if(len > actLen) {
   1.900 +                len = actLen;
   1.901 +            }
   1.902 +            str->extract(0,len,tmp);
   1.903 +            tmp[len]=0;
   1.904 +
   1.905 +            fprintf(stderr, "err - recursed, 2nd lookup was unistring %s\n", tmp);
   1.906 +#endif
   1.907 +            success = U_MISSING_RESOURCE_ERROR;  // requested a calendar type which could NOT be found.
   1.908 +            delete c;
   1.909 +            delete zone;
   1.910 +            return NULL;
   1.911 +        }
   1.912 +#ifdef U_DEBUG_CALSVC
   1.913 +        fprintf(stderr, "%p: setting week count data to locale %s, actual locale %s\n", c, (const char*)aLocale.getName(), (const char *)actualLoc.getName());
   1.914 +#endif
   1.915 +        c->setWeekData(aLocale, c->getType(), success);  // set the correct locale (this was an indirected calendar)
   1.916 +
   1.917 +        char keyword[ULOC_FULLNAME_CAPACITY];
   1.918 +        UErrorCode tmpStatus = U_ZERO_ERROR;
   1.919 +        l.getKeywordValue("calendar", keyword, ULOC_FULLNAME_CAPACITY, tmpStatus);
   1.920 +        if (U_SUCCESS(tmpStatus) && uprv_strcmp(keyword, "iso8601") == 0) {
   1.921 +            c->setFirstDayOfWeek(UCAL_MONDAY);
   1.922 +            c->setMinimalDaysInFirstWeek(4);
   1.923 +        }
   1.924 +    }
   1.925 +    else
   1.926 +#endif /* UCONFIG_NO_SERVICE */
   1.927 +    {
   1.928 +        // a calendar was returned - we assume the factory did the right thing.
   1.929 +        c = (Calendar*)u;
   1.930 +    }
   1.931 +
   1.932 +    // Now, reset calendar to default state:
   1.933 +    c->adoptTimeZone(zone); //  Set the correct time zone
   1.934 +    c->setTimeInMillis(getNow(), success); // let the new calendar have the current time.
   1.935 +
   1.936 +    return c;
   1.937 +}
   1.938 +
   1.939 +// -------------------------------------
   1.940 +
   1.941 +Calendar* U_EXPORT2
   1.942 +Calendar::createInstance(const TimeZone& zone, const Locale& aLocale, UErrorCode& success)
   1.943 +{
   1.944 +    Calendar* c = createInstance(aLocale, success);
   1.945 +    if(U_SUCCESS(success) && c) {
   1.946 +        c->setTimeZone(zone);
   1.947 +    }
   1.948 +    return c; 
   1.949 +}
   1.950 +
   1.951 +// -------------------------------------
   1.952 +
   1.953 +UBool
   1.954 +Calendar::operator==(const Calendar& that) const
   1.955 +{
   1.956 +    UErrorCode status = U_ZERO_ERROR;
   1.957 +    return isEquivalentTo(that) &&
   1.958 +        getTimeInMillis(status) == that.getTimeInMillis(status) &&
   1.959 +        U_SUCCESS(status);
   1.960 +}
   1.961 +
   1.962 +UBool 
   1.963 +Calendar::isEquivalentTo(const Calendar& other) const
   1.964 +{
   1.965 +    return typeid(*this) == typeid(other) &&
   1.966 +        fLenient                == other.fLenient &&
   1.967 +        fRepeatedWallTime       == other.fRepeatedWallTime &&
   1.968 +        fSkippedWallTime        == other.fSkippedWallTime &&
   1.969 +        fFirstDayOfWeek         == other.fFirstDayOfWeek &&
   1.970 +        fMinimalDaysInFirstWeek == other.fMinimalDaysInFirstWeek &&
   1.971 +        fWeekendOnset           == other.fWeekendOnset &&
   1.972 +        fWeekendOnsetMillis     == other.fWeekendOnsetMillis &&
   1.973 +        fWeekendCease           == other.fWeekendCease &&
   1.974 +        fWeekendCeaseMillis     == other.fWeekendCeaseMillis &&
   1.975 +        *fZone                  == *other.fZone;
   1.976 +}
   1.977 +
   1.978 +// -------------------------------------
   1.979 +
   1.980 +UBool
   1.981 +Calendar::equals(const Calendar& when, UErrorCode& status) const
   1.982 +{
   1.983 +    return (this == &when ||
   1.984 +        getTime(status) == when.getTime(status));
   1.985 +}
   1.986 +
   1.987 +// -------------------------------------
   1.988 +
   1.989 +UBool
   1.990 +Calendar::before(const Calendar& when, UErrorCode& status) const
   1.991 +{
   1.992 +    return (this != &when &&
   1.993 +        getTimeInMillis(status) < when.getTimeInMillis(status));
   1.994 +}
   1.995 +
   1.996 +// -------------------------------------
   1.997 +
   1.998 +UBool
   1.999 +Calendar::after(const Calendar& when, UErrorCode& status) const
  1.1000 +{
  1.1001 +    return (this != &when &&
  1.1002 +        getTimeInMillis(status) > when.getTimeInMillis(status));
  1.1003 +}
  1.1004 +
  1.1005 +// -------------------------------------
  1.1006 +
  1.1007 +
  1.1008 +const Locale* U_EXPORT2
  1.1009 +Calendar::getAvailableLocales(int32_t& count)
  1.1010 +{
  1.1011 +    return Locale::getAvailableLocales(count);
  1.1012 +}
  1.1013 +
  1.1014 +// -------------------------------------
  1.1015 +
  1.1016 +StringEnumeration* U_EXPORT2
  1.1017 +Calendar::getKeywordValuesForLocale(const char* key,
  1.1018 +                    const Locale& locale, UBool commonlyUsed, UErrorCode& status)
  1.1019 +{
  1.1020 +    // This is a wrapper over ucal_getKeywordValuesForLocale
  1.1021 +    UEnumeration *uenum = ucal_getKeywordValuesForLocale(key, locale.getName(),
  1.1022 +                                                        commonlyUsed, &status);
  1.1023 +    if (U_FAILURE(status)) {
  1.1024 +        uenum_close(uenum);
  1.1025 +        return NULL;
  1.1026 +    }
  1.1027 +    return new UStringEnumeration(uenum);
  1.1028 +}
  1.1029 +
  1.1030 +// -------------------------------------
  1.1031 +
  1.1032 +UDate U_EXPORT2
  1.1033 +Calendar::getNow()
  1.1034 +{
  1.1035 +    return uprv_getUTCtime(); // return as milliseconds
  1.1036 +}
  1.1037 +
  1.1038 +// -------------------------------------
  1.1039 +
  1.1040 +/**
  1.1041 +* Gets this Calendar's current time as a long.
  1.1042 +* @return the current time as UTC milliseconds from the epoch.
  1.1043 +*/
  1.1044 +double 
  1.1045 +Calendar::getTimeInMillis(UErrorCode& status) const
  1.1046 +{
  1.1047 +    if(U_FAILURE(status)) 
  1.1048 +        return 0.0;
  1.1049 +
  1.1050 +    if ( ! fIsTimeSet) 
  1.1051 +        ((Calendar*)this)->updateTime(status);
  1.1052 +
  1.1053 +    /* Test for buffer overflows */
  1.1054 +    if(U_FAILURE(status)) {
  1.1055 +        return 0.0;
  1.1056 +    }
  1.1057 +    return fTime;
  1.1058 +}
  1.1059 +
  1.1060 +// -------------------------------------
  1.1061 +
  1.1062 +/**
  1.1063 +* Sets this Calendar's current time from the given long value.
  1.1064 +* A status of U_ILLEGAL_ARGUMENT_ERROR is set when millis is
  1.1065 +* outside the range permitted by a Calendar object when not in lenient mode.
  1.1066 +* when in lenient mode the out of range values are pinned to their respective min/max.
  1.1067 +* @param date the new time in UTC milliseconds from the epoch.
  1.1068 +*/
  1.1069 +void 
  1.1070 +Calendar::setTimeInMillis( double millis, UErrorCode& status ) {
  1.1071 +    if(U_FAILURE(status)) 
  1.1072 +        return;
  1.1073 +
  1.1074 +    if (millis > MAX_MILLIS) {
  1.1075 +        if(isLenient()) {
  1.1076 +            millis = MAX_MILLIS;
  1.1077 +        } else {
  1.1078 +		    status = U_ILLEGAL_ARGUMENT_ERROR;
  1.1079 +		    return;
  1.1080 +        }
  1.1081 +    } else if (millis < MIN_MILLIS) {
  1.1082 +        if(isLenient()) {
  1.1083 +            millis = MIN_MILLIS;
  1.1084 +        } else {
  1.1085 +    		status = U_ILLEGAL_ARGUMENT_ERROR;
  1.1086 +	    	return;
  1.1087 +        }
  1.1088 +    }
  1.1089 +
  1.1090 +    fTime = millis;
  1.1091 +    fAreFieldsSet = fAreAllFieldsSet = FALSE;
  1.1092 +    fIsTimeSet = fAreFieldsVirtuallySet = TRUE;
  1.1093 +
  1.1094 +    for (int32_t i=0; i<UCAL_FIELD_COUNT; ++i) {
  1.1095 +        fFields[i]     = 0;
  1.1096 +        fStamp[i]     = kUnset;
  1.1097 +        fIsSet[i]     = FALSE;
  1.1098 +    }
  1.1099 +    
  1.1100 +
  1.1101 +}
  1.1102 +
  1.1103 +// -------------------------------------
  1.1104 +
  1.1105 +int32_t
  1.1106 +Calendar::get(UCalendarDateFields field, UErrorCode& status) const
  1.1107 +{
  1.1108 +    // field values are only computed when actually requested; for more on when computation
  1.1109 +    // of various things happens, see the "data flow in Calendar" description at the top
  1.1110 +    // of this file
  1.1111 +    if (U_SUCCESS(status)) ((Calendar*)this)->complete(status); // Cast away const
  1.1112 +    return U_SUCCESS(status) ? fFields[field] : 0;
  1.1113 +}
  1.1114 +
  1.1115 +// -------------------------------------
  1.1116 +
  1.1117 +void
  1.1118 +Calendar::set(UCalendarDateFields field, int32_t value)
  1.1119 +{
  1.1120 +    if (fAreFieldsVirtuallySet) {
  1.1121 +        UErrorCode ec = U_ZERO_ERROR;
  1.1122 +        computeFields(ec);
  1.1123 +    }
  1.1124 +    fFields[field]     = value;
  1.1125 +    /* Ensure that the fNextStamp value doesn't go pass max value for int32_t */
  1.1126 +    if (fNextStamp == STAMP_MAX) {
  1.1127 +        recalculateStamp();
  1.1128 +    }
  1.1129 +    fStamp[field]     = fNextStamp++;
  1.1130 +    fIsSet[field]     = TRUE; // Remove later
  1.1131 +    fIsTimeSet = fAreFieldsSet = fAreFieldsVirtuallySet = FALSE;
  1.1132 +}
  1.1133 +
  1.1134 +// -------------------------------------
  1.1135 +
  1.1136 +void
  1.1137 +Calendar::set(int32_t year, int32_t month, int32_t date)
  1.1138 +{
  1.1139 +    set(UCAL_YEAR, year);
  1.1140 +    set(UCAL_MONTH, month);
  1.1141 +    set(UCAL_DATE, date);
  1.1142 +}
  1.1143 +
  1.1144 +// -------------------------------------
  1.1145 +
  1.1146 +void
  1.1147 +Calendar::set(int32_t year, int32_t month, int32_t date, int32_t hour, int32_t minute)
  1.1148 +{
  1.1149 +    set(UCAL_YEAR, year);
  1.1150 +    set(UCAL_MONTH, month);
  1.1151 +    set(UCAL_DATE, date);
  1.1152 +    set(UCAL_HOUR_OF_DAY, hour);
  1.1153 +    set(UCAL_MINUTE, minute);
  1.1154 +}
  1.1155 +
  1.1156 +// -------------------------------------
  1.1157 +
  1.1158 +void
  1.1159 +Calendar::set(int32_t year, int32_t month, int32_t date, int32_t hour, int32_t minute, int32_t second)
  1.1160 +{
  1.1161 +    set(UCAL_YEAR, year);
  1.1162 +    set(UCAL_MONTH, month);
  1.1163 +    set(UCAL_DATE, date);
  1.1164 +    set(UCAL_HOUR_OF_DAY, hour);
  1.1165 +    set(UCAL_MINUTE, minute);
  1.1166 +    set(UCAL_SECOND, second);
  1.1167 +}
  1.1168 +
  1.1169 +// -------------------------------------
  1.1170 +
  1.1171 +void
  1.1172 +Calendar::clear()
  1.1173 +{
  1.1174 +    for (int32_t i=0; i<UCAL_FIELD_COUNT; ++i) {
  1.1175 +        fFields[i]     = 0; // Must do this; other code depends on it
  1.1176 +        fStamp[i]     = kUnset;
  1.1177 +        fIsSet[i]     = FALSE; // Remove later
  1.1178 +    }
  1.1179 +    fIsTimeSet = fAreFieldsSet = fAreAllFieldsSet = fAreFieldsVirtuallySet = FALSE;
  1.1180 +    // fTime is not 'cleared' - may be used if no fields are set.
  1.1181 +}
  1.1182 +
  1.1183 +// -------------------------------------
  1.1184 +
  1.1185 +void
  1.1186 +Calendar::clear(UCalendarDateFields field)
  1.1187 +{
  1.1188 +    if (fAreFieldsVirtuallySet) {
  1.1189 +        UErrorCode ec = U_ZERO_ERROR;
  1.1190 +        computeFields(ec);
  1.1191 +    }
  1.1192 +    fFields[field]         = 0;
  1.1193 +    fStamp[field]         = kUnset;
  1.1194 +    fIsSet[field]         = FALSE; // Remove later
  1.1195 +    fIsTimeSet = fAreFieldsSet = fAreAllFieldsSet = fAreFieldsVirtuallySet = FALSE;
  1.1196 +}
  1.1197 +
  1.1198 +// -------------------------------------
  1.1199 +
  1.1200 +UBool
  1.1201 +Calendar::isSet(UCalendarDateFields field) const
  1.1202 +{
  1.1203 +    return fAreFieldsVirtuallySet || (fStamp[field] != kUnset);
  1.1204 +}
  1.1205 +
  1.1206 +
  1.1207 +int32_t Calendar::newestStamp(UCalendarDateFields first, UCalendarDateFields last, int32_t bestStampSoFar) const
  1.1208 +{
  1.1209 +    int32_t bestStamp = bestStampSoFar;
  1.1210 +    for (int32_t i=(int32_t)first; i<=(int32_t)last; ++i) {
  1.1211 +        if (fStamp[i] > bestStamp) {
  1.1212 +            bestStamp = fStamp[i];
  1.1213 +        }
  1.1214 +    }
  1.1215 +    return bestStamp;
  1.1216 +}
  1.1217 +
  1.1218 +
  1.1219 +// -------------------------------------
  1.1220 +
  1.1221 +void
  1.1222 +Calendar::complete(UErrorCode& status)
  1.1223 +{
  1.1224 +    if (!fIsTimeSet) {
  1.1225 +        updateTime(status);
  1.1226 +        /* Test for buffer overflows */
  1.1227 +        if(U_FAILURE(status)) {
  1.1228 +            return;
  1.1229 +        }
  1.1230 +    }
  1.1231 +    if (!fAreFieldsSet) {
  1.1232 +        computeFields(status); // fills in unset fields
  1.1233 +        /* Test for buffer overflows */
  1.1234 +        if(U_FAILURE(status)) {
  1.1235 +            return;
  1.1236 +        }
  1.1237 +        fAreFieldsSet         = TRUE;
  1.1238 +        fAreAllFieldsSet     = TRUE;
  1.1239 +    }
  1.1240 +}
  1.1241 +
  1.1242 +//-------------------------------------------------------------------------
  1.1243 +// Protected utility methods for use by subclasses.  These are very handy
  1.1244 +// for implementing add, roll, and computeFields.
  1.1245 +//-------------------------------------------------------------------------
  1.1246 +
  1.1247 +/**
  1.1248 +* Adjust the specified field so that it is within
  1.1249 +* the allowable range for the date to which this calendar is set.
  1.1250 +* For example, in a Gregorian calendar pinning the {@link #DAY_OF_MONTH DAY_OF_MONTH}
  1.1251 +* field for a calendar set to April 31 would cause it to be set
  1.1252 +* to April 30.
  1.1253 +* <p>
  1.1254 +* <b>Subclassing:</b>
  1.1255 +* <br>
  1.1256 +* This utility method is intended for use by subclasses that need to implement
  1.1257 +* their own overrides of {@link #roll roll} and {@link #add add}.
  1.1258 +* <p>
  1.1259 +* <b>Note:</b>
  1.1260 +* <code>pinField</code> is implemented in terms of
  1.1261 +* {@link #getActualMinimum getActualMinimum}
  1.1262 +* and {@link #getActualMaximum getActualMaximum}.  If either of those methods uses
  1.1263 +* a slow, iterative algorithm for a particular field, it would be
  1.1264 +* unwise to attempt to call <code>pinField</code> for that field.  If you
  1.1265 +* really do need to do so, you should override this method to do
  1.1266 +* something more efficient for that field.
  1.1267 +* <p>
  1.1268 +* @param field The calendar field whose value should be pinned.
  1.1269 +*
  1.1270 +* @see #getActualMinimum
  1.1271 +* @see #getActualMaximum
  1.1272 +* @stable ICU 2.0
  1.1273 +*/
  1.1274 +void Calendar::pinField(UCalendarDateFields field, UErrorCode& status) {
  1.1275 +    int32_t max = getActualMaximum(field, status);
  1.1276 +    int32_t min = getActualMinimum(field, status);
  1.1277 +
  1.1278 +    if (fFields[field] > max) {
  1.1279 +        set(field, max);
  1.1280 +    } else if (fFields[field] < min) {
  1.1281 +        set(field, min);
  1.1282 +    }
  1.1283 +}
  1.1284 +
  1.1285 +
  1.1286 +void Calendar::computeFields(UErrorCode &ec)
  1.1287 +{
  1.1288 +  if (U_FAILURE(ec)) {
  1.1289 +        return;
  1.1290 +    }
  1.1291 +    // Compute local wall millis
  1.1292 +    double localMillis = internalGetTime();
  1.1293 +    int32_t rawOffset, dstOffset;
  1.1294 +    getTimeZone().getOffset(localMillis, FALSE, rawOffset, dstOffset, ec);
  1.1295 +    localMillis += (rawOffset + dstOffset); 
  1.1296 +
  1.1297 +    // Mark fields as set.  Do this before calling handleComputeFields().
  1.1298 +    uint32_t mask =   //fInternalSetMask;
  1.1299 +        (1 << UCAL_ERA) |
  1.1300 +        (1 << UCAL_YEAR) |
  1.1301 +        (1 << UCAL_MONTH) |
  1.1302 +        (1 << UCAL_DAY_OF_MONTH) | // = UCAL_DATE
  1.1303 +        (1 << UCAL_DAY_OF_YEAR) |
  1.1304 +        (1 << UCAL_EXTENDED_YEAR);  
  1.1305 +
  1.1306 +    for (int32_t i=0; i<UCAL_FIELD_COUNT; ++i) {
  1.1307 +        if ((mask & 1) == 0) {
  1.1308 +            fStamp[i] = kInternallySet;
  1.1309 +            fIsSet[i] = TRUE; // Remove later
  1.1310 +        } else {
  1.1311 +            fStamp[i] = kUnset;
  1.1312 +            fIsSet[i] = FALSE; // Remove later
  1.1313 +        }
  1.1314 +        mask >>= 1;
  1.1315 +    }
  1.1316 +
  1.1317 +    // We used to check for and correct extreme millis values (near
  1.1318 +    // Long.MIN_VALUE or Long.MAX_VALUE) here.  Such values would cause
  1.1319 +    // overflows from positive to negative (or vice versa) and had to
  1.1320 +    // be manually tweaked.  We no longer need to do this because we
  1.1321 +    // have limited the range of supported dates to those that have a
  1.1322 +    // Julian day that fits into an int.  This allows us to implement a
  1.1323 +    // JULIAN_DAY field and also removes some inelegant code. - Liu
  1.1324 +    // 11/6/00
  1.1325 +
  1.1326 +    int32_t days =  (int32_t)ClockMath::floorDivide(localMillis, (double)kOneDay);
  1.1327 +
  1.1328 +    internalSet(UCAL_JULIAN_DAY,days + kEpochStartAsJulianDay);
  1.1329 +
  1.1330 +#if defined (U_DEBUG_CAL)
  1.1331 +    //fprintf(stderr, "%s:%d- Hmm! Jules @ %d, as per %.0lf millis\n",
  1.1332 +    //__FILE__, __LINE__, fFields[UCAL_JULIAN_DAY], localMillis);
  1.1333 +#endif  
  1.1334 +
  1.1335 +    computeGregorianAndDOWFields(fFields[UCAL_JULIAN_DAY], ec);
  1.1336 +
  1.1337 +    // Call framework method to have subclass compute its fields.
  1.1338 +    // These must include, at a minimum, MONTH, DAY_OF_MONTH,
  1.1339 +    // EXTENDED_YEAR, YEAR, DAY_OF_YEAR.  This method will call internalSet(),
  1.1340 +    // which will update stamp[].
  1.1341 +    handleComputeFields(fFields[UCAL_JULIAN_DAY], ec);
  1.1342 +
  1.1343 +    // Compute week-related fields, based on the subclass-computed
  1.1344 +    // fields computed by handleComputeFields().
  1.1345 +    computeWeekFields(ec);
  1.1346 +
  1.1347 +    // Compute time-related fields.  These are indepent of the date and
  1.1348 +    // of the subclass algorithm.  They depend only on the local zone
  1.1349 +    // wall milliseconds in day.
  1.1350 +    int32_t millisInDay =  (int32_t) (localMillis - (days * kOneDay));
  1.1351 +    fFields[UCAL_MILLISECONDS_IN_DAY] = millisInDay;
  1.1352 +    fFields[UCAL_MILLISECOND] = millisInDay % 1000;
  1.1353 +    millisInDay /= 1000;
  1.1354 +    fFields[UCAL_SECOND] = millisInDay % 60;
  1.1355 +    millisInDay /= 60;
  1.1356 +    fFields[UCAL_MINUTE] = millisInDay % 60;
  1.1357 +    millisInDay /= 60;
  1.1358 +    fFields[UCAL_HOUR_OF_DAY] = millisInDay;
  1.1359 +    fFields[UCAL_AM_PM] = millisInDay / 12; // Assume AM == 0
  1.1360 +    fFields[UCAL_HOUR] = millisInDay % 12;
  1.1361 +    fFields[UCAL_ZONE_OFFSET] = rawOffset;
  1.1362 +    fFields[UCAL_DST_OFFSET] = dstOffset;
  1.1363 +}
  1.1364 +
  1.1365 +uint8_t Calendar::julianDayToDayOfWeek(double julian)
  1.1366 +{
  1.1367 +    // If julian is negative, then julian%7 will be negative, so we adjust
  1.1368 +    // accordingly.  We add 1 because Julian day 0 is Monday.
  1.1369 +    int8_t dayOfWeek = (int8_t) uprv_fmod(julian + 1, 7);
  1.1370 +
  1.1371 +    uint8_t result = (uint8_t)(dayOfWeek + ((dayOfWeek < 0) ? (7+UCAL_SUNDAY ) : UCAL_SUNDAY));
  1.1372 +    return result;
  1.1373 +}
  1.1374 +
  1.1375 +/**
  1.1376 +* Compute the Gregorian calendar year, month, and day of month from
  1.1377 +* the given Julian day.  These values are not stored in fields, but in
  1.1378 +* member variables gregorianXxx.  Also compute the DAY_OF_WEEK and
  1.1379 +* DOW_LOCAL fields.
  1.1380 +*/
  1.1381 +void Calendar::computeGregorianAndDOWFields(int32_t julianDay, UErrorCode &ec)
  1.1382 +{
  1.1383 +    computeGregorianFields(julianDay, ec);
  1.1384 +
  1.1385 +    // Compute day of week: JD 0 = Monday
  1.1386 +    int32_t dow = julianDayToDayOfWeek(julianDay);
  1.1387 +    internalSet(UCAL_DAY_OF_WEEK,dow);
  1.1388 +
  1.1389 +    // Calculate 1-based localized day of week
  1.1390 +    int32_t dowLocal = dow - getFirstDayOfWeek() + 1;
  1.1391 +    if (dowLocal < 1) {
  1.1392 +        dowLocal += 7;
  1.1393 +    }
  1.1394 +    internalSet(UCAL_DOW_LOCAL,dowLocal);
  1.1395 +    fFields[UCAL_DOW_LOCAL] = dowLocal;
  1.1396 +}
  1.1397 +
  1.1398 +/**
  1.1399 +* Compute the Gregorian calendar year, month, and day of month from the
  1.1400 +* Julian day.  These values are not stored in fields, but in member
  1.1401 +* variables gregorianXxx.  They are used for time zone computations and by
  1.1402 +* subclasses that are Gregorian derivatives.  Subclasses may call this
  1.1403 +* method to perform a Gregorian calendar millis->fields computation.
  1.1404 +*/
  1.1405 +void Calendar::computeGregorianFields(int32_t julianDay, UErrorCode & /* ec */) {
  1.1406 +    int32_t gregorianDayOfWeekUnused;
  1.1407 +    Grego::dayToFields(julianDay - kEpochStartAsJulianDay, fGregorianYear, fGregorianMonth, fGregorianDayOfMonth, gregorianDayOfWeekUnused, fGregorianDayOfYear);
  1.1408 +}
  1.1409 +
  1.1410 +/**
  1.1411 +* Compute the fields WEEK_OF_YEAR, YEAR_WOY, WEEK_OF_MONTH,
  1.1412 +* DAY_OF_WEEK_IN_MONTH, and DOW_LOCAL from EXTENDED_YEAR, YEAR,
  1.1413 +* DAY_OF_WEEK, and DAY_OF_YEAR.  The latter fields are computed by the
  1.1414 +* subclass based on the calendar system.
  1.1415 +*
  1.1416 +* <p>The YEAR_WOY field is computed simplistically.  It is equal to YEAR
  1.1417 +* most of the time, but at the year boundary it may be adjusted to YEAR-1
  1.1418 +* or YEAR+1 to reflect the overlap of a week into an adjacent year.  In
  1.1419 +* this case, a simple increment or decrement is performed on YEAR, even
  1.1420 +* though this may yield an invalid YEAR value.  For instance, if the YEAR
  1.1421 +* is part of a calendar system with an N-year cycle field CYCLE, then
  1.1422 +* incrementing the YEAR may involve incrementing CYCLE and setting YEAR
  1.1423 +* back to 0 or 1.  This is not handled by this code, and in fact cannot be
  1.1424 +* simply handled without having subclasses define an entire parallel set of
  1.1425 +* fields for fields larger than or equal to a year.  This additional
  1.1426 +* complexity is not warranted, since the intention of the YEAR_WOY field is
  1.1427 +* to support ISO 8601 notation, so it will typically be used with a
  1.1428 +* proleptic Gregorian calendar, which has no field larger than a year.
  1.1429 +*/
  1.1430 +void Calendar::computeWeekFields(UErrorCode &ec) {
  1.1431 +    if(U_FAILURE(ec)) { 
  1.1432 +        return;
  1.1433 +    }
  1.1434 +    int32_t eyear = fFields[UCAL_EXTENDED_YEAR];
  1.1435 +    int32_t dayOfWeek = fFields[UCAL_DAY_OF_WEEK];
  1.1436 +    int32_t dayOfYear = fFields[UCAL_DAY_OF_YEAR];
  1.1437 +
  1.1438 +    // WEEK_OF_YEAR start
  1.1439 +    // Compute the week of the year.  For the Gregorian calendar, valid week
  1.1440 +    // numbers run from 1 to 52 or 53, depending on the year, the first day
  1.1441 +    // of the week, and the minimal days in the first week.  For other
  1.1442 +    // calendars, the valid range may be different -- it depends on the year
  1.1443 +    // length.  Days at the start of the year may fall into the last week of
  1.1444 +    // the previous year; days at the end of the year may fall into the
  1.1445 +    // first week of the next year.  ASSUME that the year length is less than
  1.1446 +    // 7000 days.
  1.1447 +    int32_t yearOfWeekOfYear = eyear;
  1.1448 +    int32_t relDow = (dayOfWeek + 7 - getFirstDayOfWeek()) % 7; // 0..6
  1.1449 +    int32_t relDowJan1 = (dayOfWeek - dayOfYear + 7001 - getFirstDayOfWeek()) % 7; // 0..6
  1.1450 +    int32_t woy = (dayOfYear - 1 + relDowJan1) / 7; // 0..53
  1.1451 +    if ((7 - relDowJan1) >= getMinimalDaysInFirstWeek()) {
  1.1452 +        ++woy;
  1.1453 +    }
  1.1454 +
  1.1455 +    // Adjust for weeks at the year end that overlap into the previous or
  1.1456 +    // next calendar year.
  1.1457 +    if (woy == 0) {
  1.1458 +        // We are the last week of the previous year.
  1.1459 +        // Check to see if we are in the last week; if so, we need
  1.1460 +        // to handle the case in which we are the first week of the
  1.1461 +        // next year.
  1.1462 +
  1.1463 +        int32_t prevDoy = dayOfYear + handleGetYearLength(eyear - 1);
  1.1464 +        woy = weekNumber(prevDoy, dayOfWeek);
  1.1465 +        yearOfWeekOfYear--;
  1.1466 +    } else {
  1.1467 +        int32_t lastDoy = handleGetYearLength(eyear);
  1.1468 +        // Fast check: For it to be week 1 of the next year, the DOY
  1.1469 +        // must be on or after L-5, where L is yearLength(), then it
  1.1470 +        // cannot possibly be week 1 of the next year:
  1.1471 +        //          L-5                  L
  1.1472 +        // doy: 359 360 361 362 363 364 365 001
  1.1473 +        // dow:      1   2   3   4   5   6   7
  1.1474 +        if (dayOfYear >= (lastDoy - 5)) {
  1.1475 +            int32_t lastRelDow = (relDow + lastDoy - dayOfYear) % 7;
  1.1476 +            if (lastRelDow < 0) {
  1.1477 +                lastRelDow += 7;
  1.1478 +            }
  1.1479 +            if (((6 - lastRelDow) >= getMinimalDaysInFirstWeek()) &&
  1.1480 +                ((dayOfYear + 7 - relDow) > lastDoy)) {
  1.1481 +                    woy = 1;
  1.1482 +                    yearOfWeekOfYear++;
  1.1483 +                }
  1.1484 +        }
  1.1485 +    }
  1.1486 +    fFields[UCAL_WEEK_OF_YEAR] = woy;
  1.1487 +    fFields[UCAL_YEAR_WOY] = yearOfWeekOfYear;
  1.1488 +    // WEEK_OF_YEAR end
  1.1489 +
  1.1490 +    int32_t dayOfMonth = fFields[UCAL_DAY_OF_MONTH];
  1.1491 +    fFields[UCAL_WEEK_OF_MONTH] = weekNumber(dayOfMonth, dayOfWeek);
  1.1492 +    fFields[UCAL_DAY_OF_WEEK_IN_MONTH] = (dayOfMonth-1) / 7 + 1;
  1.1493 +#if defined (U_DEBUG_CAL)
  1.1494 +    if(fFields[UCAL_DAY_OF_WEEK_IN_MONTH]==0) fprintf(stderr, "%s:%d: DOWIM %d on %g\n", 
  1.1495 +        __FILE__, __LINE__,fFields[UCAL_DAY_OF_WEEK_IN_MONTH], fTime);
  1.1496 +#endif
  1.1497 +}
  1.1498 +
  1.1499 +
  1.1500 +int32_t Calendar::weekNumber(int32_t desiredDay, int32_t dayOfPeriod, int32_t dayOfWeek)
  1.1501 +{
  1.1502 +    // Determine the day of the week of the first day of the period
  1.1503 +    // in question (either a year or a month).  Zero represents the
  1.1504 +    // first day of the week on this calendar.
  1.1505 +    int32_t periodStartDayOfWeek = (dayOfWeek - getFirstDayOfWeek() - dayOfPeriod + 1) % 7;
  1.1506 +    if (periodStartDayOfWeek < 0) periodStartDayOfWeek += 7;
  1.1507 +
  1.1508 +    // Compute the week number.  Initially, ignore the first week, which
  1.1509 +    // may be fractional (or may not be).  We add periodStartDayOfWeek in
  1.1510 +    // order to fill out the first week, if it is fractional.
  1.1511 +    int32_t weekNo = (desiredDay + periodStartDayOfWeek - 1)/7;
  1.1512 +
  1.1513 +    // If the first week is long enough, then count it.  If
  1.1514 +    // the minimal days in the first week is one, or if the period start
  1.1515 +    // is zero, we always increment weekNo.
  1.1516 +    if ((7 - periodStartDayOfWeek) >= getMinimalDaysInFirstWeek()) ++weekNo;
  1.1517 +
  1.1518 +    return weekNo;
  1.1519 +}
  1.1520 +
  1.1521 +void Calendar::handleComputeFields(int32_t /* julianDay */, UErrorCode &/* status */)
  1.1522 +{
  1.1523 +    internalSet(UCAL_MONTH, getGregorianMonth());
  1.1524 +    internalSet(UCAL_DAY_OF_MONTH, getGregorianDayOfMonth());
  1.1525 +    internalSet(UCAL_DAY_OF_YEAR, getGregorianDayOfYear());
  1.1526 +    int32_t eyear = getGregorianYear();
  1.1527 +    internalSet(UCAL_EXTENDED_YEAR, eyear);
  1.1528 +    int32_t era = GregorianCalendar::AD;
  1.1529 +    if (eyear < 1) {
  1.1530 +        era = GregorianCalendar::BC;
  1.1531 +        eyear = 1 - eyear;
  1.1532 +    }
  1.1533 +    internalSet(UCAL_ERA, era);
  1.1534 +    internalSet(UCAL_YEAR, eyear);
  1.1535 +}
  1.1536 +// -------------------------------------
  1.1537 +
  1.1538 +
  1.1539 +void Calendar::roll(EDateFields field, int32_t amount, UErrorCode& status) 
  1.1540 +{
  1.1541 +    roll((UCalendarDateFields)field, amount, status);
  1.1542 +}
  1.1543 +
  1.1544 +void Calendar::roll(UCalendarDateFields field, int32_t amount, UErrorCode& status)
  1.1545 +{
  1.1546 +    if (amount == 0) {
  1.1547 +        return; // Nothing to do
  1.1548 +    }
  1.1549 +
  1.1550 +    complete(status);
  1.1551 +
  1.1552 +    if(U_FAILURE(status)) {
  1.1553 +        return;
  1.1554 +    }
  1.1555 +    switch (field) {
  1.1556 +    case UCAL_DAY_OF_MONTH:
  1.1557 +    case UCAL_AM_PM:
  1.1558 +    case UCAL_MINUTE:
  1.1559 +    case UCAL_SECOND:
  1.1560 +    case UCAL_MILLISECOND:
  1.1561 +    case UCAL_MILLISECONDS_IN_DAY:
  1.1562 +    case UCAL_ERA:
  1.1563 +        // These are the standard roll instructions.  These work for all
  1.1564 +        // simple cases, that is, cases in which the limits are fixed, such
  1.1565 +        // as the hour, the day of the month, and the era.
  1.1566 +        {
  1.1567 +            int32_t min = getActualMinimum(field,status);
  1.1568 +            int32_t max = getActualMaximum(field,status);
  1.1569 +            int32_t gap = max - min + 1;
  1.1570 +
  1.1571 +            int32_t value = internalGet(field) + amount;
  1.1572 +            value = (value - min) % gap;
  1.1573 +            if (value < 0) {
  1.1574 +                value += gap;
  1.1575 +            }
  1.1576 +            value += min;
  1.1577 +
  1.1578 +            set(field, value);
  1.1579 +            return;
  1.1580 +        }
  1.1581 +
  1.1582 +    case UCAL_HOUR:
  1.1583 +    case UCAL_HOUR_OF_DAY:
  1.1584 +        // Rolling the hour is difficult on the ONSET and CEASE days of
  1.1585 +        // daylight savings.  For example, if the change occurs at
  1.1586 +        // 2 AM, we have the following progression:
  1.1587 +        // ONSET: 12 Std -> 1 Std -> 3 Dst -> 4 Dst
  1.1588 +        // CEASE: 12 Dst -> 1 Dst -> 1 Std -> 2 Std
  1.1589 +        // To get around this problem we don't use fields; we manipulate
  1.1590 +        // the time in millis directly.
  1.1591 +        {
  1.1592 +            // Assume min == 0 in calculations below
  1.1593 +            double start = getTimeInMillis(status);
  1.1594 +            int32_t oldHour = internalGet(field);
  1.1595 +            int32_t max = getMaximum(field);
  1.1596 +            int32_t newHour = (oldHour + amount) % (max + 1);
  1.1597 +            if (newHour < 0) {
  1.1598 +                newHour += max + 1;
  1.1599 +            }
  1.1600 +            setTimeInMillis(start + kOneHour * (newHour - oldHour),status);
  1.1601 +            return;
  1.1602 +        }
  1.1603 +
  1.1604 +    case UCAL_MONTH:
  1.1605 +        // Rolling the month involves both pinning the final value
  1.1606 +        // and adjusting the DAY_OF_MONTH if necessary.  We only adjust the
  1.1607 +        // DAY_OF_MONTH if, after updating the MONTH field, it is illegal.
  1.1608 +        // E.g., <jan31>.roll(MONTH, 1) -> <feb28> or <feb29>.
  1.1609 +        {
  1.1610 +            int32_t max = getActualMaximum(UCAL_MONTH, status);
  1.1611 +            int32_t mon = (internalGet(UCAL_MONTH) + amount) % (max+1);
  1.1612 +
  1.1613 +            if (mon < 0) {
  1.1614 +                mon += (max + 1);
  1.1615 +            }
  1.1616 +            set(UCAL_MONTH, mon);
  1.1617 +
  1.1618 +            // Keep the day of month in range.  We don't want to spill over
  1.1619 +            // into the next month; e.g., we don't want jan31 + 1 mo -> feb31 ->
  1.1620 +            // mar3.
  1.1621 +            pinField(UCAL_DAY_OF_MONTH,status);
  1.1622 +            return;
  1.1623 +        }
  1.1624 +
  1.1625 +    case UCAL_YEAR:
  1.1626 +    case UCAL_YEAR_WOY:
  1.1627 +        {
  1.1628 +            // * If era==0 and years go backwards in time, change sign of amount.
  1.1629 +            // * Until we have new API per #9393, we temporarily hardcode knowledge of
  1.1630 +            //   which calendars have era 0 years that go backwards.
  1.1631 +            UBool era0WithYearsThatGoBackwards = FALSE;
  1.1632 +            int32_t era = get(UCAL_ERA, status);
  1.1633 +            if (era == 0) {
  1.1634 +                const char * calType = getType();
  1.1635 +                if ( uprv_strcmp(calType,"gregorian")==0 || uprv_strcmp(calType,"roc")==0 || uprv_strcmp(calType,"coptic")==0 ) {
  1.1636 +                    amount = -amount;
  1.1637 +                    era0WithYearsThatGoBackwards = TRUE;
  1.1638 +                }
  1.1639 +            }
  1.1640 +            int32_t newYear = internalGet(field) + amount;
  1.1641 +            if (era > 0 || newYear >= 1) {
  1.1642 +                int32_t maxYear = getActualMaximum(field, status);
  1.1643 +                if (maxYear < 32768) {
  1.1644 +                    // this era has real bounds, roll should wrap years
  1.1645 +                    if (newYear < 1) {
  1.1646 +                        newYear = maxYear - ((-newYear) % maxYear);
  1.1647 +                    } else if (newYear > maxYear) {
  1.1648 +                        newYear = ((newYear - 1) % maxYear) + 1;
  1.1649 +                    }
  1.1650 +                // else era is unbounded, just pin low year instead of wrapping
  1.1651 +                } else if (newYear < 1) {
  1.1652 +                    newYear = 1;
  1.1653 +                }
  1.1654 +            // else we are in era 0 with newYear < 1;
  1.1655 +            // calendars with years that go backwards must pin the year value at 0,
  1.1656 +            // other calendars can have years < 0 in era 0
  1.1657 +            } else if (era0WithYearsThatGoBackwards) {
  1.1658 +                newYear = 1;
  1.1659 +            }
  1.1660 +            set(field, newYear);
  1.1661 +            pinField(UCAL_MONTH,status);
  1.1662 +            pinField(UCAL_DAY_OF_MONTH,status);
  1.1663 +            return;
  1.1664 +        }
  1.1665 +
  1.1666 +    case UCAL_EXTENDED_YEAR:
  1.1667 +        // Rolling the year can involve pinning the DAY_OF_MONTH.
  1.1668 +        set(field, internalGet(field) + amount);
  1.1669 +        pinField(UCAL_MONTH,status);
  1.1670 +        pinField(UCAL_DAY_OF_MONTH,status);
  1.1671 +        return;
  1.1672 +
  1.1673 +    case UCAL_WEEK_OF_MONTH:
  1.1674 +        {
  1.1675 +            // This is tricky, because during the roll we may have to shift
  1.1676 +            // to a different day of the week.  For example:
  1.1677 +
  1.1678 +            //    s  m  t  w  r  f  s
  1.1679 +            //          1  2  3  4  5
  1.1680 +            //    6  7  8  9 10 11 12
  1.1681 +
  1.1682 +            // When rolling from the 6th or 7th back one week, we go to the
  1.1683 +            // 1st (assuming that the first partial week counts).  The same
  1.1684 +            // thing happens at the end of the month.
  1.1685 +
  1.1686 +            // The other tricky thing is that we have to figure out whether
  1.1687 +            // the first partial week actually counts or not, based on the
  1.1688 +            // minimal first days in the week.  And we have to use the
  1.1689 +            // correct first day of the week to delineate the week
  1.1690 +            // boundaries.
  1.1691 +
  1.1692 +            // Here's our algorithm.  First, we find the real boundaries of
  1.1693 +            // the month.  Then we discard the first partial week if it
  1.1694 +            // doesn't count in this locale.  Then we fill in the ends with
  1.1695 +            // phantom days, so that the first partial week and the last
  1.1696 +            // partial week are full weeks.  We then have a nice square
  1.1697 +            // block of weeks.  We do the usual rolling within this block,
  1.1698 +            // as is done elsewhere in this method.  If we wind up on one of
  1.1699 +            // the phantom days that we added, we recognize this and pin to
  1.1700 +            // the first or the last day of the month.  Easy, eh?
  1.1701 +
  1.1702 +            // Normalize the DAY_OF_WEEK so that 0 is the first day of the week
  1.1703 +            // in this locale.  We have dow in 0..6.
  1.1704 +            int32_t dow = internalGet(UCAL_DAY_OF_WEEK) - getFirstDayOfWeek();
  1.1705 +            if (dow < 0) dow += 7;
  1.1706 +
  1.1707 +            // Find the day of the week (normalized for locale) for the first
  1.1708 +            // of the month.
  1.1709 +            int32_t fdm = (dow - internalGet(UCAL_DAY_OF_MONTH) + 1) % 7;
  1.1710 +            if (fdm < 0) fdm += 7;
  1.1711 +
  1.1712 +            // Get the first day of the first full week of the month,
  1.1713 +            // including phantom days, if any.  Figure out if the first week
  1.1714 +            // counts or not; if it counts, then fill in phantom days.  If
  1.1715 +            // not, advance to the first real full week (skip the partial week).
  1.1716 +            int32_t start;
  1.1717 +            if ((7 - fdm) < getMinimalDaysInFirstWeek())
  1.1718 +                start = 8 - fdm; // Skip the first partial week
  1.1719 +            else
  1.1720 +                start = 1 - fdm; // This may be zero or negative
  1.1721 +
  1.1722 +            // Get the day of the week (normalized for locale) for the last
  1.1723 +            // day of the month.
  1.1724 +            int32_t monthLen = getActualMaximum(UCAL_DAY_OF_MONTH, status);
  1.1725 +            int32_t ldm = (monthLen - internalGet(UCAL_DAY_OF_MONTH) + dow) % 7;
  1.1726 +            // We know monthLen >= DAY_OF_MONTH so we skip the += 7 step here.
  1.1727 +
  1.1728 +            // Get the limit day for the blocked-off rectangular month; that
  1.1729 +            // is, the day which is one past the last day of the month,
  1.1730 +            // after the month has already been filled in with phantom days
  1.1731 +            // to fill out the last week.  This day has a normalized DOW of 0.
  1.1732 +            int32_t limit = monthLen + 7 - ldm;
  1.1733 +
  1.1734 +            // Now roll between start and (limit - 1).
  1.1735 +            int32_t gap = limit - start;
  1.1736 +            int32_t day_of_month = (internalGet(UCAL_DAY_OF_MONTH) + amount*7 -
  1.1737 +                start) % gap;
  1.1738 +            if (day_of_month < 0) day_of_month += gap;
  1.1739 +            day_of_month += start;
  1.1740 +
  1.1741 +            // Finally, pin to the real start and end of the month.
  1.1742 +            if (day_of_month < 1) day_of_month = 1;
  1.1743 +            if (day_of_month > monthLen) day_of_month = monthLen;
  1.1744 +
  1.1745 +            // Set the DAY_OF_MONTH.  We rely on the fact that this field
  1.1746 +            // takes precedence over everything else (since all other fields
  1.1747 +            // are also set at this point).  If this fact changes (if the
  1.1748 +            // disambiguation algorithm changes) then we will have to unset
  1.1749 +            // the appropriate fields here so that DAY_OF_MONTH is attended
  1.1750 +            // to.
  1.1751 +            set(UCAL_DAY_OF_MONTH, day_of_month);
  1.1752 +            return;
  1.1753 +        }
  1.1754 +    case UCAL_WEEK_OF_YEAR:
  1.1755 +        {
  1.1756 +            // This follows the outline of WEEK_OF_MONTH, except it applies
  1.1757 +            // to the whole year.  Please see the comment for WEEK_OF_MONTH
  1.1758 +            // for general notes.
  1.1759 +
  1.1760 +            // Normalize the DAY_OF_WEEK so that 0 is the first day of the week
  1.1761 +            // in this locale.  We have dow in 0..6.
  1.1762 +            int32_t dow = internalGet(UCAL_DAY_OF_WEEK) - getFirstDayOfWeek();
  1.1763 +            if (dow < 0) dow += 7;
  1.1764 +
  1.1765 +            // Find the day of the week (normalized for locale) for the first
  1.1766 +            // of the year.
  1.1767 +            int32_t fdy = (dow - internalGet(UCAL_DAY_OF_YEAR) + 1) % 7;
  1.1768 +            if (fdy < 0) fdy += 7;
  1.1769 +
  1.1770 +            // Get the first day of the first full week of the year,
  1.1771 +            // including phantom days, if any.  Figure out if the first week
  1.1772 +            // counts or not; if it counts, then fill in phantom days.  If
  1.1773 +            // not, advance to the first real full week (skip the partial week).
  1.1774 +            int32_t start;
  1.1775 +            if ((7 - fdy) < getMinimalDaysInFirstWeek())
  1.1776 +                start = 8 - fdy; // Skip the first partial week
  1.1777 +            else
  1.1778 +                start = 1 - fdy; // This may be zero or negative
  1.1779 +
  1.1780 +            // Get the day of the week (normalized for locale) for the last
  1.1781 +            // day of the year.
  1.1782 +            int32_t yearLen = getActualMaximum(UCAL_DAY_OF_YEAR,status);
  1.1783 +            int32_t ldy = (yearLen - internalGet(UCAL_DAY_OF_YEAR) + dow) % 7;
  1.1784 +            // We know yearLen >= DAY_OF_YEAR so we skip the += 7 step here.
  1.1785 +
  1.1786 +            // Get the limit day for the blocked-off rectangular year; that
  1.1787 +            // is, the day which is one past the last day of the year,
  1.1788 +            // after the year has already been filled in with phantom days
  1.1789 +            // to fill out the last week.  This day has a normalized DOW of 0.
  1.1790 +            int32_t limit = yearLen + 7 - ldy;
  1.1791 +
  1.1792 +            // Now roll between start and (limit - 1).
  1.1793 +            int32_t gap = limit - start;
  1.1794 +            int32_t day_of_year = (internalGet(UCAL_DAY_OF_YEAR) + amount*7 -
  1.1795 +                start) % gap;
  1.1796 +            if (day_of_year < 0) day_of_year += gap;
  1.1797 +            day_of_year += start;
  1.1798 +
  1.1799 +            // Finally, pin to the real start and end of the month.
  1.1800 +            if (day_of_year < 1) day_of_year = 1;
  1.1801 +            if (day_of_year > yearLen) day_of_year = yearLen;
  1.1802 +
  1.1803 +            // Make sure that the year and day of year are attended to by
  1.1804 +            // clearing other fields which would normally take precedence.
  1.1805 +            // If the disambiguation algorithm is changed, this section will
  1.1806 +            // have to be updated as well.
  1.1807 +            set(UCAL_DAY_OF_YEAR, day_of_year);
  1.1808 +            clear(UCAL_MONTH);
  1.1809 +            return;
  1.1810 +        }
  1.1811 +    case UCAL_DAY_OF_YEAR:
  1.1812 +        {
  1.1813 +            // Roll the day of year using millis.  Compute the millis for
  1.1814 +            // the start of the year, and get the length of the year.
  1.1815 +            double delta = amount * kOneDay; // Scale up from days to millis
  1.1816 +            double min2 = internalGet(UCAL_DAY_OF_YEAR)-1;
  1.1817 +            min2 *= kOneDay;
  1.1818 +            min2 = internalGetTime() - min2;
  1.1819 +
  1.1820 +            //      double min2 = internalGetTime() - (internalGet(UCAL_DAY_OF_YEAR) - 1.0) * kOneDay;
  1.1821 +            double newtime;
  1.1822 +
  1.1823 +            double yearLength = getActualMaximum(UCAL_DAY_OF_YEAR,status);
  1.1824 +            double oneYear = yearLength;
  1.1825 +            oneYear *= kOneDay;
  1.1826 +            newtime = uprv_fmod((internalGetTime() + delta - min2), oneYear);
  1.1827 +            if (newtime < 0) newtime += oneYear;
  1.1828 +            setTimeInMillis(newtime + min2, status);
  1.1829 +            return;
  1.1830 +        }
  1.1831 +    case UCAL_DAY_OF_WEEK:
  1.1832 +    case UCAL_DOW_LOCAL:
  1.1833 +        {
  1.1834 +            // Roll the day of week using millis.  Compute the millis for
  1.1835 +            // the start of the week, using the first day of week setting.
  1.1836 +            // Restrict the millis to [start, start+7days).
  1.1837 +            double delta = amount * kOneDay; // Scale up from days to millis
  1.1838 +            // Compute the number of days before the current day in this
  1.1839 +            // week.  This will be a value 0..6.
  1.1840 +            int32_t leadDays = internalGet(field);
  1.1841 +            leadDays -= (field == UCAL_DAY_OF_WEEK) ? getFirstDayOfWeek() : 1;
  1.1842 +            if (leadDays < 0) leadDays += 7;
  1.1843 +            double min2 = internalGetTime() - leadDays * kOneDay;
  1.1844 +            double newtime = uprv_fmod((internalGetTime() + delta - min2), kOneWeek);
  1.1845 +            if (newtime < 0) newtime += kOneWeek;
  1.1846 +            setTimeInMillis(newtime + min2, status);
  1.1847 +            return;
  1.1848 +        }
  1.1849 +    case UCAL_DAY_OF_WEEK_IN_MONTH:
  1.1850 +        {
  1.1851 +            // Roll the day of week in the month using millis.  Determine
  1.1852 +            // the first day of the week in the month, and then the last,
  1.1853 +            // and then roll within that range.
  1.1854 +            double delta = amount * kOneWeek; // Scale up from weeks to millis
  1.1855 +            // Find the number of same days of the week before this one
  1.1856 +            // in this month.
  1.1857 +            int32_t preWeeks = (internalGet(UCAL_DAY_OF_MONTH) - 1) / 7;
  1.1858 +            // Find the number of same days of the week after this one
  1.1859 +            // in this month.
  1.1860 +            int32_t postWeeks = (getActualMaximum(UCAL_DAY_OF_MONTH,status) -
  1.1861 +                internalGet(UCAL_DAY_OF_MONTH)) / 7;
  1.1862 +            // From these compute the min and gap millis for rolling.
  1.1863 +            double min2 = internalGetTime() - preWeeks * kOneWeek;
  1.1864 +            double gap2 = kOneWeek * (preWeeks + postWeeks + 1); // Must add 1!
  1.1865 +            // Roll within this range
  1.1866 +            double newtime = uprv_fmod((internalGetTime() + delta - min2), gap2);
  1.1867 +            if (newtime < 0) newtime += gap2;
  1.1868 +            setTimeInMillis(newtime + min2, status);
  1.1869 +            return;
  1.1870 +        }
  1.1871 +    case UCAL_JULIAN_DAY:
  1.1872 +        set(field, internalGet(field) + amount);
  1.1873 +        return;
  1.1874 +    default:
  1.1875 +        // Other fields cannot be rolled by this method
  1.1876 +#if defined (U_DEBUG_CAL)
  1.1877 +        fprintf(stderr, "%s:%d: ILLEGAL ARG because of roll on non-rollable field %s\n", 
  1.1878 +            __FILE__, __LINE__,fldName(field));
  1.1879 +#endif
  1.1880 +        status = U_ILLEGAL_ARGUMENT_ERROR;
  1.1881 +    }
  1.1882 +}
  1.1883 +
  1.1884 +void Calendar::add(EDateFields field, int32_t amount, UErrorCode& status)
  1.1885 +{
  1.1886 +    Calendar::add((UCalendarDateFields)field, amount, status);
  1.1887 +}
  1.1888 +
  1.1889 +// -------------------------------------
  1.1890 +void Calendar::add(UCalendarDateFields field, int32_t amount, UErrorCode& status)
  1.1891 +{
  1.1892 +    if (amount == 0) {
  1.1893 +        return;   // Do nothing!
  1.1894 +    }
  1.1895 +
  1.1896 +    // We handle most fields in the same way.  The algorithm is to add
  1.1897 +    // a computed amount of millis to the current millis.  The only
  1.1898 +    // wrinkle is with DST (and/or a change to the zone's UTC offset, which
  1.1899 +    // we'll include with DST) -- for some fields, like the DAY_OF_MONTH,
  1.1900 +    // we don't want the HOUR to shift due to changes in DST.  If the
  1.1901 +    // result of the add operation is to move from DST to Standard, or
  1.1902 +    // vice versa, we need to adjust by an hour forward or back,
  1.1903 +    // respectively.  For such fields we set keepHourInvariant to TRUE.
  1.1904 +
  1.1905 +    // We only adjust the DST for fields larger than an hour.  For
  1.1906 +    // fields smaller than an hour, we cannot adjust for DST without
  1.1907 +    // causing problems.  for instance, if you add one hour to April 5,
  1.1908 +    // 1998, 1:00 AM, in PST, the time becomes "2:00 AM PDT" (an
  1.1909 +    // illegal value), but then the adjustment sees the change and
  1.1910 +    // compensates by subtracting an hour.  As a result the time
  1.1911 +    // doesn't advance at all.
  1.1912 +
  1.1913 +    // For some fields larger than a day, such as a UCAL_MONTH, we pin the
  1.1914 +    // UCAL_DAY_OF_MONTH.  This allows <March 31>.add(UCAL_MONTH, 1) to be
  1.1915 +    // <April 30>, rather than <April 31> => <May 1>.
  1.1916 +
  1.1917 +    double delta = amount; // delta in ms
  1.1918 +    UBool keepHourInvariant = TRUE;
  1.1919 +
  1.1920 +    switch (field) {
  1.1921 +    case UCAL_ERA:
  1.1922 +        set(field, get(field, status) + amount);
  1.1923 +        pinField(UCAL_ERA, status);
  1.1924 +        return;
  1.1925 +
  1.1926 +    case UCAL_YEAR:
  1.1927 +    case UCAL_YEAR_WOY:
  1.1928 +      {
  1.1929 +        // * If era=0 and years go backwards in time, change sign of amount.
  1.1930 +        // * Until we have new API per #9393, we temporarily hardcode knowledge of
  1.1931 +        //   which calendars have era 0 years that go backwards.
  1.1932 +        // * Note that for UCAL_YEAR (but not UCAL_YEAR_WOY) we could instead handle
  1.1933 +        //   this by applying the amount to the UCAL_EXTENDED_YEAR field; but since
  1.1934 +        //   we would still need to handle UCAL_YEAR_WOY as below, might as well
  1.1935 +        //   also handle UCAL_YEAR the same way.
  1.1936 +        int32_t era = get(UCAL_ERA, status);
  1.1937 +        if (era == 0) {
  1.1938 +          const char * calType = getType();
  1.1939 +          if ( uprv_strcmp(calType,"gregorian")==0 || uprv_strcmp(calType,"roc")==0 || uprv_strcmp(calType,"coptic")==0 ) {
  1.1940 +            amount = -amount;
  1.1941 +          }
  1.1942 +        }
  1.1943 +      }
  1.1944 +      // Fall through into normal handling
  1.1945 +    case UCAL_EXTENDED_YEAR:
  1.1946 +    case UCAL_MONTH:
  1.1947 +      {
  1.1948 +        UBool oldLenient = isLenient();
  1.1949 +        setLenient(TRUE);
  1.1950 +        set(field, get(field, status) + amount);
  1.1951 +        pinField(UCAL_DAY_OF_MONTH, status);
  1.1952 +        if(oldLenient==FALSE) {
  1.1953 +          complete(status); /* force recalculate */
  1.1954 +          setLenient(oldLenient);
  1.1955 +        }
  1.1956 +      }
  1.1957 +      return;
  1.1958 +
  1.1959 +    case UCAL_WEEK_OF_YEAR:
  1.1960 +    case UCAL_WEEK_OF_MONTH:
  1.1961 +    case UCAL_DAY_OF_WEEK_IN_MONTH:
  1.1962 +        delta *= kOneWeek;
  1.1963 +        break;
  1.1964 +
  1.1965 +    case UCAL_AM_PM:
  1.1966 +        delta *= 12 * kOneHour;
  1.1967 +        break;
  1.1968 +
  1.1969 +    case UCAL_DAY_OF_MONTH:
  1.1970 +    case UCAL_DAY_OF_YEAR:
  1.1971 +    case UCAL_DAY_OF_WEEK:
  1.1972 +    case UCAL_DOW_LOCAL:
  1.1973 +    case UCAL_JULIAN_DAY:
  1.1974 +        delta *= kOneDay;
  1.1975 +        break;
  1.1976 +
  1.1977 +    case UCAL_HOUR_OF_DAY:
  1.1978 +    case UCAL_HOUR:
  1.1979 +        delta *= kOneHour;
  1.1980 +        keepHourInvariant = FALSE;
  1.1981 +        break;
  1.1982 +
  1.1983 +    case UCAL_MINUTE:
  1.1984 +        delta *= kOneMinute;
  1.1985 +        keepHourInvariant = FALSE;
  1.1986 +        break;
  1.1987 +
  1.1988 +    case UCAL_SECOND:
  1.1989 +        delta *= kOneSecond;
  1.1990 +        keepHourInvariant = FALSE;
  1.1991 +        break;
  1.1992 +
  1.1993 +    case UCAL_MILLISECOND:
  1.1994 +    case UCAL_MILLISECONDS_IN_DAY:
  1.1995 +        keepHourInvariant = FALSE;
  1.1996 +        break;
  1.1997 +
  1.1998 +    default:
  1.1999 +#if defined (U_DEBUG_CAL)
  1.2000 +        fprintf(stderr, "%s:%d: ILLEGAL ARG because field %s not addable",
  1.2001 +            __FILE__, __LINE__, fldName(field));
  1.2002 +#endif
  1.2003 +        status = U_ILLEGAL_ARGUMENT_ERROR;
  1.2004 +        return;
  1.2005 +        //  throw new IllegalArgumentException("Calendar.add(" + fieldName(field) +
  1.2006 +        //                                     ") not supported");
  1.2007 +    }
  1.2008 +
  1.2009 +    // In order to keep the hour invariant (for fields where this is
  1.2010 +    // appropriate), check the combined DST & ZONE offset before and
  1.2011 +    // after the add() operation. If it changes, then adjust the millis
  1.2012 +    // to compensate.
  1.2013 +    int32_t prevOffset = 0;
  1.2014 +    int32_t hour = 0;
  1.2015 +    if (keepHourInvariant) {
  1.2016 +        prevOffset = get(UCAL_DST_OFFSET, status) + get(UCAL_ZONE_OFFSET, status);
  1.2017 +        hour = internalGet(UCAL_HOUR_OF_DAY);
  1.2018 +    }
  1.2019 +
  1.2020 +    setTimeInMillis(getTimeInMillis(status) + delta, status);
  1.2021 +
  1.2022 +    if (keepHourInvariant) {
  1.2023 +        int32_t newOffset = get(UCAL_DST_OFFSET, status) + get(UCAL_ZONE_OFFSET, status);
  1.2024 +        if (newOffset != prevOffset) {
  1.2025 +            // We have done an hour-invariant adjustment but the
  1.2026 +            // combined offset has changed. We adjust millis to keep
  1.2027 +            // the hour constant. In cases such as midnight after
  1.2028 +            // a DST change which occurs at midnight, there is the
  1.2029 +            // danger of adjusting into a different day. To avoid
  1.2030 +            // this we make the adjustment only if it actually
  1.2031 +            // maintains the hour.
  1.2032 +
  1.2033 +            // When the difference of the previous UTC offset and
  1.2034 +            // the new UTC offset exceeds 1 full day, we do not want
  1.2035 +            // to roll over/back the date. For now, this only happens
  1.2036 +            // in Samoa (Pacific/Apia) on Dec 30, 2011. See ticket:9452.
  1.2037 +            int32_t adjAmount = prevOffset - newOffset;
  1.2038 +            adjAmount = adjAmount >= 0 ? adjAmount % (int32_t)kOneDay : -(-adjAmount % (int32_t)kOneDay);
  1.2039 +            if (adjAmount != 0) {
  1.2040 +                double t = internalGetTime();
  1.2041 +                setTimeInMillis(t + adjAmount, status);
  1.2042 +                if (get(UCAL_HOUR_OF_DAY, status) != hour) {
  1.2043 +                    setTimeInMillis(t, status);
  1.2044 +                }
  1.2045 +            }
  1.2046 +        }
  1.2047 +    } 
  1.2048 +}
  1.2049 +
  1.2050 +// -------------------------------------
  1.2051 +int32_t Calendar::fieldDifference(UDate when, EDateFields field, UErrorCode& status) {
  1.2052 +    return fieldDifference(when, (UCalendarDateFields) field, status);
  1.2053 +}
  1.2054 +
  1.2055 +int32_t Calendar::fieldDifference(UDate targetMs, UCalendarDateFields field, UErrorCode& ec) {
  1.2056 +    if (U_FAILURE(ec)) return 0;
  1.2057 +    int32_t min = 0;
  1.2058 +    double startMs = getTimeInMillis(ec);
  1.2059 +    // Always add from the start millis.  This accomodates
  1.2060 +    // operations like adding years from February 29, 2000 up to
  1.2061 +    // February 29, 2004.  If 1, 1, 1, 1 is added to the year
  1.2062 +    // field, the DOM gets pinned to 28 and stays there, giving an
  1.2063 +    // incorrect DOM difference of 1.  We have to add 1, reset, 2,
  1.2064 +    // reset, 3, reset, 4.
  1.2065 +    if (startMs < targetMs) {
  1.2066 +        int32_t max = 1;
  1.2067 +        // Find a value that is too large
  1.2068 +        while (U_SUCCESS(ec)) {
  1.2069 +            setTimeInMillis(startMs, ec);
  1.2070 +            add(field, max, ec);
  1.2071 +            double ms = getTimeInMillis(ec);
  1.2072 +            if (ms == targetMs) {
  1.2073 +                return max;
  1.2074 +            } else if (ms > targetMs) {
  1.2075 +                break;
  1.2076 +            } else if (max < INT32_MAX) {
  1.2077 +                min = max;
  1.2078 +                max <<= 1;
  1.2079 +                if (max < 0) {
  1.2080 +                    max = INT32_MAX;
  1.2081 +                }
  1.2082 +            } else {
  1.2083 +                // Field difference too large to fit into int32_t
  1.2084 +#if defined (U_DEBUG_CAL)
  1.2085 +                fprintf(stderr, "%s:%d: ILLEGAL ARG because field %s's max too large for int32_t\n",
  1.2086 +                    __FILE__, __LINE__, fldName(field));
  1.2087 +#endif
  1.2088 +                ec = U_ILLEGAL_ARGUMENT_ERROR;
  1.2089 +            }
  1.2090 +        }
  1.2091 +        // Do a binary search
  1.2092 +        while ((max - min) > 1 && U_SUCCESS(ec)) {
  1.2093 +            int32_t t = min + (max - min)/2; // make sure intermediate values don't exceed INT32_MAX
  1.2094 +            setTimeInMillis(startMs, ec);
  1.2095 +            add(field, t, ec);
  1.2096 +            double ms = getTimeInMillis(ec);
  1.2097 +            if (ms == targetMs) {
  1.2098 +                return t;
  1.2099 +            } else if (ms > targetMs) {
  1.2100 +                max = t;
  1.2101 +            } else {
  1.2102 +                min = t;
  1.2103 +            }
  1.2104 +        }
  1.2105 +    } else if (startMs > targetMs) {
  1.2106 +        int32_t max = -1;
  1.2107 +        // Find a value that is too small
  1.2108 +        while (U_SUCCESS(ec)) {
  1.2109 +            setTimeInMillis(startMs, ec);
  1.2110 +            add(field, max, ec);
  1.2111 +            double ms = getTimeInMillis(ec);
  1.2112 +            if (ms == targetMs) {
  1.2113 +                return max;
  1.2114 +            } else if (ms < targetMs) {
  1.2115 +                break;
  1.2116 +            } else {
  1.2117 +                min = max;
  1.2118 +                max <<= 1;
  1.2119 +                if (max == 0) {
  1.2120 +                    // Field difference too large to fit into int32_t
  1.2121 +#if defined (U_DEBUG_CAL)
  1.2122 +                    fprintf(stderr, "%s:%d: ILLEGAL ARG because field %s's max too large for int32_t\n",
  1.2123 +                        __FILE__, __LINE__, fldName(field));
  1.2124 +#endif
  1.2125 +                    ec = U_ILLEGAL_ARGUMENT_ERROR;
  1.2126 +                }
  1.2127 +            }
  1.2128 +        }
  1.2129 +        // Do a binary search
  1.2130 +        while ((min - max) > 1 && U_SUCCESS(ec)) {
  1.2131 +            int32_t t = min + (max - min)/2; // make sure intermediate values don't exceed INT32_MAX
  1.2132 +            setTimeInMillis(startMs, ec);
  1.2133 +            add(field, t, ec);
  1.2134 +            double ms = getTimeInMillis(ec);
  1.2135 +            if (ms == targetMs) {
  1.2136 +                return t;
  1.2137 +            } else if (ms < targetMs) {
  1.2138 +                max = t;
  1.2139 +            } else {
  1.2140 +                min = t;
  1.2141 +            }
  1.2142 +        }
  1.2143 +    }
  1.2144 +    // Set calendar to end point
  1.2145 +    setTimeInMillis(startMs, ec);
  1.2146 +    add(field, min, ec);
  1.2147 +
  1.2148 +    /* Test for buffer overflows */
  1.2149 +    if(U_FAILURE(ec)) {
  1.2150 +        return 0;
  1.2151 +    }
  1.2152 +    return min;
  1.2153 +}
  1.2154 +
  1.2155 +// -------------------------------------
  1.2156 +
  1.2157 +void
  1.2158 +Calendar::adoptTimeZone(TimeZone* zone)
  1.2159 +{
  1.2160 +    // Do nothing if passed-in zone is NULL
  1.2161 +    if (zone == NULL) return;
  1.2162 +
  1.2163 +    // fZone should always be non-null
  1.2164 +    if (fZone != NULL) delete fZone;
  1.2165 +    fZone = zone;
  1.2166 +
  1.2167 +    // if the zone changes, we need to recompute the time fields
  1.2168 +    fAreFieldsSet = FALSE;
  1.2169 +}
  1.2170 +
  1.2171 +// -------------------------------------
  1.2172 +void
  1.2173 +Calendar::setTimeZone(const TimeZone& zone)
  1.2174 +{
  1.2175 +    adoptTimeZone(zone.clone());
  1.2176 +}
  1.2177 +
  1.2178 +// -------------------------------------
  1.2179 +
  1.2180 +const TimeZone&
  1.2181 +Calendar::getTimeZone() const
  1.2182 +{
  1.2183 +    return *fZone;
  1.2184 +}
  1.2185 +
  1.2186 +// -------------------------------------
  1.2187 +
  1.2188 +TimeZone*
  1.2189 +Calendar::orphanTimeZone()
  1.2190 +{
  1.2191 +    TimeZone *z = fZone;
  1.2192 +    // we let go of the time zone; the new time zone is the system default time zone
  1.2193 +    fZone = TimeZone::createDefault();
  1.2194 +    return z;
  1.2195 +}
  1.2196 +
  1.2197 +// -------------------------------------
  1.2198 +
  1.2199 +void
  1.2200 +Calendar::setLenient(UBool lenient)
  1.2201 +{
  1.2202 +    fLenient = lenient;
  1.2203 +}
  1.2204 +
  1.2205 +// -------------------------------------
  1.2206 +
  1.2207 +UBool
  1.2208 +Calendar::isLenient() const
  1.2209 +{
  1.2210 +    return fLenient;
  1.2211 +}
  1.2212 +
  1.2213 +// -------------------------------------
  1.2214 +
  1.2215 +void
  1.2216 +Calendar::setRepeatedWallTimeOption(UCalendarWallTimeOption option)
  1.2217 +{
  1.2218 +    if (option == UCAL_WALLTIME_LAST || option == UCAL_WALLTIME_FIRST) {
  1.2219 +        fRepeatedWallTime = option;
  1.2220 +    }
  1.2221 +}
  1.2222 +
  1.2223 +// -------------------------------------
  1.2224 +
  1.2225 +UCalendarWallTimeOption
  1.2226 +Calendar::getRepeatedWallTimeOption(void) const
  1.2227 +{
  1.2228 +    return fRepeatedWallTime;
  1.2229 +}
  1.2230 +
  1.2231 +// -------------------------------------
  1.2232 +
  1.2233 +void
  1.2234 +Calendar::setSkippedWallTimeOption(UCalendarWallTimeOption option)
  1.2235 +{
  1.2236 +    fSkippedWallTime = option;
  1.2237 +}
  1.2238 +
  1.2239 +// -------------------------------------
  1.2240 +
  1.2241 +UCalendarWallTimeOption
  1.2242 +Calendar::getSkippedWallTimeOption(void) const
  1.2243 +{
  1.2244 +    return fSkippedWallTime;
  1.2245 +}
  1.2246 +
  1.2247 +// -------------------------------------
  1.2248 +
  1.2249 +void
  1.2250 +Calendar::setFirstDayOfWeek(UCalendarDaysOfWeek value)
  1.2251 +{
  1.2252 +    if (fFirstDayOfWeek != value &&
  1.2253 +        value >= UCAL_SUNDAY && value <= UCAL_SATURDAY) {
  1.2254 +            fFirstDayOfWeek = value;
  1.2255 +            fAreFieldsSet = FALSE;
  1.2256 +        }
  1.2257 +}
  1.2258 +
  1.2259 +// -------------------------------------
  1.2260 +
  1.2261 +Calendar::EDaysOfWeek
  1.2262 +Calendar::getFirstDayOfWeek() const
  1.2263 +{
  1.2264 +    return (Calendar::EDaysOfWeek)fFirstDayOfWeek;
  1.2265 +}
  1.2266 +
  1.2267 +UCalendarDaysOfWeek
  1.2268 +Calendar::getFirstDayOfWeek(UErrorCode & /*status*/) const
  1.2269 +{
  1.2270 +    return fFirstDayOfWeek;
  1.2271 +}
  1.2272 +// -------------------------------------
  1.2273 +
  1.2274 +void
  1.2275 +Calendar::setMinimalDaysInFirstWeek(uint8_t value)
  1.2276 +{
  1.2277 +    // Values less than 1 have the same effect as 1; values greater
  1.2278 +    // than 7 have the same effect as 7. However, we normalize values
  1.2279 +    // so operator== and so forth work.
  1.2280 +    if (value < 1) {
  1.2281 +        value = 1;
  1.2282 +    } else if (value > 7) {
  1.2283 +        value = 7;
  1.2284 +    }
  1.2285 +    if (fMinimalDaysInFirstWeek != value) {
  1.2286 +        fMinimalDaysInFirstWeek = value;
  1.2287 +        fAreFieldsSet = FALSE;
  1.2288 +    }
  1.2289 +}
  1.2290 +
  1.2291 +// -------------------------------------
  1.2292 +
  1.2293 +uint8_t
  1.2294 +Calendar::getMinimalDaysInFirstWeek() const
  1.2295 +{
  1.2296 +    return fMinimalDaysInFirstWeek;
  1.2297 +}
  1.2298 +
  1.2299 +// -------------------------------------
  1.2300 +// weekend functions, just dummy implementations for now (for API freeze)
  1.2301 +
  1.2302 +UCalendarWeekdayType
  1.2303 +Calendar::getDayOfWeekType(UCalendarDaysOfWeek dayOfWeek, UErrorCode &status) const
  1.2304 +{
  1.2305 +    if (U_FAILURE(status)) {
  1.2306 +        return UCAL_WEEKDAY;
  1.2307 +    }
  1.2308 +    if (dayOfWeek < UCAL_SUNDAY || dayOfWeek > UCAL_SATURDAY) {
  1.2309 +        status = U_ILLEGAL_ARGUMENT_ERROR;
  1.2310 +        return UCAL_WEEKDAY;
  1.2311 +    }
  1.2312 +	if (fWeekendOnset == fWeekendCease) {
  1.2313 +		if (dayOfWeek != fWeekendOnset)
  1.2314 +			return UCAL_WEEKDAY;
  1.2315 +		return (fWeekendOnsetMillis == 0) ? UCAL_WEEKEND : UCAL_WEEKEND_ONSET;
  1.2316 +	}
  1.2317 +    if (fWeekendOnset < fWeekendCease) {
  1.2318 +        if (dayOfWeek < fWeekendOnset || dayOfWeek > fWeekendCease) {
  1.2319 +            return UCAL_WEEKDAY;
  1.2320 +        }
  1.2321 +    } else {
  1.2322 +        if (dayOfWeek > fWeekendCease && dayOfWeek < fWeekendOnset) {
  1.2323 +            return UCAL_WEEKDAY;
  1.2324 +        }
  1.2325 +    }
  1.2326 +    if (dayOfWeek == fWeekendOnset) {
  1.2327 +        return (fWeekendOnsetMillis == 0) ? UCAL_WEEKEND : UCAL_WEEKEND_ONSET;
  1.2328 +    }
  1.2329 +    if (dayOfWeek == fWeekendCease) {
  1.2330 +        return (fWeekendCeaseMillis >= 86400000) ? UCAL_WEEKEND : UCAL_WEEKEND_CEASE;
  1.2331 +    }
  1.2332 +    return UCAL_WEEKEND;
  1.2333 +}
  1.2334 +
  1.2335 +int32_t
  1.2336 +Calendar::getWeekendTransition(UCalendarDaysOfWeek dayOfWeek, UErrorCode &status) const
  1.2337 +{
  1.2338 +    if (U_FAILURE(status)) {
  1.2339 +        return 0;
  1.2340 +    }
  1.2341 +    if (dayOfWeek == fWeekendOnset) {
  1.2342 +        return fWeekendOnsetMillis;
  1.2343 +    } else if (dayOfWeek == fWeekendCease) {
  1.2344 +        return fWeekendCeaseMillis;
  1.2345 +    }
  1.2346 +    status = U_ILLEGAL_ARGUMENT_ERROR;
  1.2347 +    return 0;
  1.2348 +}
  1.2349 +
  1.2350 +UBool
  1.2351 +Calendar::isWeekend(UDate date, UErrorCode &status) const
  1.2352 +{
  1.2353 +    if (U_FAILURE(status)) {
  1.2354 +        return FALSE;
  1.2355 +    }
  1.2356 +    // clone the calendar so we don't mess with the real one.
  1.2357 +    Calendar *work = (Calendar*)this->clone();
  1.2358 +    if (work == NULL) {
  1.2359 +        status = U_MEMORY_ALLOCATION_ERROR;
  1.2360 +        return FALSE;
  1.2361 +    }
  1.2362 +    UBool result = FALSE;
  1.2363 +    work->setTime(date, status);
  1.2364 +    if (U_SUCCESS(status)) {
  1.2365 +        result = work->isWeekend();
  1.2366 +    }
  1.2367 +    delete work;
  1.2368 +    return result;
  1.2369 +}
  1.2370 +
  1.2371 +UBool
  1.2372 +Calendar::isWeekend(void) const
  1.2373 +{
  1.2374 +    UErrorCode status = U_ZERO_ERROR;
  1.2375 +    UCalendarDaysOfWeek dayOfWeek = (UCalendarDaysOfWeek)get(UCAL_DAY_OF_WEEK, status);
  1.2376 +    UCalendarWeekdayType dayType = getDayOfWeekType(dayOfWeek, status);
  1.2377 +    if (U_SUCCESS(status)) {
  1.2378 +        switch (dayType) {
  1.2379 +            case UCAL_WEEKDAY:
  1.2380 +                return FALSE;
  1.2381 +            case UCAL_WEEKEND:
  1.2382 +                return TRUE;
  1.2383 +            case UCAL_WEEKEND_ONSET:
  1.2384 +            case UCAL_WEEKEND_CEASE:
  1.2385 +                // Use internalGet() because the above call to get() populated all fields.
  1.2386 +                {
  1.2387 +                    int32_t millisInDay = internalGet(UCAL_MILLISECONDS_IN_DAY);
  1.2388 +                    int32_t transitionMillis = getWeekendTransition(dayOfWeek, status);
  1.2389 +                    if (U_SUCCESS(status)) {
  1.2390 +                        return (dayType == UCAL_WEEKEND_ONSET)?
  1.2391 +                            (millisInDay >= transitionMillis):
  1.2392 +                            (millisInDay <  transitionMillis);
  1.2393 +                    }
  1.2394 +                    // else fall through, return FALSE
  1.2395 +                }
  1.2396 +            default:
  1.2397 +                break;
  1.2398 +        }
  1.2399 +    }
  1.2400 +    return FALSE;
  1.2401 +}
  1.2402 +
  1.2403 +// ------------------------------------- limits
  1.2404 +
  1.2405 +int32_t 
  1.2406 +Calendar::getMinimum(EDateFields field) const {
  1.2407 +    return getLimit((UCalendarDateFields) field,UCAL_LIMIT_MINIMUM);
  1.2408 +}
  1.2409 +
  1.2410 +int32_t
  1.2411 +Calendar::getMinimum(UCalendarDateFields field) const
  1.2412 +{
  1.2413 +    return getLimit(field,UCAL_LIMIT_MINIMUM);
  1.2414 +}
  1.2415 +
  1.2416 +// -------------------------------------
  1.2417 +int32_t
  1.2418 +Calendar::getMaximum(EDateFields field) const
  1.2419 +{
  1.2420 +    return getLimit((UCalendarDateFields) field,UCAL_LIMIT_MAXIMUM);
  1.2421 +}
  1.2422 +
  1.2423 +int32_t
  1.2424 +Calendar::getMaximum(UCalendarDateFields field) const
  1.2425 +{
  1.2426 +    return getLimit(field,UCAL_LIMIT_MAXIMUM);
  1.2427 +}
  1.2428 +
  1.2429 +// -------------------------------------
  1.2430 +int32_t
  1.2431 +Calendar::getGreatestMinimum(EDateFields field) const
  1.2432 +{
  1.2433 +    return getLimit((UCalendarDateFields)field,UCAL_LIMIT_GREATEST_MINIMUM);
  1.2434 +}
  1.2435 +
  1.2436 +int32_t
  1.2437 +Calendar::getGreatestMinimum(UCalendarDateFields field) const
  1.2438 +{
  1.2439 +    return getLimit(field,UCAL_LIMIT_GREATEST_MINIMUM);
  1.2440 +}
  1.2441 +
  1.2442 +// -------------------------------------
  1.2443 +int32_t
  1.2444 +Calendar::getLeastMaximum(EDateFields field) const
  1.2445 +{
  1.2446 +    return getLimit((UCalendarDateFields) field,UCAL_LIMIT_LEAST_MAXIMUM);
  1.2447 +}
  1.2448 +
  1.2449 +int32_t
  1.2450 +Calendar::getLeastMaximum(UCalendarDateFields field) const
  1.2451 +{
  1.2452 +    return getLimit( field,UCAL_LIMIT_LEAST_MAXIMUM);
  1.2453 +}
  1.2454 +
  1.2455 +// -------------------------------------
  1.2456 +int32_t 
  1.2457 +Calendar::getActualMinimum(EDateFields field, UErrorCode& status) const
  1.2458 +{
  1.2459 +    return getActualMinimum((UCalendarDateFields) field, status);
  1.2460 +}
  1.2461 +
  1.2462 +int32_t Calendar::getLimit(UCalendarDateFields field, ELimitType limitType) const {
  1.2463 +    switch (field) {
  1.2464 +    case UCAL_DAY_OF_WEEK:
  1.2465 +    case UCAL_AM_PM:
  1.2466 +    case UCAL_HOUR:
  1.2467 +    case UCAL_HOUR_OF_DAY:
  1.2468 +    case UCAL_MINUTE:
  1.2469 +    case UCAL_SECOND:
  1.2470 +    case UCAL_MILLISECOND:
  1.2471 +    case UCAL_ZONE_OFFSET:
  1.2472 +    case UCAL_DST_OFFSET:
  1.2473 +    case UCAL_DOW_LOCAL:
  1.2474 +    case UCAL_JULIAN_DAY:
  1.2475 +    case UCAL_MILLISECONDS_IN_DAY:
  1.2476 +    case UCAL_IS_LEAP_MONTH:
  1.2477 +        return kCalendarLimits[field][limitType];
  1.2478 +
  1.2479 +    case UCAL_WEEK_OF_MONTH:
  1.2480 +        {
  1.2481 +            int32_t limit;
  1.2482 +            if (limitType == UCAL_LIMIT_MINIMUM) {
  1.2483 +                limit = getMinimalDaysInFirstWeek() == 1 ? 1 : 0;
  1.2484 +            } else if (limitType == UCAL_LIMIT_GREATEST_MINIMUM) {
  1.2485 +                limit = 1;
  1.2486 +            } else {
  1.2487 +                int32_t minDaysInFirst = getMinimalDaysInFirstWeek();
  1.2488 +                int32_t daysInMonth = handleGetLimit(UCAL_DAY_OF_MONTH, limitType);
  1.2489 +                if (limitType == UCAL_LIMIT_LEAST_MAXIMUM) {
  1.2490 +                    limit = (daysInMonth + (7 - minDaysInFirst)) / 7;
  1.2491 +                } else { // limitType == UCAL_LIMIT_MAXIMUM
  1.2492 +                    limit = (daysInMonth + 6 + (7 - minDaysInFirst)) / 7;
  1.2493 +                }
  1.2494 +            }
  1.2495 +            return limit;
  1.2496 +        }
  1.2497 +    default:
  1.2498 +        return handleGetLimit(field, limitType);
  1.2499 +    }
  1.2500 +}
  1.2501 +
  1.2502 +
  1.2503 +int32_t
  1.2504 +Calendar::getActualMinimum(UCalendarDateFields field, UErrorCode& status) const
  1.2505 +{
  1.2506 +    int32_t fieldValue = getGreatestMinimum(field);
  1.2507 +    int32_t endValue = getMinimum(field);
  1.2508 +
  1.2509 +    // if we know that the minimum value is always the same, just return it
  1.2510 +    if (fieldValue == endValue) {
  1.2511 +        return fieldValue;
  1.2512 +    }
  1.2513 +
  1.2514 +    // clone the calendar so we don't mess with the real one, and set it to
  1.2515 +    // accept anything for the field values
  1.2516 +    Calendar *work = (Calendar*)this->clone();
  1.2517 +    if (work == NULL) {
  1.2518 +        status = U_MEMORY_ALLOCATION_ERROR;
  1.2519 +        return 0;
  1.2520 +    }
  1.2521 +    work->setLenient(TRUE);
  1.2522 +
  1.2523 +    // now try each value from getLeastMaximum() to getMaximum() one by one until
  1.2524 +    // we get a value that normalizes to another value.  The last value that
  1.2525 +    // normalizes to itself is the actual minimum for the current date
  1.2526 +    int32_t result = fieldValue;
  1.2527 +
  1.2528 +    do {
  1.2529 +        work->set(field, fieldValue);
  1.2530 +        if (work->get(field, status) != fieldValue) {
  1.2531 +            break;
  1.2532 +        } 
  1.2533 +        else {
  1.2534 +            result = fieldValue;
  1.2535 +            fieldValue--;
  1.2536 +        }
  1.2537 +    } while (fieldValue >= endValue);
  1.2538 +
  1.2539 +    delete work;
  1.2540 +
  1.2541 +    /* Test for buffer overflows */
  1.2542 +    if(U_FAILURE(status)) {
  1.2543 +        return 0;
  1.2544 +    }
  1.2545 +    return result;
  1.2546 +}
  1.2547 +
  1.2548 +// -------------------------------------
  1.2549 +
  1.2550 +
  1.2551 +
  1.2552 +/**
  1.2553 +* Ensure that each field is within its valid range by calling {@link
  1.2554 +* #validateField(int)} on each field that has been set.  This method
  1.2555 +* should only be called if this calendar is not lenient.
  1.2556 +* @see #isLenient
  1.2557 +* @see #validateField(int)
  1.2558 +*/
  1.2559 +void Calendar::validateFields(UErrorCode &status) {
  1.2560 +    for (int32_t field = 0; U_SUCCESS(status) && (field < UCAL_FIELD_COUNT); field++) {
  1.2561 +        if (fStamp[field] >= kMinimumUserStamp) {
  1.2562 +            validateField((UCalendarDateFields)field, status);
  1.2563 +        }
  1.2564 +    }
  1.2565 +}
  1.2566 +
  1.2567 +/**
  1.2568 +* Validate a single field of this calendar.  Subclasses should
  1.2569 +* override this method to validate any calendar-specific fields.
  1.2570 +* Generic fields can be handled by
  1.2571 +* <code>Calendar.validateField()</code>.
  1.2572 +* @see #validateField(int, int, int)
  1.2573 +*/
  1.2574 +void Calendar::validateField(UCalendarDateFields field, UErrorCode &status) {
  1.2575 +    int32_t y;
  1.2576 +    switch (field) {
  1.2577 +    case UCAL_DAY_OF_MONTH:
  1.2578 +        y = handleGetExtendedYear();
  1.2579 +        validateField(field, 1, handleGetMonthLength(y, internalGet(UCAL_MONTH)), status);
  1.2580 +        break;
  1.2581 +    case UCAL_DAY_OF_YEAR:
  1.2582 +        y = handleGetExtendedYear();
  1.2583 +        validateField(field, 1, handleGetYearLength(y), status);
  1.2584 +        break;
  1.2585 +    case UCAL_DAY_OF_WEEK_IN_MONTH:
  1.2586 +        if (internalGet(field) == 0) {
  1.2587 +#if defined (U_DEBUG_CAL)
  1.2588 +            fprintf(stderr, "%s:%d: ILLEGAL ARG because DOW in month cannot be 0\n", 
  1.2589 +                __FILE__, __LINE__);
  1.2590 +#endif
  1.2591 +            status = U_ILLEGAL_ARGUMENT_ERROR; // "DAY_OF_WEEK_IN_MONTH cannot be zero"
  1.2592 +            return;
  1.2593 +        }
  1.2594 +        validateField(field, getMinimum(field), getMaximum(field), status);
  1.2595 +        break;
  1.2596 +    default:
  1.2597 +        validateField(field, getMinimum(field), getMaximum(field), status);
  1.2598 +        break;
  1.2599 +    }
  1.2600 +}
  1.2601 +
  1.2602 +/**
  1.2603 +* Validate a single field of this calendar given its minimum and
  1.2604 +* maximum allowed value.  If the field is out of range, throw a
  1.2605 +* descriptive <code>IllegalArgumentException</code>.  Subclasses may
  1.2606 +* use this method in their implementation of {@link
  1.2607 +* #validateField(int)}.
  1.2608 +*/
  1.2609 +void Calendar::validateField(UCalendarDateFields field, int32_t min, int32_t max, UErrorCode& status)
  1.2610 +{
  1.2611 +    int32_t value = fFields[field];
  1.2612 +    if (value < min || value > max) {
  1.2613 +#if defined (U_DEBUG_CAL)
  1.2614 +        fprintf(stderr, "%s:%d: ILLEGAL ARG because of field %s out of range %d..%d  at %d\n", 
  1.2615 +            __FILE__, __LINE__,fldName(field),min,max,value);
  1.2616 +#endif
  1.2617 +        status = U_ILLEGAL_ARGUMENT_ERROR;
  1.2618 +        return;
  1.2619 +    }
  1.2620 +}
  1.2621 +
  1.2622 +// -------------------------
  1.2623 +
  1.2624 +const UFieldResolutionTable* Calendar::getFieldResolutionTable() const {
  1.2625 +    return kDatePrecedence;
  1.2626 +}
  1.2627 +
  1.2628 +
  1.2629 +UCalendarDateFields Calendar::newerField(UCalendarDateFields defaultField, UCalendarDateFields alternateField) const
  1.2630 +{
  1.2631 +    if (fStamp[alternateField] > fStamp[defaultField]) {
  1.2632 +        return alternateField;
  1.2633 +    }
  1.2634 +    return defaultField;
  1.2635 +}
  1.2636 +
  1.2637 +UCalendarDateFields Calendar::resolveFields(const UFieldResolutionTable* precedenceTable) {
  1.2638 +    int32_t bestField = UCAL_FIELD_COUNT;
  1.2639 +    int32_t tempBestField;
  1.2640 +    for (int32_t g=0; precedenceTable[g][0][0] != -1 && (bestField == UCAL_FIELD_COUNT); ++g) {
  1.2641 +        int32_t bestStamp = kUnset;
  1.2642 +        for (int32_t l=0; precedenceTable[g][l][0] != -1; ++l) {
  1.2643 +            int32_t lineStamp = kUnset;
  1.2644 +            // Skip over first entry if it is negative
  1.2645 +            for (int32_t i=((precedenceTable[g][l][0]>=kResolveRemap)?1:0); precedenceTable[g][l][i]!=-1; ++i) {
  1.2646 +                U_ASSERT(precedenceTable[g][l][i] < UCAL_FIELD_COUNT);
  1.2647 +                int32_t s = fStamp[precedenceTable[g][l][i]];
  1.2648 +                // If any field is unset then don't use this line
  1.2649 +                if (s == kUnset) {
  1.2650 +                    goto linesInGroup;
  1.2651 +                } else if(s > lineStamp) {
  1.2652 +                    lineStamp = s;
  1.2653 +                }
  1.2654 +            }
  1.2655 +            // Record new maximum stamp & field no.
  1.2656 +            if (lineStamp > bestStamp) {
  1.2657 +                tempBestField = precedenceTable[g][l][0]; // First field refers to entire line
  1.2658 +                if (tempBestField >= kResolveRemap) {
  1.2659 +                    tempBestField &= (kResolveRemap-1);
  1.2660 +                    // This check is needed to resolve some issues with UCAL_YEAR precedence mapping
  1.2661 +                    if (tempBestField != UCAL_DATE || (fStamp[UCAL_WEEK_OF_MONTH] < fStamp[tempBestField])) {
  1.2662 +                        bestField = tempBestField;
  1.2663 +                    }
  1.2664 +                } else {
  1.2665 +                    bestField = tempBestField;
  1.2666 +                }
  1.2667 +
  1.2668 +                if (bestField == tempBestField) {
  1.2669 +                    bestStamp = lineStamp;
  1.2670 +                }
  1.2671 +            }
  1.2672 +linesInGroup:
  1.2673 +            ;
  1.2674 +        }
  1.2675 +    }
  1.2676 +    return (UCalendarDateFields)bestField;
  1.2677 +}
  1.2678 +
  1.2679 +const UFieldResolutionTable Calendar::kDatePrecedence[] =
  1.2680 +{ 
  1.2681 +    {
  1.2682 +        { UCAL_DAY_OF_MONTH, kResolveSTOP },
  1.2683 +        { UCAL_WEEK_OF_YEAR, UCAL_DAY_OF_WEEK, kResolveSTOP },
  1.2684 +        { UCAL_WEEK_OF_MONTH, UCAL_DAY_OF_WEEK, kResolveSTOP },
  1.2685 +        { UCAL_DAY_OF_WEEK_IN_MONTH, UCAL_DAY_OF_WEEK, kResolveSTOP },
  1.2686 +        { UCAL_WEEK_OF_YEAR, UCAL_DOW_LOCAL, kResolveSTOP },
  1.2687 +        { UCAL_WEEK_OF_MONTH, UCAL_DOW_LOCAL, kResolveSTOP },
  1.2688 +        { UCAL_DAY_OF_WEEK_IN_MONTH, UCAL_DOW_LOCAL, kResolveSTOP },
  1.2689 +        { UCAL_DAY_OF_YEAR, kResolveSTOP },
  1.2690 +        { kResolveRemap | UCAL_DAY_OF_MONTH, UCAL_YEAR, kResolveSTOP },  // if YEAR is set over YEAR_WOY use DAY_OF_MONTH
  1.2691 +        { kResolveRemap | UCAL_WEEK_OF_YEAR, UCAL_YEAR_WOY, kResolveSTOP },  // if YEAR_WOY is set,  calc based on WEEK_OF_YEAR
  1.2692 +        { kResolveSTOP }
  1.2693 +    },
  1.2694 +    {
  1.2695 +        { UCAL_WEEK_OF_YEAR, kResolveSTOP },
  1.2696 +        { UCAL_WEEK_OF_MONTH, kResolveSTOP },
  1.2697 +        { UCAL_DAY_OF_WEEK_IN_MONTH, kResolveSTOP },
  1.2698 +        { kResolveRemap | UCAL_DAY_OF_WEEK_IN_MONTH, UCAL_DAY_OF_WEEK, kResolveSTOP },
  1.2699 +        { kResolveRemap | UCAL_DAY_OF_WEEK_IN_MONTH, UCAL_DOW_LOCAL, kResolveSTOP },
  1.2700 +        { kResolveSTOP }
  1.2701 +    }, 
  1.2702 +    {{kResolveSTOP}}
  1.2703 +};
  1.2704 +
  1.2705 +
  1.2706 +const UFieldResolutionTable Calendar::kDOWPrecedence[] = 
  1.2707 +{
  1.2708 +    {
  1.2709 +        { UCAL_DAY_OF_WEEK,kResolveSTOP, kResolveSTOP },
  1.2710 +        { UCAL_DOW_LOCAL,kResolveSTOP, kResolveSTOP },
  1.2711 +        {kResolveSTOP}
  1.2712 +    },
  1.2713 +    {{kResolveSTOP}}
  1.2714 +};
  1.2715 +
  1.2716 +// precedence for calculating a year
  1.2717 +const UFieldResolutionTable Calendar::kYearPrecedence[] = 
  1.2718 +{
  1.2719 +    {
  1.2720 +        { UCAL_YEAR, kResolveSTOP },
  1.2721 +        { UCAL_EXTENDED_YEAR, kResolveSTOP },
  1.2722 +        { UCAL_YEAR_WOY, UCAL_WEEK_OF_YEAR, kResolveSTOP },  // YEAR_WOY is useless without WEEK_OF_YEAR
  1.2723 +        { kResolveSTOP }
  1.2724 +    },
  1.2725 +    {{kResolveSTOP}}
  1.2726 +};
  1.2727 +
  1.2728 +
  1.2729 +// -------------------------
  1.2730 +
  1.2731 +
  1.2732 +void Calendar::computeTime(UErrorCode& status) {
  1.2733 +    if (!isLenient()) {
  1.2734 +        validateFields(status);
  1.2735 +        if (U_FAILURE(status)) {
  1.2736 +            return;
  1.2737 +        }
  1.2738 +    }
  1.2739 +
  1.2740 +    // Compute the Julian day
  1.2741 +    int32_t julianDay = computeJulianDay();
  1.2742 +
  1.2743 +    double millis = Grego::julianDayToMillis(julianDay);
  1.2744 +
  1.2745 +#if defined (U_DEBUG_CAL)
  1.2746 +    //  int32_t julianInsanityCheck =  (int32_t)ClockMath::floorDivide(millis, kOneDay);
  1.2747 +    //  julianInsanityCheck += kEpochStartAsJulianDay;
  1.2748 +    //  if(1 || julianInsanityCheck != julianDay) {
  1.2749 +    //    fprintf(stderr, "%s:%d- D'oh- computed jules %d, to mills (%s)%.lf, recomputed %d\n",
  1.2750 +    //            __FILE__, __LINE__, julianDay, millis<0.0?"NEG":"", millis, julianInsanityCheck);
  1.2751 +    //  }
  1.2752 +#endif
  1.2753 +
  1.2754 +    int32_t millisInDay;
  1.2755 +
  1.2756 +    // We only use MILLISECONDS_IN_DAY if it has been set by the user.
  1.2757 +    // This makes it possible for the caller to set the calendar to a
  1.2758 +    // time and call clear(MONTH) to reset the MONTH to January.  This
  1.2759 +    // is legacy behavior.  Without this, clear(MONTH) has no effect,
  1.2760 +    // since the internally set JULIAN_DAY is used.
  1.2761 +    if (fStamp[UCAL_MILLISECONDS_IN_DAY] >= ((int32_t)kMinimumUserStamp) &&
  1.2762 +            newestStamp(UCAL_AM_PM, UCAL_MILLISECOND, kUnset) <= fStamp[UCAL_MILLISECONDS_IN_DAY]) {
  1.2763 +        millisInDay = internalGet(UCAL_MILLISECONDS_IN_DAY);
  1.2764 +    } else {
  1.2765 +        millisInDay = computeMillisInDay();
  1.2766 +    }
  1.2767 +
  1.2768 +    UDate t = 0;
  1.2769 +    if (fStamp[UCAL_ZONE_OFFSET] >= ((int32_t)kMinimumUserStamp) || fStamp[UCAL_DST_OFFSET] >= ((int32_t)kMinimumUserStamp)) {
  1.2770 +        t = millis + millisInDay - (internalGet(UCAL_ZONE_OFFSET) + internalGet(UCAL_DST_OFFSET));
  1.2771 +    } else {
  1.2772 +        // Compute the time zone offset and DST offset.  There are two potential
  1.2773 +        // ambiguities here.  We'll assume a 2:00 am (wall time) switchover time
  1.2774 +        // for discussion purposes here.
  1.2775 +        //
  1.2776 +        // 1. The positive offset change such as transition into DST.
  1.2777 +        //    Here, a designated time of 2:00 am - 2:59 am does not actually exist.
  1.2778 +        //    For this case, skippedWallTime option specifies the behavior.
  1.2779 +        //    For example, 2:30 am is interpreted as;
  1.2780 +        //      - WALLTIME_LAST(default): 3:30 am (DST) (interpreting 2:30 am as 31 minutes after 1:59 am (STD))
  1.2781 +        //      - WALLTIME_FIRST: 1:30 am (STD) (interpreting 2:30 am as 30 minutes before 3:00 am (DST))
  1.2782 +        //      - WALLTIME_NEXT_VALID: 3:00 am (DST) (next valid time after 2:30 am on a wall clock)
  1.2783 +        // 2. The negative offset change such as transition out of DST.
  1.2784 +        //    Here, a designated time of 1:00 am - 1:59 am can be in standard or DST.  Both are valid
  1.2785 +        //    representations (the rep jumps from 1:59:59 DST to 1:00:00 Std).
  1.2786 +        //    For this case, repeatedWallTime option specifies the behavior.
  1.2787 +        //    For example, 1:30 am is interpreted as;
  1.2788 +        //      - WALLTIME_LAST(default): 1:30 am (STD) - latter occurrence
  1.2789 +        //      - WALLTIME_FIRST: 1:30 am (DST) - former occurrence
  1.2790 +        //
  1.2791 +        // In addition to above, when calendar is strict (not default), wall time falls into
  1.2792 +        // the skipped time range will be processed as an error case.
  1.2793 +        //
  1.2794 +        // These special cases are mostly handled in #computeZoneOffset(long), except WALLTIME_NEXT_VALID
  1.2795 +        // at positive offset change. The protected method computeZoneOffset(long) is exposed to Calendar
  1.2796 +        // subclass implementations and marked as @stable. Strictly speaking, WALLTIME_NEXT_VALID
  1.2797 +        // should be also handled in the same place, but we cannot change the code flow without deprecating
  1.2798 +        // the protected method.
  1.2799 +        //
  1.2800 +        // We use the TimeZone object, unless the user has explicitly set the ZONE_OFFSET
  1.2801 +        // or DST_OFFSET fields; then we use those fields.
  1.2802 +
  1.2803 +        if (!isLenient() || fSkippedWallTime == UCAL_WALLTIME_NEXT_VALID) {
  1.2804 +            // When strict, invalidate a wall time falls into a skipped wall time range.
  1.2805 +            // When lenient and skipped wall time option is WALLTIME_NEXT_VALID,
  1.2806 +            // the result time will be adjusted to the next valid time (on wall clock).
  1.2807 +            int32_t zoneOffset = computeZoneOffset(millis, millisInDay, status);
  1.2808 +            UDate tmpTime = millis + millisInDay - zoneOffset;
  1.2809 +
  1.2810 +            int32_t raw, dst;
  1.2811 +            fZone->getOffset(tmpTime, FALSE, raw, dst, status);
  1.2812 +
  1.2813 +            if (U_SUCCESS(status)) {
  1.2814 +                // zoneOffset != (raw + dst) only when the given wall time fall into
  1.2815 +                // a skipped wall time range caused by positive zone offset transition.
  1.2816 +                if (zoneOffset != (raw + dst)) {
  1.2817 +                    if (!isLenient()) {
  1.2818 +                        status = U_ILLEGAL_ARGUMENT_ERROR;
  1.2819 +                    } else {
  1.2820 +                        U_ASSERT(fSkippedWallTime == UCAL_WALLTIME_NEXT_VALID);
  1.2821 +                        // Adjust time to the next valid wall clock time.
  1.2822 +                        // At this point, tmpTime is on or after the zone offset transition causing
  1.2823 +                        // the skipped time range.
  1.2824 +
  1.2825 +                        BasicTimeZone *btz = getBasicTimeZone();
  1.2826 +                        if (btz) {
  1.2827 +                            TimeZoneTransition transition;
  1.2828 +                            UBool hasTransition = btz->getPreviousTransition(tmpTime, TRUE, transition);
  1.2829 +                            if (hasTransition) {
  1.2830 +                                t = transition.getTime();
  1.2831 +                            } else {
  1.2832 +                                // Could not find any transitions.
  1.2833 +                                // Note: This should never happen.
  1.2834 +                                status = U_INTERNAL_PROGRAM_ERROR;
  1.2835 +                            }
  1.2836 +                        } else {
  1.2837 +                            // If not BasicTimeZone, return unsupported error for now.
  1.2838 +                            // TODO: We may support non-BasicTimeZone in future.
  1.2839 +                            status = U_UNSUPPORTED_ERROR;
  1.2840 +                        }
  1.2841 +                    }
  1.2842 +                } else {
  1.2843 +                    t = tmpTime;
  1.2844 +                }
  1.2845 +            }
  1.2846 +        } else {
  1.2847 +            t = millis + millisInDay - computeZoneOffset(millis, millisInDay, status);
  1.2848 +        }
  1.2849 +    }
  1.2850 +    if (U_SUCCESS(status)) {
  1.2851 +        internalSetTime(t);
  1.2852 +    }
  1.2853 +}
  1.2854 +
  1.2855 +/**
  1.2856 +* Compute the milliseconds in the day from the fields.  This is a
  1.2857 +* value from 0 to 23:59:59.999 inclusive, unless fields are out of
  1.2858 +* range, in which case it can be an arbitrary value.  This value
  1.2859 +* reflects local zone wall time.
  1.2860 +* @stable ICU 2.0
  1.2861 +*/
  1.2862 +int32_t Calendar::computeMillisInDay() {
  1.2863 +  // Do the time portion of the conversion.
  1.2864 +
  1.2865 +    int32_t millisInDay = 0;
  1.2866 +
  1.2867 +    // Find the best set of fields specifying the time of day.  There
  1.2868 +    // are only two possibilities here; the HOUR_OF_DAY or the
  1.2869 +    // AM_PM and the HOUR.
  1.2870 +    int32_t hourOfDayStamp = fStamp[UCAL_HOUR_OF_DAY];
  1.2871 +    int32_t hourStamp = (fStamp[UCAL_HOUR] > fStamp[UCAL_AM_PM])?fStamp[UCAL_HOUR]:fStamp[UCAL_AM_PM];
  1.2872 +    int32_t bestStamp = (hourStamp > hourOfDayStamp) ? hourStamp : hourOfDayStamp;
  1.2873 +
  1.2874 +    // Hours
  1.2875 +    if (bestStamp != kUnset) {
  1.2876 +        if (bestStamp == hourOfDayStamp) {
  1.2877 +            // Don't normalize here; let overflow bump into the next period.
  1.2878 +            // This is consistent with how we handle other fields.
  1.2879 +            millisInDay += internalGet(UCAL_HOUR_OF_DAY);
  1.2880 +        } else {
  1.2881 +            // Don't normalize here; let overflow bump into the next period.
  1.2882 +            // This is consistent with how we handle other fields.
  1.2883 +            millisInDay += internalGet(UCAL_HOUR);
  1.2884 +            millisInDay += 12 * internalGet(UCAL_AM_PM); // Default works for unset AM_PM
  1.2885 +        }
  1.2886 +    }
  1.2887 +
  1.2888 +    // We use the fact that unset == 0; we start with millisInDay
  1.2889 +    // == HOUR_OF_DAY.
  1.2890 +    millisInDay *= 60;
  1.2891 +    millisInDay += internalGet(UCAL_MINUTE); // now have minutes
  1.2892 +    millisInDay *= 60;
  1.2893 +    millisInDay += internalGet(UCAL_SECOND); // now have seconds
  1.2894 +    millisInDay *= 1000;
  1.2895 +    millisInDay += internalGet(UCAL_MILLISECOND); // now have millis
  1.2896 +
  1.2897 +    return millisInDay;
  1.2898 +}
  1.2899 +
  1.2900 +/**
  1.2901 +* This method can assume EXTENDED_YEAR has been set.
  1.2902 +* @param millis milliseconds of the date fields
  1.2903 +* @param millisInDay milliseconds of the time fields; may be out
  1.2904 +* or range.
  1.2905 +* @stable ICU 2.0
  1.2906 +*/
  1.2907 +int32_t Calendar::computeZoneOffset(double millis, int32_t millisInDay, UErrorCode &ec) {
  1.2908 +    int32_t rawOffset, dstOffset;
  1.2909 +    UDate wall = millis + millisInDay;
  1.2910 +    BasicTimeZone* btz = getBasicTimeZone();
  1.2911 +    if (btz) {
  1.2912 +        int duplicatedTimeOpt = (fRepeatedWallTime == UCAL_WALLTIME_FIRST) ? BasicTimeZone::kFormer : BasicTimeZone::kLatter;
  1.2913 +        int nonExistingTimeOpt = (fSkippedWallTime == UCAL_WALLTIME_FIRST) ? BasicTimeZone::kLatter : BasicTimeZone::kFormer;
  1.2914 +        btz->getOffsetFromLocal(wall, nonExistingTimeOpt, duplicatedTimeOpt, rawOffset, dstOffset, ec);
  1.2915 +    } else {
  1.2916 +        const TimeZone& tz = getTimeZone();
  1.2917 +        // By default, TimeZone::getOffset behaves UCAL_WALLTIME_LAST for both.
  1.2918 +        tz.getOffset(wall, TRUE, rawOffset, dstOffset, ec);
  1.2919 +
  1.2920 +        UBool sawRecentNegativeShift = FALSE;
  1.2921 +        if (fRepeatedWallTime == UCAL_WALLTIME_FIRST) {
  1.2922 +            // Check if the given wall time falls into repeated time range
  1.2923 +            UDate tgmt = wall - (rawOffset + dstOffset);
  1.2924 +
  1.2925 +            // Any negative zone transition within last 6 hours?
  1.2926 +            // Note: The maximum historic negative zone transition is -3 hours in the tz database.
  1.2927 +            // 6 hour window would be sufficient for this purpose.
  1.2928 +            int32_t tmpRaw, tmpDst;
  1.2929 +            tz.getOffset(tgmt - 6*60*60*1000, FALSE, tmpRaw, tmpDst, ec);
  1.2930 +            int32_t offsetDelta = (rawOffset + dstOffset) - (tmpRaw + tmpDst);
  1.2931 +
  1.2932 +            U_ASSERT(offsetDelta < -6*60*60*1000);
  1.2933 +            if (offsetDelta < 0) {
  1.2934 +                sawRecentNegativeShift = TRUE;
  1.2935 +                // Negative shift within last 6 hours. When UCAL_WALLTIME_FIRST is used and the given wall time falls
  1.2936 +                // into the repeated time range, use offsets before the transition.
  1.2937 +                // Note: If it does not fall into the repeated time range, offsets remain unchanged below.
  1.2938 +                tz.getOffset(wall + offsetDelta, TRUE, rawOffset, dstOffset, ec);
  1.2939 +            }
  1.2940 +        }
  1.2941 +        if (!sawRecentNegativeShift && fSkippedWallTime == UCAL_WALLTIME_FIRST) {
  1.2942 +            // When skipped wall time option is WALLTIME_FIRST,
  1.2943 +            // recalculate offsets from the resolved time (non-wall).
  1.2944 +            // When the given wall time falls into skipped wall time,
  1.2945 +            // the offsets will be based on the zone offsets AFTER
  1.2946 +            // the transition (which means, earliest possibe interpretation).
  1.2947 +            UDate tgmt = wall - (rawOffset + dstOffset);
  1.2948 +            tz.getOffset(tgmt, FALSE, rawOffset, dstOffset, ec);
  1.2949 +        }
  1.2950 +    }
  1.2951 +    return rawOffset + dstOffset;
  1.2952 +}
  1.2953 +
  1.2954 +int32_t Calendar::computeJulianDay() 
  1.2955 +{
  1.2956 +    // We want to see if any of the date fields is newer than the
  1.2957 +    // JULIAN_DAY.  If not, then we use JULIAN_DAY.  If so, then we do
  1.2958 +    // the normal resolution.  We only use JULIAN_DAY if it has been
  1.2959 +    // set by the user.  This makes it possible for the caller to set
  1.2960 +    // the calendar to a time and call clear(MONTH) to reset the MONTH
  1.2961 +    // to January.  This is legacy behavior.  Without this,
  1.2962 +    // clear(MONTH) has no effect, since the internally set JULIAN_DAY
  1.2963 +    // is used.
  1.2964 +    if (fStamp[UCAL_JULIAN_DAY] >= (int32_t)kMinimumUserStamp) {
  1.2965 +        int32_t bestStamp = newestStamp(UCAL_ERA, UCAL_DAY_OF_WEEK_IN_MONTH, kUnset);
  1.2966 +        bestStamp = newestStamp(UCAL_YEAR_WOY, UCAL_EXTENDED_YEAR, bestStamp);
  1.2967 +        if (bestStamp <= fStamp[UCAL_JULIAN_DAY]) {
  1.2968 +            return internalGet(UCAL_JULIAN_DAY);
  1.2969 +        }
  1.2970 +    }
  1.2971 +
  1.2972 +    UCalendarDateFields bestField = resolveFields(getFieldResolutionTable());
  1.2973 +    if (bestField == UCAL_FIELD_COUNT) {
  1.2974 +        bestField = UCAL_DAY_OF_MONTH;
  1.2975 +    }
  1.2976 +
  1.2977 +    return handleComputeJulianDay(bestField);
  1.2978 +}
  1.2979 +
  1.2980 +// -------------------------------------------
  1.2981 +
  1.2982 +int32_t Calendar::handleComputeJulianDay(UCalendarDateFields bestField)  {
  1.2983 +    UBool useMonth = (bestField == UCAL_DAY_OF_MONTH ||
  1.2984 +        bestField == UCAL_WEEK_OF_MONTH ||
  1.2985 +        bestField == UCAL_DAY_OF_WEEK_IN_MONTH);
  1.2986 +    int32_t year;
  1.2987 +
  1.2988 +    if (bestField == UCAL_WEEK_OF_YEAR) {
  1.2989 +        year = internalGet(UCAL_YEAR_WOY, handleGetExtendedYear());
  1.2990 +        internalSet(UCAL_EXTENDED_YEAR, year);
  1.2991 +    } else {
  1.2992 +        year = handleGetExtendedYear();
  1.2993 +        internalSet(UCAL_EXTENDED_YEAR, year);
  1.2994 +    }
  1.2995 +
  1.2996 +#if defined (U_DEBUG_CAL) 
  1.2997 +    fprintf(stderr, "%s:%d: bestField= %s - y=%d\n", __FILE__, __LINE__, fldName(bestField), year);
  1.2998 +#endif 
  1.2999 +
  1.3000 +    // Get the Julian day of the day BEFORE the start of this year.
  1.3001 +    // If useMonth is true, get the day before the start of the month.
  1.3002 +
  1.3003 +    // give calendar subclass a chance to have a default 'first' month
  1.3004 +    int32_t month;
  1.3005 +
  1.3006 +    if(isSet(UCAL_MONTH)) {
  1.3007 +        month = internalGet(UCAL_MONTH);
  1.3008 +    } else {
  1.3009 +        month = getDefaultMonthInYear(year);
  1.3010 +    }
  1.3011 +
  1.3012 +    int32_t julianDay = handleComputeMonthStart(year, useMonth ? month : 0, useMonth);
  1.3013 +
  1.3014 +    if (bestField == UCAL_DAY_OF_MONTH) {
  1.3015 +
  1.3016 +        // give calendar subclass a chance to have a default 'first' dom
  1.3017 +        int32_t dayOfMonth;
  1.3018 +        if(isSet(UCAL_DAY_OF_MONTH)) {
  1.3019 +            dayOfMonth = internalGet(UCAL_DAY_OF_MONTH,1);
  1.3020 +        } else {
  1.3021 +            dayOfMonth = getDefaultDayInMonth(year, month);
  1.3022 +        }
  1.3023 +        return julianDay + dayOfMonth;
  1.3024 +    }
  1.3025 +
  1.3026 +    if (bestField == UCAL_DAY_OF_YEAR) {
  1.3027 +        return julianDay + internalGet(UCAL_DAY_OF_YEAR);
  1.3028 +    }
  1.3029 +
  1.3030 +    int32_t firstDayOfWeek = getFirstDayOfWeek(); // Localized fdw
  1.3031 +
  1.3032 +    // At this point julianDay is the 0-based day BEFORE the first day of
  1.3033 +    // January 1, year 1 of the given calendar.  If julianDay == 0, it
  1.3034 +    // specifies (Jan. 1, 1) - 1, in whatever calendar we are using (Julian
  1.3035 +    // or Gregorian). (or it is before the month we are in, if useMonth is True)
  1.3036 +
  1.3037 +    // At this point we need to process the WEEK_OF_MONTH or
  1.3038 +    // WEEK_OF_YEAR, which are similar, or the DAY_OF_WEEK_IN_MONTH.
  1.3039 +    // First, perform initial shared computations.  These locate the
  1.3040 +    // first week of the period.
  1.3041 +
  1.3042 +    // Get the 0-based localized DOW of day one of the month or year.
  1.3043 +    // Valid range 0..6.
  1.3044 +    int32_t first = julianDayToDayOfWeek(julianDay + 1) - firstDayOfWeek;
  1.3045 +    if (first < 0) {
  1.3046 +        first += 7;
  1.3047 +    }
  1.3048 +
  1.3049 +    int32_t dowLocal = getLocalDOW();
  1.3050 +
  1.3051 +    // Find the first target DOW (dowLocal) in the month or year.
  1.3052 +    // Actually, it may be just before the first of the month or year.
  1.3053 +    // It will be an integer from -5..7.
  1.3054 +    int32_t date = 1 - first + dowLocal;
  1.3055 +
  1.3056 +    if (bestField == UCAL_DAY_OF_WEEK_IN_MONTH) {
  1.3057 +        // Adjust the target DOW to be in the month or year.
  1.3058 +        if (date < 1) {
  1.3059 +            date += 7;
  1.3060 +        }
  1.3061 +
  1.3062 +        // The only trickiness occurs if the day-of-week-in-month is
  1.3063 +        // negative.
  1.3064 +        int32_t dim = internalGet(UCAL_DAY_OF_WEEK_IN_MONTH, 1);
  1.3065 +        if (dim >= 0) {
  1.3066 +            date += 7*(dim - 1);
  1.3067 +
  1.3068 +        } else {
  1.3069 +            // Move date to the last of this day-of-week in this month,
  1.3070 +            // then back up as needed.  If dim==-1, we don't back up at
  1.3071 +            // all.  If dim==-2, we back up once, etc.  Don't back up
  1.3072 +            // past the first of the given day-of-week in this month.
  1.3073 +            // Note that we handle -2, -3, etc. correctly, even though
  1.3074 +            // values < -1 are technically disallowed.
  1.3075 +            int32_t m = internalGet(UCAL_MONTH, UCAL_JANUARY);
  1.3076 +            int32_t monthLength = handleGetMonthLength(year, m);
  1.3077 +            date += ((monthLength - date) / 7 + dim + 1) * 7;
  1.3078 +        }
  1.3079 +    } else {
  1.3080 +#if defined (U_DEBUG_CAL) 
  1.3081 +        fprintf(stderr, "%s:%d - bf= %s\n", __FILE__, __LINE__, fldName(bestField));
  1.3082 +#endif 
  1.3083 +
  1.3084 +        if(bestField == UCAL_WEEK_OF_YEAR) {  // ------------------------------------- WOY -------------
  1.3085 +            if(!isSet(UCAL_YEAR_WOY) ||  // YWOY not set at all or
  1.3086 +                ( (resolveFields(kYearPrecedence) != UCAL_YEAR_WOY) // YWOY doesn't have precedence
  1.3087 +                && (fStamp[UCAL_YEAR_WOY]!=kInternallySet) ) ) // (excluding where all fields are internally set - then YWOY is used)
  1.3088 +            {
  1.3089 +                // need to be sure to stay in 'real' year.
  1.3090 +                int32_t woy = internalGet(bestField);
  1.3091 +
  1.3092 +                int32_t nextJulianDay = handleComputeMonthStart(year+1, 0, FALSE); // jd of day before jan 1
  1.3093 +                int32_t nextFirst = julianDayToDayOfWeek(nextJulianDay + 1) - firstDayOfWeek; 
  1.3094 +
  1.3095 +                if (nextFirst < 0) { // 0..6 ldow of Jan 1
  1.3096 +                    nextFirst += 7;
  1.3097 +                }
  1.3098 +
  1.3099 +                if(woy==1) {  // FIRST WEEK ---------------------------------
  1.3100 +#if defined (U_DEBUG_CAL) 
  1.3101 +                    fprintf(stderr, "%s:%d - woy=%d, yp=%d, nj(%d)=%d, nf=%d", __FILE__, __LINE__, 
  1.3102 +                        internalGet(bestField), resolveFields(kYearPrecedence), year+1, 
  1.3103 +                        nextJulianDay, nextFirst);
  1.3104 +
  1.3105 +                    fprintf(stderr, " next: %d DFW,  min=%d   \n", (7-nextFirst), getMinimalDaysInFirstWeek() );
  1.3106 +#endif 
  1.3107 +
  1.3108 +                    // nextFirst is now the localized DOW of Jan 1  of y-woy+1
  1.3109 +                    if((nextFirst > 0) &&   // Jan 1 starts on FDOW
  1.3110 +                        (7-nextFirst) >= getMinimalDaysInFirstWeek()) // or enough days in the week
  1.3111 +                    {
  1.3112 +                        // Jan 1 of (yearWoy+1) is in yearWoy+1 - recalculate JD to next year
  1.3113 +#if defined (U_DEBUG_CAL) 
  1.3114 +                        fprintf(stderr, "%s:%d - was going to move JD from %d to %d [d%d]\n", __FILE__, __LINE__, 
  1.3115 +                            julianDay, nextJulianDay, (nextJulianDay-julianDay));
  1.3116 +#endif 
  1.3117 +                        julianDay = nextJulianDay;
  1.3118 +
  1.3119 +                        // recalculate 'first' [0-based local dow of jan 1]
  1.3120 +                        first = julianDayToDayOfWeek(julianDay + 1) - firstDayOfWeek;
  1.3121 +                        if (first < 0) {
  1.3122 +                            first += 7;
  1.3123 +                        }
  1.3124 +                        // recalculate date.
  1.3125 +                        date = 1 - first + dowLocal;
  1.3126 +                    }
  1.3127 +                } else if(woy>=getLeastMaximum(bestField)) {          
  1.3128 +                    // could be in the last week- find out if this JD would overstep
  1.3129 +                    int32_t testDate = date;
  1.3130 +                    if ((7 - first) < getMinimalDaysInFirstWeek()) {
  1.3131 +                        testDate += 7;
  1.3132 +                    }
  1.3133 +
  1.3134 +                    // Now adjust for the week number.
  1.3135 +                    testDate += 7 * (woy - 1);
  1.3136 +
  1.3137 +#if defined (U_DEBUG_CAL) 
  1.3138 +                    fprintf(stderr, "%s:%d - y=%d, y-1=%d doy%d, njd%d (C.F. %d)\n",
  1.3139 +                        __FILE__, __LINE__, year, year-1, testDate, julianDay+testDate, nextJulianDay);
  1.3140 +#endif
  1.3141 +                    if(julianDay+testDate > nextJulianDay) { // is it past Dec 31?  (nextJulianDay is day BEFORE year+1's  Jan 1)
  1.3142 +                        // Fire up the calculating engines.. retry YWOY = (year-1)
  1.3143 +                        julianDay = handleComputeMonthStart(year-1, 0, FALSE); // jd before Jan 1 of previous year
  1.3144 +                        first = julianDayToDayOfWeek(julianDay + 1) - firstDayOfWeek; // 0 based local dow   of first week
  1.3145 +
  1.3146 +                        if(first < 0) { // 0..6
  1.3147 +                            first += 7;
  1.3148 +                        }
  1.3149 +                        date = 1 - first + dowLocal;
  1.3150 +
  1.3151 +#if defined (U_DEBUG_CAL) 
  1.3152 +                        fprintf(stderr, "%s:%d - date now %d, jd%d, ywoy%d\n",
  1.3153 +                            __FILE__, __LINE__, date, julianDay, year-1);
  1.3154 +#endif
  1.3155 +
  1.3156 +
  1.3157 +                    } /* correction needed */
  1.3158 +                } /* leastmaximum */
  1.3159 +            } /* resolvefields(year) != year_woy */
  1.3160 +        } /* bestfield != week_of_year */
  1.3161 +
  1.3162 +        // assert(bestField == WEEK_OF_MONTH || bestField == WEEK_OF_YEAR)
  1.3163 +        // Adjust for minimal days in first week
  1.3164 +        if ((7 - first) < getMinimalDaysInFirstWeek()) {
  1.3165 +            date += 7;
  1.3166 +        }
  1.3167 +
  1.3168 +        // Now adjust for the week number.
  1.3169 +        date += 7 * (internalGet(bestField) - 1);
  1.3170 +    }
  1.3171 +
  1.3172 +    return julianDay + date;
  1.3173 +}
  1.3174 +
  1.3175 +int32_t
  1.3176 +Calendar::getDefaultMonthInYear(int32_t /*eyear*/) 
  1.3177 +{
  1.3178 +    return 0;
  1.3179 +}
  1.3180 +
  1.3181 +int32_t
  1.3182 +Calendar::getDefaultDayInMonth(int32_t /*eyear*/, int32_t /*month*/) 
  1.3183 +{
  1.3184 +    return 1;
  1.3185 +}
  1.3186 +
  1.3187 +
  1.3188 +int32_t Calendar::getLocalDOW()
  1.3189 +{
  1.3190 +  // Get zero-based localized DOW, valid range 0..6.  This is the DOW
  1.3191 +    // we are looking for.
  1.3192 +    int32_t dowLocal = 0;
  1.3193 +    switch (resolveFields(kDOWPrecedence)) {
  1.3194 +    case UCAL_DAY_OF_WEEK:
  1.3195 +        dowLocal = internalGet(UCAL_DAY_OF_WEEK) - fFirstDayOfWeek;
  1.3196 +        break;
  1.3197 +    case UCAL_DOW_LOCAL:
  1.3198 +        dowLocal = internalGet(UCAL_DOW_LOCAL) - 1;
  1.3199 +        break;
  1.3200 +    default:
  1.3201 +        break;
  1.3202 +    }
  1.3203 +    dowLocal = dowLocal % 7;
  1.3204 +    if (dowLocal < 0) {
  1.3205 +        dowLocal += 7;
  1.3206 +    }
  1.3207 +    return dowLocal;
  1.3208 +}
  1.3209 +
  1.3210 +int32_t Calendar::handleGetExtendedYearFromWeekFields(int32_t yearWoy, int32_t woy)
  1.3211 +{
  1.3212 +    // We have UCAL_YEAR_WOY and UCAL_WEEK_OF_YEAR - from those, determine 
  1.3213 +    // what year we fall in, so that other code can set it properly.
  1.3214 +    // (code borrowed from computeWeekFields and handleComputeJulianDay)
  1.3215 +    //return yearWoy;
  1.3216 +
  1.3217 +    // First, we need a reliable DOW.
  1.3218 +    UCalendarDateFields bestField = resolveFields(kDatePrecedence); // !! Note: if subclasses have a different table, they should override handleGetExtendedYearFromWeekFields 
  1.3219 +
  1.3220 +    // Now, a local DOW
  1.3221 +    int32_t dowLocal = getLocalDOW(); // 0..6
  1.3222 +    int32_t firstDayOfWeek = getFirstDayOfWeek(); // Localized fdw
  1.3223 +    int32_t jan1Start = handleComputeMonthStart(yearWoy, 0, FALSE);
  1.3224 +    int32_t nextJan1Start = handleComputeMonthStart(yearWoy+1, 0, FALSE); // next year's Jan1 start
  1.3225 +
  1.3226 +    // At this point julianDay is the 0-based day BEFORE the first day of
  1.3227 +    // January 1, year 1 of the given calendar.  If julianDay == 0, it
  1.3228 +    // specifies (Jan. 1, 1) - 1, in whatever calendar we are using (Julian
  1.3229 +    // or Gregorian). (or it is before the month we are in, if useMonth is True)
  1.3230 +
  1.3231 +    // At this point we need to process the WEEK_OF_MONTH or
  1.3232 +    // WEEK_OF_YEAR, which are similar, or the DAY_OF_WEEK_IN_MONTH.
  1.3233 +    // First, perform initial shared computations.  These locate the
  1.3234 +    // first week of the period.
  1.3235 +
  1.3236 +    // Get the 0-based localized DOW of day one of the month or year.
  1.3237 +    // Valid range 0..6.
  1.3238 +    int32_t first = julianDayToDayOfWeek(jan1Start + 1) - firstDayOfWeek;
  1.3239 +    if (first < 0) {
  1.3240 +        first += 7;
  1.3241 +    }
  1.3242 +    int32_t nextFirst = julianDayToDayOfWeek(nextJan1Start + 1) - firstDayOfWeek;
  1.3243 +    if (nextFirst < 0) {
  1.3244 +        nextFirst += 7;
  1.3245 +    }
  1.3246 +
  1.3247 +    int32_t minDays = getMinimalDaysInFirstWeek();
  1.3248 +    UBool jan1InPrevYear = FALSE;  // January 1st in the year of WOY is the 1st week?  (i.e. first week is < minimal )
  1.3249 +    //UBool nextJan1InPrevYear = FALSE; // January 1st of Year of WOY + 1 is in the first week? 
  1.3250 +
  1.3251 +    if((7 - first) < minDays) { 
  1.3252 +        jan1InPrevYear = TRUE;
  1.3253 +    }
  1.3254 +
  1.3255 +    //   if((7 - nextFirst) < minDays) {
  1.3256 +    //     nextJan1InPrevYear = TRUE;
  1.3257 +    //   }
  1.3258 +
  1.3259 +    switch(bestField) {
  1.3260 +    case UCAL_WEEK_OF_YEAR:
  1.3261 +        if(woy == 1) {
  1.3262 +            if(jan1InPrevYear == TRUE) {
  1.3263 +                // the first week of January is in the previous year
  1.3264 +                // therefore WOY1 is always solidly within yearWoy
  1.3265 +                return yearWoy;
  1.3266 +            } else {
  1.3267 +                // First WOY is split between two years
  1.3268 +                if( dowLocal < first) { // we are prior to Jan 1
  1.3269 +                    return yearWoy-1; // previous year
  1.3270 +                } else {
  1.3271 +                    return yearWoy; // in this year
  1.3272 +                }
  1.3273 +            }
  1.3274 +        } else if(woy >= getLeastMaximum(bestField)) {  
  1.3275 +            // we _might_ be in the last week.. 
  1.3276 +            int32_t jd =  // Calculate JD of our target day:
  1.3277 +                jan1Start +  // JD of Jan 1
  1.3278 +                (7-first) + //  days in the first week (Jan 1.. )
  1.3279 +                (woy-1)*7 + // add the weeks of the year
  1.3280 +                dowLocal;   // the local dow (0..6) of last week
  1.3281 +            if(jan1InPrevYear==FALSE) {
  1.3282 +                jd -= 7; // woy already includes Jan 1's week.
  1.3283 +            }
  1.3284 +
  1.3285 +            if( (jd+1) >= nextJan1Start ) {
  1.3286 +                // we are in week 52 or 53 etc. - actual year is yearWoy+1
  1.3287 +                return yearWoy+1;
  1.3288 +            } else {
  1.3289 +                // still in yearWoy;
  1.3290 +                return yearWoy;
  1.3291 +            }
  1.3292 +        } else {
  1.3293 +            // we're not possibly in the last week -must be ywoy
  1.3294 +            return yearWoy;
  1.3295 +        }
  1.3296 +
  1.3297 +    case UCAL_DATE:
  1.3298 +        if((internalGet(UCAL_MONTH)==0) &&
  1.3299 +            (woy >= getLeastMaximum(UCAL_WEEK_OF_YEAR))) {
  1.3300 +                return yearWoy+1; // month 0, late woy = in the next year
  1.3301 +            } else if(woy==1) {
  1.3302 +                //if(nextJan1InPrevYear) {
  1.3303 +                if(internalGet(UCAL_MONTH)==0) {
  1.3304 +                    return yearWoy;
  1.3305 +                } else {
  1.3306 +                    return yearWoy-1;
  1.3307 +                }
  1.3308 +                //}
  1.3309 +            }
  1.3310 +
  1.3311 +            //(internalGet(UCAL_DATE) <= (7-first)) /* && in minDow  */ ) {
  1.3312 +            //within 1st week and in this month.. 
  1.3313 +            //return yearWoy+1;
  1.3314 +            return yearWoy;
  1.3315 +
  1.3316 +    default: // assume the year is appropriate
  1.3317 +        return yearWoy;
  1.3318 +    }
  1.3319 +}
  1.3320 +
  1.3321 +int32_t Calendar::handleGetMonthLength(int32_t extendedYear, int32_t month) const
  1.3322 +{
  1.3323 +    return handleComputeMonthStart(extendedYear, month+1, TRUE) -
  1.3324 +        handleComputeMonthStart(extendedYear, month, TRUE);
  1.3325 +}
  1.3326 +
  1.3327 +int32_t Calendar::handleGetYearLength(int32_t eyear) const  {
  1.3328 +    return handleComputeMonthStart(eyear+1, 0, FALSE) -
  1.3329 +        handleComputeMonthStart(eyear, 0, FALSE);
  1.3330 +}
  1.3331 +
  1.3332 +int32_t
  1.3333 +Calendar::getActualMaximum(UCalendarDateFields field, UErrorCode& status) const
  1.3334 +{
  1.3335 +    int32_t result;
  1.3336 +    switch (field) {
  1.3337 +    case UCAL_DATE:
  1.3338 +        {
  1.3339 +            if(U_FAILURE(status)) return 0;
  1.3340 +            Calendar *cal = clone();
  1.3341 +            if(!cal) { status = U_MEMORY_ALLOCATION_ERROR; return 0; }
  1.3342 +            cal->setLenient(TRUE);
  1.3343 +            cal->prepareGetActual(field,FALSE,status);
  1.3344 +            result = handleGetMonthLength(cal->get(UCAL_EXTENDED_YEAR, status), cal->get(UCAL_MONTH, status));
  1.3345 +            delete cal;
  1.3346 +        }
  1.3347 +        break;
  1.3348 +
  1.3349 +    case UCAL_DAY_OF_YEAR:
  1.3350 +        {
  1.3351 +            if(U_FAILURE(status)) return 0;
  1.3352 +            Calendar *cal = clone();
  1.3353 +            if(!cal) { status = U_MEMORY_ALLOCATION_ERROR; return 0; }
  1.3354 +            cal->setLenient(TRUE);
  1.3355 +            cal->prepareGetActual(field,FALSE,status);
  1.3356 +            result = handleGetYearLength(cal->get(UCAL_EXTENDED_YEAR, status));
  1.3357 +            delete cal;
  1.3358 +        }
  1.3359 +        break;
  1.3360 +
  1.3361 +    case UCAL_DAY_OF_WEEK:
  1.3362 +    case UCAL_AM_PM:
  1.3363 +    case UCAL_HOUR:
  1.3364 +    case UCAL_HOUR_OF_DAY:
  1.3365 +    case UCAL_MINUTE:
  1.3366 +    case UCAL_SECOND:
  1.3367 +    case UCAL_MILLISECOND:
  1.3368 +    case UCAL_ZONE_OFFSET:
  1.3369 +    case UCAL_DST_OFFSET:
  1.3370 +    case UCAL_DOW_LOCAL:
  1.3371 +    case UCAL_JULIAN_DAY:
  1.3372 +    case UCAL_MILLISECONDS_IN_DAY:
  1.3373 +        // These fields all have fixed minima/maxima
  1.3374 +        result = getMaximum(field);
  1.3375 +        break;
  1.3376 +
  1.3377 +    default:
  1.3378 +        // For all other fields, do it the hard way....
  1.3379 +        result = getActualHelper(field, getLeastMaximum(field), getMaximum(field),status);
  1.3380 +        break;
  1.3381 +    }
  1.3382 +    return result;
  1.3383 +}
  1.3384 +
  1.3385 +
  1.3386 +/**
  1.3387 +* Prepare this calendar for computing the actual minimum or maximum.
  1.3388 +* This method modifies this calendar's fields; it is called on a
  1.3389 +* temporary calendar.
  1.3390 +*
  1.3391 +* <p>Rationale: The semantics of getActualXxx() is to return the
  1.3392 +* maximum or minimum value that the given field can take, taking into
  1.3393 +* account other relevant fields.  In general these other fields are
  1.3394 +* larger fields.  For example, when computing the actual maximum
  1.3395 +* DATE, the current value of DATE itself is ignored,
  1.3396 +* as is the value of any field smaller.
  1.3397 +*
  1.3398 +* <p>The time fields all have fixed minima and maxima, so we don't
  1.3399 +* need to worry about them.  This also lets us set the
  1.3400 +* MILLISECONDS_IN_DAY to zero to erase any effects the time fields
  1.3401 +* might have when computing date fields.
  1.3402 +*
  1.3403 +* <p>DAY_OF_WEEK is adjusted specially for the WEEK_OF_MONTH and
  1.3404 +* WEEK_OF_YEAR fields to ensure that they are computed correctly.
  1.3405 +* @internal
  1.3406 +*/
  1.3407 +void Calendar::prepareGetActual(UCalendarDateFields field, UBool isMinimum, UErrorCode &status)
  1.3408 +{
  1.3409 +    set(UCAL_MILLISECONDS_IN_DAY, 0);
  1.3410 +
  1.3411 +    switch (field) {
  1.3412 +    case UCAL_YEAR:
  1.3413 +    case UCAL_EXTENDED_YEAR:
  1.3414 +        set(UCAL_DAY_OF_YEAR, getGreatestMinimum(UCAL_DAY_OF_YEAR));
  1.3415 +        break;
  1.3416 +
  1.3417 +    case UCAL_YEAR_WOY:
  1.3418 +        set(UCAL_WEEK_OF_YEAR, getGreatestMinimum(UCAL_WEEK_OF_YEAR));
  1.3419 +
  1.3420 +    case UCAL_MONTH:
  1.3421 +        set(UCAL_DATE, getGreatestMinimum(UCAL_DATE));
  1.3422 +        break;
  1.3423 +
  1.3424 +    case UCAL_DAY_OF_WEEK_IN_MONTH:
  1.3425 +        // For dowim, the maximum occurs for the DOW of the first of the
  1.3426 +        // month.
  1.3427 +        set(UCAL_DATE, 1);
  1.3428 +        set(UCAL_DAY_OF_WEEK, get(UCAL_DAY_OF_WEEK, status)); // Make this user set
  1.3429 +        break;
  1.3430 +
  1.3431 +    case UCAL_WEEK_OF_MONTH:
  1.3432 +    case UCAL_WEEK_OF_YEAR:
  1.3433 +        // If we're counting weeks, set the day of the week to either the
  1.3434 +        // first or last localized DOW.  We know the last week of a month
  1.3435 +        // or year will contain the first day of the week, and that the
  1.3436 +        // first week will contain the last DOW.
  1.3437 +        {
  1.3438 +            int32_t dow = fFirstDayOfWeek;
  1.3439 +            if (isMinimum) {
  1.3440 +                dow = (dow + 6) % 7; // set to last DOW
  1.3441 +                if (dow < UCAL_SUNDAY) {
  1.3442 +                    dow += 7;
  1.3443 +                }
  1.3444 +            }
  1.3445 +#if defined (U_DEBUG_CAL) 
  1.3446 +            fprintf(stderr, "prepareGetActualHelper(WOM/WOY) - dow=%d\n", dow);
  1.3447 +#endif
  1.3448 +            set(UCAL_DAY_OF_WEEK, dow);
  1.3449 +        }
  1.3450 +        break;
  1.3451 +    default:
  1.3452 +        break;
  1.3453 +    }
  1.3454 +
  1.3455 +    // Do this last to give it the newest time stamp
  1.3456 +    set(field, getGreatestMinimum(field));
  1.3457 +}
  1.3458 +
  1.3459 +int32_t Calendar::getActualHelper(UCalendarDateFields field, int32_t startValue, int32_t endValue, UErrorCode &status) const
  1.3460 +{
  1.3461 +#if defined (U_DEBUG_CAL) 
  1.3462 +    fprintf(stderr, "getActualHelper(%d,%d .. %d, %s)\n", field, startValue, endValue, u_errorName(status));
  1.3463 +#endif
  1.3464 +    if (startValue == endValue) {
  1.3465 +        // if we know that the maximum value is always the same, just return it
  1.3466 +        return startValue;
  1.3467 +    }
  1.3468 +
  1.3469 +    int32_t delta = (endValue > startValue) ? 1 : -1;
  1.3470 +
  1.3471 +    // clone the calendar so we don't mess with the real one, and set it to
  1.3472 +    // accept anything for the field values
  1.3473 +    if(U_FAILURE(status)) return startValue;
  1.3474 +    Calendar *work = clone();
  1.3475 +    if(!work) { status = U_MEMORY_ALLOCATION_ERROR; return startValue; }
  1.3476 +
  1.3477 +    // need to resolve time here, otherwise, fields set for actual limit
  1.3478 +    // may cause conflict with fields previously set (but not yet resolved).
  1.3479 +    work->complete(status);
  1.3480 +
  1.3481 +    work->setLenient(TRUE);
  1.3482 +    work->prepareGetActual(field, delta < 0, status);
  1.3483 +
  1.3484 +    // now try each value from the start to the end one by one until
  1.3485 +    // we get a value that normalizes to another value.  The last value that
  1.3486 +    // normalizes to itself is the actual maximum for the current date
  1.3487 +    work->set(field, startValue);
  1.3488 +
  1.3489 +    // prepareGetActual sets the first day of week in the same week with
  1.3490 +    // the first day of a month.  Unlike WEEK_OF_YEAR, week number for the
  1.3491 +    // week which contains days from both previous and current month is
  1.3492 +    // not unique.  For example, last several days in the previous month
  1.3493 +    // is week 5, and the rest of week is week 1.
  1.3494 +    int32_t result = startValue;
  1.3495 +    if ((work->get(field, status) != startValue
  1.3496 +         && field != UCAL_WEEK_OF_MONTH && delta > 0 ) || U_FAILURE(status)) {
  1.3497 +#if defined (U_DEBUG_CAL) 
  1.3498 +        fprintf(stderr, "getActualHelper(fld %d) - got  %d (not %d) - %s\n", field, work->get(field,status), startValue, u_errorName(status));
  1.3499 +#endif
  1.3500 +    } else {
  1.3501 +        do {
  1.3502 +            startValue += delta;
  1.3503 +            work->add(field, delta, status);
  1.3504 +            if (work->get(field, status) != startValue || U_FAILURE(status)) {
  1.3505 +#if defined (U_DEBUG_CAL)
  1.3506 +                fprintf(stderr, "getActualHelper(fld %d) - got  %d (not %d), BREAK - %s\n", field, work->get(field,status), startValue, u_errorName(status));
  1.3507 +#endif
  1.3508 +                break;
  1.3509 +            }
  1.3510 +            result = startValue;
  1.3511 +        } while (startValue != endValue);
  1.3512 +    }
  1.3513 +    delete work;
  1.3514 +#if defined (U_DEBUG_CAL) 
  1.3515 +    fprintf(stderr, "getActualHelper(%d) = %d\n", field, result);
  1.3516 +#endif
  1.3517 +    return result;
  1.3518 +}
  1.3519 +
  1.3520 +
  1.3521 +
  1.3522 +
  1.3523 +// -------------------------------------
  1.3524 +
  1.3525 +void
  1.3526 +Calendar::setWeekData(const Locale& desiredLocale, const char *type, UErrorCode& status)
  1.3527 +{
  1.3528 +
  1.3529 +    if (U_FAILURE(status)) return;
  1.3530 +
  1.3531 +    fFirstDayOfWeek = UCAL_SUNDAY;
  1.3532 +    fMinimalDaysInFirstWeek = 1;
  1.3533 +    fWeekendOnset = UCAL_SATURDAY;
  1.3534 +    fWeekendOnsetMillis = 0;
  1.3535 +    fWeekendCease = UCAL_SUNDAY;
  1.3536 +    fWeekendCeaseMillis = 86400000; // 24*60*60*1000
  1.3537 +
  1.3538 +    // Since week and weekend data is territory based instead of language based,
  1.3539 +    // we may need to tweak the locale that we are using to try to get the appropriate
  1.3540 +    // values, using the following logic:
  1.3541 +    // 1). If the locale has a language but no territory, use the territory as defined by 
  1.3542 +    //     the likely subtags.
  1.3543 +    // 2). If the locale has a script designation then we ignore it,
  1.3544 +    //     then remove it ( i.e. "en_Latn_US" becomes "en_US" )
  1.3545 + 
  1.3546 +    char minLocaleID[ULOC_FULLNAME_CAPACITY] = { 0 };
  1.3547 +    UErrorCode myStatus = U_ZERO_ERROR;
  1.3548 +
  1.3549 +    uloc_minimizeSubtags(desiredLocale.getName(),minLocaleID,ULOC_FULLNAME_CAPACITY,&myStatus);
  1.3550 +    Locale min = Locale::createFromName(minLocaleID);
  1.3551 +    Locale useLocale;
  1.3552 +    if ( uprv_strlen(desiredLocale.getCountry()) == 0 || 
  1.3553 +         (uprv_strlen(desiredLocale.getScript()) > 0 && uprv_strlen(min.getScript()) == 0) ) {
  1.3554 +        char maxLocaleID[ULOC_FULLNAME_CAPACITY] = { 0 };
  1.3555 +        myStatus = U_ZERO_ERROR;
  1.3556 +        uloc_addLikelySubtags(desiredLocale.getName(),maxLocaleID,ULOC_FULLNAME_CAPACITY,&myStatus);
  1.3557 +        Locale max = Locale::createFromName(maxLocaleID);
  1.3558 +        useLocale = Locale(max.getLanguage(),max.getCountry());
  1.3559 +    } else {
  1.3560 +        useLocale = Locale(desiredLocale);
  1.3561 +    }
  1.3562 + 
  1.3563 +    /* The code here is somewhat of a hack, since week data and weekend data aren't really tied to 
  1.3564 +       a specific calendar, they aren't truly locale data.  But this is the only place where valid and
  1.3565 +       actual locale can be set, so we take a shot at it here by loading a representative resource
  1.3566 +       from the calendar data.  The code used to use the dateTimeElements resource to get first day
  1.3567 +       of week data, but this was moved to supplemental data under ticket 7755. (JCE) */
  1.3568 +
  1.3569 +    CalendarData calData(useLocale,type,status);
  1.3570 +    UResourceBundle *monthNames = calData.getByKey(gMonthNames,status);
  1.3571 +    if (U_SUCCESS(status)) {
  1.3572 +        U_LOCALE_BASED(locBased,*this);
  1.3573 +        locBased.setLocaleIDs(ures_getLocaleByType(monthNames, ULOC_VALID_LOCALE, &status),
  1.3574 +                              ures_getLocaleByType(monthNames, ULOC_ACTUAL_LOCALE, &status));
  1.3575 +    } else {
  1.3576 +        status = U_USING_FALLBACK_WARNING;
  1.3577 +        return;
  1.3578 +    }
  1.3579 +
  1.3580 +    
  1.3581 +    // Read week data values from supplementalData week data
  1.3582 +    UResourceBundle *rb = ures_openDirect(NULL, "supplementalData", &status);
  1.3583 +    ures_getByKey(rb, "weekData", rb, &status);
  1.3584 +    UResourceBundle *weekData = ures_getByKey(rb, useLocale.getCountry(), NULL, &status);
  1.3585 +    if (status == U_MISSING_RESOURCE_ERROR && rb != NULL) {
  1.3586 +        status = U_ZERO_ERROR;
  1.3587 +        weekData = ures_getByKey(rb, "001", NULL, &status);
  1.3588 +    }
  1.3589 +
  1.3590 +    if (U_FAILURE(status)) {
  1.3591 +#if defined (U_DEBUG_CALDATA)
  1.3592 +        fprintf(stderr, " Failure loading weekData from supplemental = %s\n", u_errorName(status));
  1.3593 +#endif
  1.3594 +        status = U_USING_FALLBACK_WARNING;
  1.3595 +    } else {
  1.3596 +        int32_t arrLen;
  1.3597 +        const int32_t *weekDataArr = ures_getIntVector(weekData,&arrLen,&status);
  1.3598 +        if( U_SUCCESS(status) && arrLen == 6
  1.3599 +                && 1 <= weekDataArr[0] && weekDataArr[0] <= 7
  1.3600 +                && 1 <= weekDataArr[1] && weekDataArr[1] <= 7
  1.3601 +                && 1 <= weekDataArr[2] && weekDataArr[2] <= 7
  1.3602 +                && 1 <= weekDataArr[4] && weekDataArr[4] <= 7) {
  1.3603 +            fFirstDayOfWeek = (UCalendarDaysOfWeek)weekDataArr[0];
  1.3604 +            fMinimalDaysInFirstWeek = (uint8_t)weekDataArr[1];
  1.3605 +            fWeekendOnset = (UCalendarDaysOfWeek)weekDataArr[2];
  1.3606 +            fWeekendOnsetMillis = weekDataArr[3];
  1.3607 +            fWeekendCease = (UCalendarDaysOfWeek)weekDataArr[4];
  1.3608 +            fWeekendCeaseMillis = weekDataArr[5];
  1.3609 +        } else {
  1.3610 +            status = U_INVALID_FORMAT_ERROR;
  1.3611 +        }
  1.3612 +    }
  1.3613 +    ures_close(weekData);
  1.3614 +    ures_close(rb);
  1.3615 +}
  1.3616 +
  1.3617 +/**
  1.3618 +* Recompute the time and update the status fields isTimeSet
  1.3619 +* and areFieldsSet.  Callers should check isTimeSet and only
  1.3620 +* call this method if isTimeSet is false.
  1.3621 +*/
  1.3622 +void 
  1.3623 +Calendar::updateTime(UErrorCode& status) 
  1.3624 +{
  1.3625 +    computeTime(status);
  1.3626 +    if(U_FAILURE(status))
  1.3627 +        return;
  1.3628 +
  1.3629 +    // If we are lenient, we need to recompute the fields to normalize
  1.3630 +    // the values.  Also, if we haven't set all the fields yet (i.e.,
  1.3631 +    // in a newly-created object), we need to fill in the fields. [LIU]
  1.3632 +    if (isLenient() || ! fAreAllFieldsSet) 
  1.3633 +        fAreFieldsSet = FALSE;
  1.3634 +
  1.3635 +    fIsTimeSet = TRUE;
  1.3636 +    fAreFieldsVirtuallySet = FALSE;
  1.3637 +}
  1.3638 +
  1.3639 +Locale 
  1.3640 +Calendar::getLocale(ULocDataLocaleType type, UErrorCode& status) const {
  1.3641 +    U_LOCALE_BASED(locBased, *this);
  1.3642 +    return locBased.getLocale(type, status);
  1.3643 +}
  1.3644 +
  1.3645 +const char *
  1.3646 +Calendar::getLocaleID(ULocDataLocaleType type, UErrorCode& status) const {
  1.3647 +    U_LOCALE_BASED(locBased, *this);
  1.3648 +    return locBased.getLocaleID(type, status);
  1.3649 +}
  1.3650 +
  1.3651 +void
  1.3652 +Calendar::recalculateStamp() {
  1.3653 +    int32_t index;
  1.3654 +    int32_t currentValue;
  1.3655 +    int32_t j, i;
  1.3656 +
  1.3657 +    fNextStamp = 1;
  1.3658 +
  1.3659 +    for (j = 0; j < UCAL_FIELD_COUNT; j++) {
  1.3660 +        currentValue = STAMP_MAX;
  1.3661 +        index = -1;
  1.3662 +        for (i = 0; i < UCAL_FIELD_COUNT; i++) {
  1.3663 +            if (fStamp[i] > fNextStamp && fStamp[i] < currentValue) {
  1.3664 +                currentValue = fStamp[i];
  1.3665 +                index = i;
  1.3666 +            }
  1.3667 +        }
  1.3668 +
  1.3669 +        if (index >= 0) {
  1.3670 +            fStamp[index] = ++fNextStamp;
  1.3671 +        } else {
  1.3672 +            break;
  1.3673 +        }
  1.3674 +    }
  1.3675 +    fNextStamp++;
  1.3676 +}
  1.3677 +
  1.3678 +// Deprecated function. This doesn't need to be inline.
  1.3679 +void
  1.3680 +Calendar::internalSet(EDateFields field, int32_t value)
  1.3681 +{
  1.3682 +    internalSet((UCalendarDateFields) field, value);
  1.3683 +}
  1.3684 +
  1.3685 +BasicTimeZone*
  1.3686 +Calendar::getBasicTimeZone(void) const {
  1.3687 +    if (dynamic_cast<const OlsonTimeZone *>(fZone) != NULL
  1.3688 +        || dynamic_cast<const SimpleTimeZone *>(fZone) != NULL
  1.3689 +        || dynamic_cast<const RuleBasedTimeZone *>(fZone) != NULL
  1.3690 +        || dynamic_cast<const VTimeZone *>(fZone) != NULL) {
  1.3691 +        return (BasicTimeZone*)fZone;
  1.3692 +    }
  1.3693 +    return NULL;
  1.3694 +}
  1.3695 +
  1.3696 +U_NAMESPACE_END
  1.3697 +
  1.3698 +#endif /* #if !UCONFIG_NO_FORMATTING */
  1.3699 +
  1.3700 +
  1.3701 +//eof
  1.3702 +

mercurial