Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / icu / source / i18n / calendar.cpp
index 6494ea1..27825c0 100644 (file)
@@ -1,12 +1,12 @@
 /*
 *******************************************************************************
-* Copyright (C) 1997-2010, International Business Machines Corporation and    *
+* Copyright (C) 1997-2013, International Business Machines Corporation and    *
 * others. All Rights Reserved.                                                *
 *******************************************************************************
 *
 * File CALENDAR.CPP
 *
-* Modification History:
+* Modification History: 
 *
 *   Date        Name        Description
 *   02/03/97    clhuang     Creation.
 *******************************************************************************
 */
 
-#include "unicode/utypeinfo.h"  // for 'typeid' to work 
+#include "utypeinfo.h"  // for 'typeid' to work 
 
 #include "unicode/utypes.h"
 
 #if !UCONFIG_NO_FORMATTING
 
 #include "unicode/gregocal.h"
+#include "unicode/basictz.h"
+#include "unicode/simpletz.h"
+#include "unicode/rbtz.h"
+#include "unicode/vtzone.h"
 #include "gregoimp.h"
 #include "buddhcal.h"
 #include "taiwncal.h"
@@ -41,6 +45,7 @@
 #include "indiancal.h"
 #include "chnsecal.h"
 #include "coptccal.h"
+#include "dangical.h"
 #include "ethpccal.h"
 #include "unicode/calendar.h"
 #include "cpputils.h"
 #include "locbased.h"
 #include "uresimp.h"
 #include "ustrenum.h"
+#include "uassert.h"
+#include "olsontz.h"
 
 #if !UCONFIG_NO_SERVICE
-static U_NAMESPACE_QUALIFIER ICULocaleService* gService = NULL;
+static icu::ICULocaleService* gService = NULL;
+static icu::UInitOnce gServiceInitOnce = U_INITONCE_INITIALIZER;
 #endif
 
 // INTERNAL - for cleanup
@@ -64,6 +72,7 @@ static UBool calendar_cleanup(void) {
         delete gService;
         gService = NULL;
     }
+    gServiceInitOnce.reset();
 #endif
     return TRUE;
 }
@@ -82,9 +91,11 @@ U_CDECL_END
 /** 
  * fldName was removed as a duplicate implementation. 
  * use  udbg_ services instead, 
- * which depend on include files and library from ../tools/ctestfw
+ * which depend on include files and library from ../tools/toolutil, the following circular link:
+ *   CPPFLAGS+=-I$(top_srcdir)/tools/toolutil
+ *   LIBS+=$(LIBICUTOOLUTIL)
  */
-#include "unicode/udbgutil.h"
+#include "udbgutil.h"
 #include <stdio.h>
 
 /**
@@ -138,6 +149,9 @@ U_CFUNC void ucal_dump(UCalendar* cal) {
 
 #endif
 
+/* Max value for stamp allowable before recalculation */
+#define STAMP_MAX 10000
+
 static const char * const gCalTypes[] = {
     "gregorian",
     "japanese",
@@ -152,6 +166,11 @@ static const char * const gCalTypes[] = {
     "coptic",
     "ethiopic",
     "ethiopic-amete-alem",
+    "iso8601",
+    "dangi",
+    "islamic-umalqura",
+    "islamic-tbla",
+    "islamic-rgsa",
     NULL
 };
 
@@ -170,7 +189,12 @@ typedef enum ECalType {
     CALTYPE_INDIAN,
     CALTYPE_COPTIC,
     CALTYPE_ETHIOPIC,
-    CALTYPE_ETHIOPIC_AMETE_ALEM
+    CALTYPE_ETHIOPIC_AMETE_ALEM,
+    CALTYPE_ISO8601,
+    CALTYPE_DANGI,
+    CALTYPE_ISLAMIC_UMALQURA,
+    CALTYPE_ISLAMIC_TBLA,
+    CALTYPE_ISLAMIC_RGSA
 } ECalType;
 
 U_NAMESPACE_BEGIN
@@ -241,8 +265,7 @@ static ECalType getCalendarTypeForLocale(const char *locid) {
     regionLen = uloc_getCountry(canonicalName, region, sizeof(region) - 1, &status);
     if (regionLen == 0) {
         char fullLoc[256];
-        int32_t fullLocLen = 0;
-        fullLocLen = uloc_addLikelySubtags(locid, fullLoc, sizeof(fullLoc) - 1, &status);
+        uloc_addLikelySubtags(locid, fullLoc, sizeof(fullLoc) - 1, &status);
         regionLen = uloc_getCountry(fullLoc, region, sizeof(region) - 1, &status);
     }
     if (U_FAILURE(status)) {
@@ -300,12 +323,20 @@ static Calendar *createStandardCalendar(ECalType calType, const Locale &loc, UEr
         case CALTYPE_PERSIAN:
             cal = new PersianCalendar(loc, status);
             break;
+        case CALTYPE_ISLAMIC_TBLA:
+            cal = new IslamicCalendar(loc, status, IslamicCalendar::TBLA);
+            break;
         case CALTYPE_ISLAMIC_CIVIL:
             cal = new IslamicCalendar(loc, status, IslamicCalendar::CIVIL);
             break;
+        case CALTYPE_ISLAMIC_RGSA:
+            // default any region specific not handled individually to islamic
         case CALTYPE_ISLAMIC:
             cal = new IslamicCalendar(loc, status, IslamicCalendar::ASTRONOMICAL);
             break;
+        case CALTYPE_ISLAMIC_UMALQURA:
+            cal = new IslamicCalendar(loc, status, IslamicCalendar::UMALQURA);
+            break;
         case CALTYPE_HEBREW:
             cal = new HebrewCalendar(loc, status);
             break;
@@ -324,6 +355,14 @@ static Calendar *createStandardCalendar(ECalType calType, const Locale &loc, UEr
         case CALTYPE_ETHIOPIC_AMETE_ALEM:
             cal = new EthiopicCalendar(loc, status, EthiopicCalendar::AMETE_ALEM_ERA);
             break;
+        case CALTYPE_ISO8601:
+            cal = new GregorianCalendar(loc, status);
+            cal->setFirstDayOfWeek(UCAL_MONDAY);
+            cal->setMinimalDaysInFirstWeek(4);
+            break;
+        case CALTYPE_DANGI:
+            cal = new DangiCalendar(loc, status);
+            break;
         default:
             status = U_UNSUPPORTED_ERROR;
     }
@@ -347,7 +386,7 @@ public:
     BasicCalendarFactory()
         : LocaleKeyFactory(LocaleKeyFactory::INVISIBLE) { }
 
-        virtual ~BasicCalendarFactory() {}
+    virtual ~BasicCalendarFactory();
 
 protected:
     //virtual UBool isSupportedID( const UnicodeString& id, UErrorCode& status) const { 
@@ -406,6 +445,7 @@ protected:
     }
 };
 
+BasicCalendarFactory::~BasicCalendarFactory() {}
 
 /** 
 * A factory which looks up the DefaultCalendar resource to determine which class of calendar to use
@@ -413,7 +453,8 @@ protected:
 
 class DefaultCalendarFactory : public ICUResourceBundleFactory {
 public:
-    DefaultCalendarFactory():  ICUResourceBundleFactory() { } 
+    DefaultCalendarFactory() : ICUResourceBundleFactory() { }
+    virtual ~DefaultCalendarFactory();
 protected:
     virtual UObject* create(const ICUServiceKey& key, const ICUService* /*service*/, UErrorCode& status) const  {
 
@@ -427,12 +468,14 @@ protected:
         } else {
             ret->append((UChar)0x40); // '@' is a variant character
             ret->append(UNICODE_STRING("calendar=", 9));
-            ret->append(UnicodeString(gCalTypes[getCalendarTypeForLocale(loc.getName())]));
+            ret->append(UnicodeString(gCalTypes[getCalendarTypeForLocale(loc.getName())], -1, US_INV));
         }
         return ret;
     }
 };
 
+DefaultCalendarFactory::~DefaultCalendarFactory() {}
+
 // -------------------------------------
 class CalendarService : public ICULocaleService {
 public:
@@ -443,6 +486,8 @@ public:
         registerFactory(new DefaultCalendarFactory(), status);
     }
 
+    virtual ~CalendarService();
+
     virtual UObject* cloneInstance(UObject* instance) const {
         UnicodeString *s = dynamic_cast<UnicodeString *>(instance);
         if(s != NULL) {
@@ -482,37 +527,35 @@ public:
     }
 };
 
+CalendarService::~CalendarService() {}
+
 // -------------------------------------
 
 static inline UBool
 isCalendarServiceUsed() {
-    UBool retVal;
-    UMTX_CHECK(NULL, gService != NULL, retVal);
-    return retVal;
+    return !gServiceInitOnce.isReset();
 }
 
 // -------------------------------------
 
-static ICULocaleService* 
-getCalendarService(UErrorCode &status)
+static void U_CALLCONV
+initCalendarService(UErrorCode &status)
 {
-    UBool needInit;
-    UMTX_CHECK(NULL, (UBool)(gService == NULL), needInit);
-    if (needInit) {
 #ifdef U_DEBUG_CALSVC
         fprintf(stderr, "Spinning up Calendar Service\n");
 #endif
-        ICULocaleService * newservice = new CalendarService();
-        if (newservice == NULL) {
+    ucln_i18n_registerCleanup(UCLN_I18N_CALENDAR, calendar_cleanup);
+    gService = new CalendarService();
+    if (gService == NULL) {
             status = U_MEMORY_ALLOCATION_ERROR;
-            return newservice;
+        return;
         }
 #ifdef U_DEBUG_CALSVC
         fprintf(stderr, "Registering classes..\n");
 #endif
 
         // Register all basic instances. 
-        newservice->registerFactory(new BasicCalendarFactory(),status);
+    gService->registerFactory(new BasicCalendarFactory(),status);
 
 #ifdef U_DEBUG_CALSVC
         fprintf(stderr, "Done..\n");
@@ -522,25 +565,15 @@ getCalendarService(UErrorCode &status)
 #ifdef U_DEBUG_CALSVC
             fprintf(stderr, "err (%s) registering classes, deleting service.....\n", u_errorName(status));
 #endif
-            delete newservice;
-            newservice = NULL;
+        delete gService;
+        gService = NULL;
+    }
         }
 
-        if (newservice) {
-            umtx_lock(NULL);
-            if (gService == NULL) {
-                gService = newservice;
-                newservice = NULL;
-            }
-            umtx_unlock(NULL);
-        }
-        if (newservice) {
-            delete newservice;
-        } else {
-            // we won the contention - we can register the cleanup.
-            ucln_i18n_registerCleanup(UCLN_I18N_CALENDAR, calendar_cleanup);
-        }
-    }
+static ICULocaleService* 
+getCalendarService(UErrorCode &status)
+{
+    umtx_initOnce(gServiceInitOnce, &initCalendarService, status);
     return gService;
 }
 
@@ -584,8 +617,7 @@ static const int32_t kCalendarLimits[UCAL_FIELD_COUNT][4] = {
 };
 
 // Resource bundle tags read by this class
-static const char gDateTimeElements[] = "DateTimeElements";
-static const char gWeekend[] = "weekend";
+static const char gMonthNames[] = "monthNames";
 
 // Data flow in Calendar
 // ---------------------
@@ -648,7 +680,9 @@ fAreFieldsVirtuallySet(FALSE),
 fNextStamp((int32_t)kMinimumUserStamp),
 fTime(0),
 fLenient(TRUE),
-fZone(0)
+fZone(0),
+fRepeatedWallTime(UCAL_WALLTIME_LAST),
+fSkippedWallTime(UCAL_WALLTIME_LAST)
 {
     clear();
     fZone = TimeZone::createDefault();
@@ -669,7 +703,9 @@ fAreFieldsVirtuallySet(FALSE),
 fNextStamp((int32_t)kMinimumUserStamp),
 fTime(0),
 fLenient(TRUE),
-fZone(0)
+fZone(0),
+fRepeatedWallTime(UCAL_WALLTIME_LAST),
+fSkippedWallTime(UCAL_WALLTIME_LAST)
 {
     if(zone == 0) {
 #if defined (U_DEBUG_CAL)
@@ -697,7 +733,9 @@ fAreFieldsVirtuallySet(FALSE),
 fNextStamp((int32_t)kMinimumUserStamp),
 fTime(0),
 fLenient(TRUE),
-fZone(0)
+fZone(0),
+fRepeatedWallTime(UCAL_WALLTIME_LAST),
+fSkippedWallTime(UCAL_WALLTIME_LAST)
 {
     clear();
     fZone = zone.clone();
@@ -738,6 +776,8 @@ Calendar::operator=(const Calendar &right)
         fAreFieldsSet            = right.fAreFieldsSet;
         fAreFieldsVirtuallySet   = right.fAreFieldsVirtuallySet;
         fLenient                 = right.fLenient;
+        fRepeatedWallTime        = right.fRepeatedWallTime;
+        fSkippedWallTime         = right.fSkippedWallTime;
         if (fZone != NULL) {
             delete fZone;
         }
@@ -751,6 +791,8 @@ Calendar::operator=(const Calendar &right)
         fWeekendCease            = right.fWeekendCease;
         fWeekendCeaseMillis      = right.fWeekendCeaseMillis;
         fNextStamp               = right.fNextStamp;
+        uprv_strcpy(validLocale, right.validLocale);
+        uprv_strcpy(actualLocale, right.actualLocale);
     }
 
     return *this;
@@ -868,6 +910,14 @@ Calendar::createInstance(TimeZone* zone, const Locale& aLocale, UErrorCode& succ
         fprintf(stderr, "%p: setting week count data to locale %s, actual locale %s\n", c, (const char*)aLocale.getName(), (const char *)actualLoc.getName());
 #endif
         c->setWeekData(aLocale, c->getType(), success);  // set the correct locale (this was an indirected calendar)
+
+        char keyword[ULOC_FULLNAME_CAPACITY];
+        UErrorCode tmpStatus = U_ZERO_ERROR;
+        l.getKeywordValue("calendar", keyword, ULOC_FULLNAME_CAPACITY, tmpStatus);
+        if (U_SUCCESS(tmpStatus) && uprv_strcmp(keyword, "iso8601") == 0) {
+            c->setFirstDayOfWeek(UCAL_MONDAY);
+            c->setMinimalDaysInFirstWeek(4);
+        }
     }
     else
 #endif /* UCONFIG_NO_SERVICE */
@@ -911,6 +961,8 @@ Calendar::isEquivalentTo(const Calendar& other) const
 {
     return typeid(*this) == typeid(other) &&
         fLenient                == other.fLenient &&
+        fRepeatedWallTime       == other.fRepeatedWallTime &&
+        fSkippedWallTime        == other.fSkippedWallTime &&
         fFirstDayOfWeek         == other.fFirstDayOfWeek &&
         fMinimalDaysInFirstWeek == other.fMinimalDaysInFirstWeek &&
         fWeekendOnset           == other.fWeekendOnset &&
@@ -1006,6 +1058,9 @@ Calendar::getTimeInMillis(UErrorCode& status) const
 
 /**
 * Sets this Calendar's current time from the given long value.
+* A status of U_ILLEGAL_ARGUMENT_ERROR is set when millis is
+* outside the range permitted by a Calendar object when not in lenient mode.
+* when in lenient mode the out of range values are pinned to their respective min/max.
 * @param date the new time in UTC milliseconds from the epoch.
 */
 void 
@@ -1014,9 +1069,19 @@ Calendar::setTimeInMillis( double millis, UErrorCode& status ) {
         return;
 
     if (millis > MAX_MILLIS) {
-        millis = MAX_MILLIS;
+        if(isLenient()) {
+            millis = MAX_MILLIS;
+        } else {
+                   status = U_ILLEGAL_ARGUMENT_ERROR;
+                   return;
+        }
     } else if (millis < MIN_MILLIS) {
-        millis = MIN_MILLIS;
+        if(isLenient()) {
+            millis = MIN_MILLIS;
+        } else {
+               status = U_ILLEGAL_ARGUMENT_ERROR;
+               return;
+        }
     }
 
     fTime = millis;
@@ -1054,6 +1119,10 @@ Calendar::set(UCalendarDateFields field, int32_t value)
         computeFields(ec);
     }
     fFields[field]     = value;
+    /* Ensure that the fNextStamp value doesn't go pass max value for int32_t */
+    if (fNextStamp == STAMP_MAX) {
+        recalculateStamp();
+    }
     fStamp[field]     = fNextStamp++;
     fIsSet[field]     = TRUE; // Remove later
     fIsTimeSet = fAreFieldsSet = fAreFieldsVirtuallySet = FALSE;
@@ -1552,6 +1621,45 @@ void Calendar::roll(UCalendarDateFields field, int32_t amount, UErrorCode& statu
 
     case UCAL_YEAR:
     case UCAL_YEAR_WOY:
+        {
+            // * If era==0 and years go backwards in time, change sign of amount.
+            // * Until we have new API per #9393, we temporarily hardcode knowledge of
+            //   which calendars have era 0 years that go backwards.
+            UBool era0WithYearsThatGoBackwards = FALSE;
+            int32_t era = get(UCAL_ERA, status);
+            if (era == 0) {
+                const char * calType = getType();
+                if ( uprv_strcmp(calType,"gregorian")==0 || uprv_strcmp(calType,"roc")==0 || uprv_strcmp(calType,"coptic")==0 ) {
+                    amount = -amount;
+                    era0WithYearsThatGoBackwards = TRUE;
+                }
+            }
+            int32_t newYear = internalGet(field) + amount;
+            if (era > 0 || newYear >= 1) {
+                int32_t maxYear = getActualMaximum(field, status);
+                if (maxYear < 32768) {
+                    // this era has real bounds, roll should wrap years
+                    if (newYear < 1) {
+                        newYear = maxYear - ((-newYear) % maxYear);
+                    } else if (newYear > maxYear) {
+                        newYear = ((newYear - 1) % maxYear) + 1;
+                    }
+                // else era is unbounded, just pin low year instead of wrapping
+                } else if (newYear < 1) {
+                    newYear = 1;
+                }
+            // else we are in era 0 with newYear < 1;
+            // calendars with years that go backwards must pin the year value at 0,
+            // other calendars can have years < 0 in era 0
+            } else if (era0WithYearsThatGoBackwards) {
+                newYear = 1;
+            }
+            set(field, newYear);
+            pinField(UCAL_MONTH,status);
+            pinField(UCAL_DAY_OF_MONTH,status);
+            return;
+        }
+
     case UCAL_EXTENDED_YEAR:
         // Rolling the year can involve pinning the DAY_OF_MONTH.
         set(field, internalGet(field) + amount);
@@ -1784,7 +1892,8 @@ void Calendar::add(UCalendarDateFields field, int32_t amount, UErrorCode& status
 
     // We handle most fields in the same way.  The algorithm is to add
     // a computed amount of millis to the current millis.  The only
-    // wrinkle is with DST -- for some fields, like the DAY_OF_MONTH,
+    // wrinkle is with DST (and/or a change to the zone's UTC offset, which
+    // we'll include with DST) -- for some fields, like the DAY_OF_MONTH,
     // we don't want the HOUR to shift due to changes in DST.  If the
     // result of the add operation is to move from DST to Standard, or
     // vice versa, we need to adjust by an hour forward or back,
@@ -1812,12 +1921,37 @@ void Calendar::add(UCalendarDateFields field, int32_t amount, UErrorCode& status
         return;
 
     case UCAL_YEAR:
-    case UCAL_EXTENDED_YEAR:
     case UCAL_YEAR_WOY:
+      {
+        // * If era=0 and years go backwards in time, change sign of amount.
+        // * Until we have new API per #9393, we temporarily hardcode knowledge of
+        //   which calendars have era 0 years that go backwards.
+        // * Note that for UCAL_YEAR (but not UCAL_YEAR_WOY) we could instead handle
+        //   this by applying the amount to the UCAL_EXTENDED_YEAR field; but since
+        //   we would still need to handle UCAL_YEAR_WOY as below, might as well
+        //   also handle UCAL_YEAR the same way.
+        int32_t era = get(UCAL_ERA, status);
+        if (era == 0) {
+          const char * calType = getType();
+          if ( uprv_strcmp(calType,"gregorian")==0 || uprv_strcmp(calType,"roc")==0 || uprv_strcmp(calType,"coptic")==0 ) {
+            amount = -amount;
+          }
+        }
+      }
+      // Fall through into normal handling
+    case UCAL_EXTENDED_YEAR:
     case UCAL_MONTH:
+      {
+        UBool oldLenient = isLenient();
+        setLenient(TRUE);
         set(field, get(field, status) + amount);
         pinField(UCAL_DAY_OF_MONTH, status);
-        return;
+        if(oldLenient==FALSE) {
+          complete(status); /* force recalculate */
+          setLenient(oldLenient);
+        }
+      }
+      return;
 
     case UCAL_WEEK_OF_YEAR:
     case UCAL_WEEK_OF_MONTH:
@@ -1870,32 +2004,41 @@ void Calendar::add(UCalendarDateFields field, int32_t amount, UErrorCode& status
     }
 
     // In order to keep the hour invariant (for fields where this is
-    // appropriate), record the DST_OFFSET before and after the add()
-    // operation.  If it has changed, then adjust the millis to
-    // compensate.
-    int32_t dst = 0;
+    // appropriate), check the combined DST & ZONE offset before and
+    // after the add() operation. If it changes, then adjust the millis
+    // to compensate.
+    int32_t prevOffset = 0;
     int32_t hour = 0;
     if (keepHourInvariant) {
-        dst = get(UCAL_DST_OFFSET, status);
+        prevOffset = get(UCAL_DST_OFFSET, status) + get(UCAL_ZONE_OFFSET, status);
         hour = internalGet(UCAL_HOUR_OF_DAY);
     }
 
     setTimeInMillis(getTimeInMillis(status) + delta, status);
 
     if (keepHourInvariant) {
-        dst -= get(UCAL_DST_OFFSET, status);
-        if (dst != 0) {
+        int32_t newOffset = get(UCAL_DST_OFFSET, status) + get(UCAL_ZONE_OFFSET, status);
+        if (newOffset != prevOffset) {
             // We have done an hour-invariant adjustment but the
-            // DST offset has altered.  We adjust millis to keep
-            // the hour constant.  In cases such as midnight after
+            // combined offset has changed. We adjust millis to keep
+            // the hour constant. In cases such as midnight after
             // a DST change which occurs at midnight, there is the
-            // danger of adjusting into a different day.  To avoid
+            // danger of adjusting into a different day. To avoid
             // this we make the adjustment only if it actually
             // maintains the hour.
-            double t = internalGetTime();
-            setTimeInMillis(t + dst, status);
-            if (get(UCAL_HOUR_OF_DAY, status) != hour) {
-                setTimeInMillis(t, status);
+
+            // When the difference of the previous UTC offset and
+            // the new UTC offset exceeds 1 full day, we do not want
+            // to roll over/back the date. For now, this only happens
+            // in Samoa (Pacific/Apia) on Dec 30, 2011. See ticket:9452.
+            int32_t adjAmount = prevOffset - newOffset;
+            adjAmount = adjAmount >= 0 ? adjAmount % (int32_t)kOneDay : -(-adjAmount % (int32_t)kOneDay);
+            if (adjAmount != 0) {
+                double t = internalGetTime();
+                setTimeInMillis(t + adjAmount, status);
+                if (get(UCAL_HOUR_OF_DAY, status) != hour) {
+                    setTimeInMillis(t, status);
+                }
             }
         }
     } 
@@ -1927,21 +2070,24 @@ int32_t Calendar::fieldDifference(UDate targetMs, UCalendarDateFields field, UEr
                 return max;
             } else if (ms > targetMs) {
                 break;
-            } else {
+            } else if (max < INT32_MAX) {
+                min = max;
                 max <<= 1;
                 if (max < 0) {
-                    // Field difference too large to fit into int32_t
+                    max = INT32_MAX;
+                }
+            } else {
+                // Field difference too large to fit into int32_t
 #if defined (U_DEBUG_CAL)
-                    fprintf(stderr, "%s:%d: ILLEGAL ARG because field %s's max too large for int32_t\n",
-                        __FILE__, __LINE__, fldName(field));
+                fprintf(stderr, "%s:%d: ILLEGAL ARG because field %s's max too large for int32_t\n",
+                    __FILE__, __LINE__, fldName(field));
 #endif
-                    ec = U_ILLEGAL_ARGUMENT_ERROR;
-                }
+                ec = U_ILLEGAL_ARGUMENT_ERROR;
             }
         }
         // Do a binary search
         while ((max - min) > 1 && U_SUCCESS(ec)) {
-            int32_t t = (min + max) / 2;
+            int32_t t = min + (max - min)/2; // make sure intermediate values don't exceed INT32_MAX
             setTimeInMillis(startMs, ec);
             add(field, t, ec);
             double ms = getTimeInMillis(ec);
@@ -1965,6 +2111,7 @@ int32_t Calendar::fieldDifference(UDate targetMs, UCalendarDateFields field, UEr
             } else if (ms < targetMs) {
                 break;
             } else {
+                min = max;
                 max <<= 1;
                 if (max == 0) {
                     // Field difference too large to fit into int32_t
@@ -1978,7 +2125,7 @@ int32_t Calendar::fieldDifference(UDate targetMs, UCalendarDateFields field, UEr
         }
         // Do a binary search
         while ((min - max) > 1 && U_SUCCESS(ec)) {
-            int32_t t = (min + max) / 2;
+            int32_t t = min + (max - min)/2; // make sure intermediate values don't exceed INT32_MAX
             setTimeInMillis(startMs, ec);
             add(field, t, ec);
             double ms = getTimeInMillis(ec);
@@ -2063,6 +2210,40 @@ Calendar::isLenient() const
 // -------------------------------------
 
 void
+Calendar::setRepeatedWallTimeOption(UCalendarWallTimeOption option)
+{
+    if (option == UCAL_WALLTIME_LAST || option == UCAL_WALLTIME_FIRST) {
+        fRepeatedWallTime = option;
+    }
+}
+
+// -------------------------------------
+
+UCalendarWallTimeOption
+Calendar::getRepeatedWallTimeOption(void) const
+{
+    return fRepeatedWallTime;
+}
+
+// -------------------------------------
+
+void
+Calendar::setSkippedWallTimeOption(UCalendarWallTimeOption option)
+{
+    fSkippedWallTime = option;
+}
+
+// -------------------------------------
+
+UCalendarWallTimeOption
+Calendar::getSkippedWallTimeOption(void) const
+{
+    return fSkippedWallTime;
+}
+
+// -------------------------------------
+
+void
 Calendar::setFirstDayOfWeek(UCalendarDaysOfWeek value)
 {
     if (fFirstDayOfWeek != value &&
@@ -2125,6 +2306,11 @@ Calendar::getDayOfWeekType(UCalendarDaysOfWeek dayOfWeek, UErrorCode &status) co
         status = U_ILLEGAL_ARGUMENT_ERROR;
         return UCAL_WEEKDAY;
     }
+       if (fWeekendOnset == fWeekendCease) {
+               if (dayOfWeek != fWeekendOnset)
+                       return UCAL_WEEKDAY;
+               return (fWeekendOnsetMillis == 0) ? UCAL_WEEKEND : UCAL_WEEKEND_ONSET;
+       }
     if (fWeekendOnset < fWeekendCease) {
         if (dayOfWeek < fWeekendOnset || dayOfWeek > fWeekendCease) {
             return UCAL_WEEKDAY;
@@ -2138,7 +2324,7 @@ Calendar::getDayOfWeekType(UCalendarDaysOfWeek dayOfWeek, UErrorCode &status) co
         return (fWeekendOnsetMillis == 0) ? UCAL_WEEKEND : UCAL_WEEKEND_ONSET;
     }
     if (dayOfWeek == fWeekendCease) {
-        return (fWeekendCeaseMillis == 0) ? UCAL_WEEKDAY : UCAL_WEEKEND_CEASE;
+        return (fWeekendCeaseMillis >= 86400000) ? UCAL_WEEKEND : UCAL_WEEKEND_CEASE;
     }
     return UCAL_WEEKEND;
 }
@@ -2369,7 +2555,7 @@ Calendar::getActualMinimum(UCalendarDateFields field, UErrorCode& status) const
 */
 void Calendar::validateFields(UErrorCode &status) {
     for (int32_t field = 0; U_SUCCESS(status) && (field < UCAL_FIELD_COUNT); field++) {
-        if (isSet((UCalendarDateFields)field)) {
+        if (fStamp[field] >= kMinimumUserStamp) {
             validateField((UCalendarDateFields)field, status);
         }
     }
@@ -2447,12 +2633,14 @@ UCalendarDateFields Calendar::newerField(UCalendarDateFields defaultField, UCale
 
 UCalendarDateFields Calendar::resolveFields(const UFieldResolutionTable* precedenceTable) {
     int32_t bestField = UCAL_FIELD_COUNT;
+    int32_t tempBestField;
     for (int32_t g=0; precedenceTable[g][0][0] != -1 && (bestField == UCAL_FIELD_COUNT); ++g) {
         int32_t bestStamp = kUnset;
         for (int32_t l=0; precedenceTable[g][l][0] != -1; ++l) {
             int32_t lineStamp = kUnset;
             // Skip over first entry if it is negative
             for (int32_t i=((precedenceTable[g][l][0]>=kResolveRemap)?1:0); precedenceTable[g][l][i]!=-1; ++i) {
+                U_ASSERT(precedenceTable[g][l][i] < UCAL_FIELD_COUNT);
                 int32_t s = fStamp[precedenceTable[g][l][i]];
                 // If any field is unset then don't use this line
                 if (s == kUnset) {
@@ -2463,14 +2651,26 @@ UCalendarDateFields Calendar::resolveFields(const UFieldResolutionTable* precede
             }
             // Record new maximum stamp & field no.
             if (lineStamp > bestStamp) {
-                bestStamp = lineStamp;
-                bestField = precedenceTable[g][l][0]; // First field refers to entire line
+                tempBestField = precedenceTable[g][l][0]; // First field refers to entire line
+                if (tempBestField >= kResolveRemap) {
+                    tempBestField &= (kResolveRemap-1);
+                    // This check is needed to resolve some issues with UCAL_YEAR precedence mapping
+                    if (tempBestField != UCAL_DATE || (fStamp[UCAL_WEEK_OF_MONTH] < fStamp[tempBestField])) {
+                        bestField = tempBestField;
+                    }
+                } else {
+                    bestField = tempBestField;
+                }
+
+                if (bestField == tempBestField) {
+                    bestStamp = lineStamp;
+                }
             }
 linesInGroup:
             ;
         }
     }
-    return (UCalendarDateFields)( (bestField>=kResolveRemap)?(bestField&(kResolveRemap-1)):bestField  );
+    return (UCalendarDateFields)bestField;
 }
 
 const UFieldResolutionTable Calendar::kDatePrecedence[] =
@@ -2556,33 +2756,97 @@ void Calendar::computeTime(UErrorCode& status) {
     // is legacy behavior.  Without this, clear(MONTH) has no effect,
     // since the internally set JULIAN_DAY is used.
     if (fStamp[UCAL_MILLISECONDS_IN_DAY] >= ((int32_t)kMinimumUserStamp) &&
-        newestStamp(UCAL_AM_PM, UCAL_MILLISECOND, kUnset) <= fStamp[UCAL_MILLISECONDS_IN_DAY]) {
-            millisInDay = internalGet(UCAL_MILLISECONDS_IN_DAY);
-        } else {
-            millisInDay = computeMillisInDay();
-        }
+            newestStamp(UCAL_AM_PM, UCAL_MILLISECOND, kUnset) <= fStamp[UCAL_MILLISECONDS_IN_DAY]) {
+        millisInDay = internalGet(UCAL_MILLISECONDS_IN_DAY);
+    } else {
+        millisInDay = computeMillisInDay();
+    }
 
+    UDate t = 0;
+    if (fStamp[UCAL_ZONE_OFFSET] >= ((int32_t)kMinimumUserStamp) || fStamp[UCAL_DST_OFFSET] >= ((int32_t)kMinimumUserStamp)) {
+        t = millis + millisInDay - (internalGet(UCAL_ZONE_OFFSET) + internalGet(UCAL_DST_OFFSET));
+    } else {
         // Compute the time zone offset and DST offset.  There are two potential
         // ambiguities here.  We'll assume a 2:00 am (wall time) switchover time
         // for discussion purposes here.
-        // 1. The transition into DST.  Here, a designated time of 2:00 am - 2:59 am
-        //    can be in standard or in DST depending.  However, 2:00 am is an invalid
-        //    representation (the representation jumps from 1:59:59 am Std to 3:00:00 am DST).
-        //    We assume standard time, that is, 2:30 am is interpreted as 3:30 am DST.
-        // 2. The transition out of DST.  Here, a designated time of 1:00 am - 1:59 am
-        //    can be in standard or DST.  Both are valid representations (the rep
-        //    jumps from 1:59:59 DST to 1:00:00 Std).
-        //    Again, we assume standard time, that is, 1:30 am is interpreted as 1:30 am Std.
+        //
+        // 1. The positive offset change such as transition into DST.
+        //    Here, a designated time of 2:00 am - 2:59 am does not actually exist.
+        //    For this case, skippedWallTime option specifies the behavior.
+        //    For example, 2:30 am is interpreted as;
+        //      - WALLTIME_LAST(default): 3:30 am (DST) (interpreting 2:30 am as 31 minutes after 1:59 am (STD))
+        //      - WALLTIME_FIRST: 1:30 am (STD) (interpreting 2:30 am as 30 minutes before 3:00 am (DST))
+        //      - WALLTIME_NEXT_VALID: 3:00 am (DST) (next valid time after 2:30 am on a wall clock)
+        // 2. The negative offset change such as transition out of DST.
+        //    Here, a designated time of 1:00 am - 1:59 am can be in standard or DST.  Both are valid
+        //    representations (the rep jumps from 1:59:59 DST to 1:00:00 Std).
+        //    For this case, repeatedWallTime option specifies the behavior.
+        //    For example, 1:30 am is interpreted as;
+        //      - WALLTIME_LAST(default): 1:30 am (STD) - latter occurrence
+        //      - WALLTIME_FIRST: 1:30 am (DST) - former occurrence
+        //
+        // In addition to above, when calendar is strict (not default), wall time falls into
+        // the skipped time range will be processed as an error case.
+        //
+        // These special cases are mostly handled in #computeZoneOffset(long), except WALLTIME_NEXT_VALID
+        // at positive offset change. The protected method computeZoneOffset(long) is exposed to Calendar
+        // subclass implementations and marked as @stable. Strictly speaking, WALLTIME_NEXT_VALID
+        // should be also handled in the same place, but we cannot change the code flow without deprecating
+        // the protected method.
+        //
         // We use the TimeZone object, unless the user has explicitly set the ZONE_OFFSET
         // or DST_OFFSET fields; then we use those fields.
-        if (fStamp[UCAL_ZONE_OFFSET] >= ((int32_t)kMinimumUserStamp) ||
-            fStamp[UCAL_DST_OFFSET] >= ((int32_t)kMinimumUserStamp)) {
-                millisInDay -= internalGet(UCAL_ZONE_OFFSET) + internalGet(UCAL_DST_OFFSET);
-            } else {
-                millisInDay -= computeZoneOffset(millis, millisInDay,status);
-            }
 
-            internalSetTime(millis + millisInDay);
+        if (!isLenient() || fSkippedWallTime == UCAL_WALLTIME_NEXT_VALID) {
+            // When strict, invalidate a wall time falls into a skipped wall time range.
+            // When lenient and skipped wall time option is WALLTIME_NEXT_VALID,
+            // the result time will be adjusted to the next valid time (on wall clock).
+            int32_t zoneOffset = computeZoneOffset(millis, millisInDay, status);
+            UDate tmpTime = millis + millisInDay - zoneOffset;
+
+            int32_t raw, dst;
+            fZone->getOffset(tmpTime, FALSE, raw, dst, status);
+
+            if (U_SUCCESS(status)) {
+                // zoneOffset != (raw + dst) only when the given wall time fall into
+                // a skipped wall time range caused by positive zone offset transition.
+                if (zoneOffset != (raw + dst)) {
+                    if (!isLenient()) {
+                        status = U_ILLEGAL_ARGUMENT_ERROR;
+                    } else {
+                        U_ASSERT(fSkippedWallTime == UCAL_WALLTIME_NEXT_VALID);
+                        // Adjust time to the next valid wall clock time.
+                        // At this point, tmpTime is on or after the zone offset transition causing
+                        // the skipped time range.
+
+                        BasicTimeZone *btz = getBasicTimeZone();
+                        if (btz) {
+                            TimeZoneTransition transition;
+                            UBool hasTransition = btz->getPreviousTransition(tmpTime, TRUE, transition);
+                            if (hasTransition) {
+                                t = transition.getTime();
+                            } else {
+                                // Could not find any transitions.
+                                // Note: This should never happen.
+                                status = U_INTERNAL_PROGRAM_ERROR;
+                            }
+                        } else {
+                            // If not BasicTimeZone, return unsupported error for now.
+                            // TODO: We may support non-BasicTimeZone in future.
+                            status = U_UNSUPPORTED_ERROR;
+                        }
+                    }
+                } else {
+                    t = tmpTime;
+                }
+            }
+        } else {
+            t = millis + millisInDay - computeZoneOffset(millis, millisInDay, status);
+        }
+    }
+    if (U_SUCCESS(status)) {
+        internalSetTime(t);
+    }
 }
 
 /**
@@ -2639,12 +2903,49 @@ int32_t Calendar::computeMillisInDay() {
 */
 int32_t Calendar::computeZoneOffset(double millis, int32_t millisInDay, UErrorCode &ec) {
     int32_t rawOffset, dstOffset;
-    getTimeZone().getOffset(millis+millisInDay, TRUE, rawOffset, dstOffset, ec);
+    UDate wall = millis + millisInDay;
+    BasicTimeZone* btz = getBasicTimeZone();
+    if (btz) {
+        int duplicatedTimeOpt = (fRepeatedWallTime == UCAL_WALLTIME_FIRST) ? BasicTimeZone::kFormer : BasicTimeZone::kLatter;
+        int nonExistingTimeOpt = (fSkippedWallTime == UCAL_WALLTIME_FIRST) ? BasicTimeZone::kLatter : BasicTimeZone::kFormer;
+        btz->getOffsetFromLocal(wall, nonExistingTimeOpt, duplicatedTimeOpt, rawOffset, dstOffset, ec);
+    } else {
+        const TimeZone& tz = getTimeZone();
+        // By default, TimeZone::getOffset behaves UCAL_WALLTIME_LAST for both.
+        tz.getOffset(wall, TRUE, rawOffset, dstOffset, ec);
+
+        UBool sawRecentNegativeShift = FALSE;
+        if (fRepeatedWallTime == UCAL_WALLTIME_FIRST) {
+            // Check if the given wall time falls into repeated time range
+            UDate tgmt = wall - (rawOffset + dstOffset);
+
+            // Any negative zone transition within last 6 hours?
+            // Note: The maximum historic negative zone transition is -3 hours in the tz database.
+            // 6 hour window would be sufficient for this purpose.
+            int32_t tmpRaw, tmpDst;
+            tz.getOffset(tgmt - 6*60*60*1000, FALSE, tmpRaw, tmpDst, ec);
+            int32_t offsetDelta = (rawOffset + dstOffset) - (tmpRaw + tmpDst);
+
+            U_ASSERT(offsetDelta < -6*60*60*1000);
+            if (offsetDelta < 0) {
+                sawRecentNegativeShift = TRUE;
+                // Negative shift within last 6 hours. When UCAL_WALLTIME_FIRST is used and the given wall time falls
+                // into the repeated time range, use offsets before the transition.
+                // Note: If it does not fall into the repeated time range, offsets remain unchanged below.
+                tz.getOffset(wall + offsetDelta, TRUE, rawOffset, dstOffset, ec);
+            }
+        }
+        if (!sawRecentNegativeShift && fSkippedWallTime == UCAL_WALLTIME_FIRST) {
+            // When skipped wall time option is WALLTIME_FIRST,
+            // recalculate offsets from the resolved time (non-wall).
+            // When the given wall time falls into skipped wall time,
+            // the offsets will be based on the zone offsets AFTER
+            // the transition (which means, earliest possibe interpretation).
+            UDate tgmt = wall - (rawOffset + dstOffset);
+            tz.getOffset(tgmt, FALSE, rawOffset, dstOffset, ec);
+        }
+    }
     return rawOffset + dstOffset;
-    // Note: Because we pass in wall millisInDay, rather than
-    // standard millisInDay, we interpret "1:00 am" on the day
-    // of cessation of DST as "1:00 am Std" (assuming the time
-    // of cessation is 2:00 am).
 }
 
 int32_t Calendar::computeJulianDay() 
@@ -2989,7 +3290,6 @@ int32_t Calendar::handleGetExtendedYearFromWeekFields(int32_t yearWoy, int32_t w
             // we're not possibly in the last week -must be ywoy
             return yearWoy;
         }
-        break;
 
     case UCAL_DATE:
         if((internalGet(UCAL_MONTH)==0) &&
@@ -3009,18 +3309,10 @@ int32_t Calendar::handleGetExtendedYearFromWeekFields(int32_t yearWoy, int32_t w
             //within 1st week and in this month.. 
             //return yearWoy+1;
             return yearWoy;
-            break;
 
     default: // assume the year is appropriate
         return yearWoy;
-        break;
     }
-
-#if defined (U_DEBUG_CAL) 
-    fprintf(stderr, "%s:%d - forgot a return on field %s\n", __FILE__, __LINE__, fldName(bestField));
-#endif 
-
-    return yearWoy;
 }
 
 int32_t Calendar::handleGetMonthLength(int32_t extendedYear, int32_t month) const
@@ -3044,6 +3336,7 @@ Calendar::getActualMaximum(UCalendarDateFields field, UErrorCode& status) const
             if(U_FAILURE(status)) return 0;
             Calendar *cal = clone();
             if(!cal) { status = U_MEMORY_ALLOCATION_ERROR; return 0; }
+            cal->setLenient(TRUE);
             cal->prepareGetActual(field,FALSE,status);
             result = handleGetMonthLength(cal->get(UCAL_EXTENDED_YEAR, status), cal->get(UCAL_MONTH, status));
             delete cal;
@@ -3055,6 +3348,7 @@ Calendar::getActualMaximum(UCalendarDateFields field, UErrorCode& status) const
             if(U_FAILURE(status)) return 0;
             Calendar *cal = clone();
             if(!cal) { status = U_MEMORY_ALLOCATION_ERROR; return 0; }
+            cal->setLenient(TRUE);
             cal->prepareGetActual(field,FALSE,status);
             result = handleGetYearLength(cal->get(UCAL_EXTENDED_YEAR, status));
             delete cal;
@@ -3176,6 +3470,11 @@ int32_t Calendar::getActualHelper(UCalendarDateFields field, int32_t startValue,
     if(U_FAILURE(status)) return startValue;
     Calendar *work = clone();
     if(!work) { status = U_MEMORY_ALLOCATION_ERROR; return startValue; }
+
+    // need to resolve time here, otherwise, fields set for actual limit
+    // may cause conflict with fields previously set (but not yet resolved).
+    work->complete(status);
+
     work->setLenient(TRUE);
     work->prepareGetActual(field, delta < 0, status);
 
@@ -3223,15 +3522,6 @@ int32_t Calendar::getActualHelper(UCalendarDateFields field, int32_t startValue,
 void
 Calendar::setWeekData(const Locale& desiredLocale, const char *type, UErrorCode& status)
 {
-    // Read the week count data from the resource bundle.  This should
-    // have the form:
-    //
-    //   DateTimeElements:intvector {
-    //      1,    // first day of week
-    //      1     // min days in week
-    //   }
-    //   Both have a range of 1..7
-
 
     if (U_FAILURE(status)) return;
 
@@ -3257,7 +3547,7 @@ Calendar::setWeekData(const Locale& desiredLocale, const char *type, UErrorCode&
     Locale min = Locale::createFromName(minLocaleID);
     Locale useLocale;
     if ( uprv_strlen(desiredLocale.getCountry()) == 0 || 
-         uprv_strlen(desiredLocale.getScript()) > 0 && uprv_strlen(min.getScript()) == 0 ) {
+         (uprv_strlen(desiredLocale.getScript()) > 0 && uprv_strlen(min.getScript()) == 0) ) {
         char maxLocaleID[ULOC_FULLNAME_CAPACITY] = { 0 };
         myStatus = U_ZERO_ERROR;
         uloc_addLikelySubtags(desiredLocale.getName(),maxLocaleID,ULOC_FULLNAME_CAPACITY,&myStatus);
@@ -3267,62 +3557,58 @@ Calendar::setWeekData(const Locale& desiredLocale, const char *type, UErrorCode&
         useLocale = Locale(desiredLocale);
     }
  
-    CalendarData calData(useLocale, type, status);
-    // If the resource data doesn't seem to be present at all, then use last-resort
-    // hard-coded data.
-    UResourceBundle *dateTimeElements = calData.getByKey(gDateTimeElements, status);
+    /* The code here is somewhat of a hack, since week data and weekend data aren't really tied to 
+       a specific calendar, they aren't truly locale data.  But this is the only place where valid and
+       actual locale can be set, so we take a shot at it here by loading a representative resource
+       from the calendar data.  The code used to use the dateTimeElements resource to get first day
+       of week data, but this was moved to supplemental data under ticket 7755. (JCE) */
+
+    CalendarData calData(useLocale,type,status);
+    UResourceBundle *monthNames = calData.getByKey(gMonthNames,status);
+    if (U_SUCCESS(status)) {
+        U_LOCALE_BASED(locBased,*this);
+        locBased.setLocaleIDs(ures_getLocaleByType(monthNames, ULOC_VALID_LOCALE, &status),
+                              ures_getLocaleByType(monthNames, ULOC_ACTUAL_LOCALE, &status));
+    } else {
+        status = U_USING_FALLBACK_WARNING;
+        return;
+    }
+
+    
+    // Read week data values from supplementalData week data
+    UResourceBundle *rb = ures_openDirect(NULL, "supplementalData", &status);
+    ures_getByKey(rb, "weekData", rb, &status);
+    UResourceBundle *weekData = ures_getByKey(rb, useLocale.getCountry(), NULL, &status);
+    if (status == U_MISSING_RESOURCE_ERROR && rb != NULL) {
+        status = U_ZERO_ERROR;
+        weekData = ures_getByKey(rb, "001", NULL, &status);
+    }
 
     if (U_FAILURE(status)) {
 #if defined (U_DEBUG_CALDATA)
-        fprintf(stderr, " Failure loading dateTimeElements = %s\n", u_errorName(status));
+        fprintf(stderr, " Failure loading weekData from supplemental = %s\n", u_errorName(status));
 #endif
         status = U_USING_FALLBACK_WARNING;
     } else {
-        U_LOCALE_BASED(locBased, *this);
-        locBased.setLocaleIDs(ures_getLocaleByType(dateTimeElements, ULOC_VALID_LOCALE, &status),
-            ures_getLocaleByType(dateTimeElements, ULOC_ACTUAL_LOCALE, &status));
-        if (U_SUCCESS(status)) {
-#if defined (U_DEBUG_CAL)
-            fprintf(stderr, " Valid=%s, Actual=%s\n", validLocale, actualLocale);
-#endif
-            int32_t arrLen;
-            const int32_t *dateTimeElementsArr = ures_getIntVector(dateTimeElements, &arrLen, &status);
-    
-            if(U_SUCCESS(status) && arrLen == 2
-                && 1 <= dateTimeElementsArr[0] && dateTimeElementsArr[0] <= 7
-                && 1 <= dateTimeElementsArr[1] && dateTimeElementsArr[1] <= 7)
-            {
-                fFirstDayOfWeek = (UCalendarDaysOfWeek)dateTimeElementsArr[0];
-                fMinimalDaysInFirstWeek = (uint8_t)dateTimeElementsArr[1];
-            }
-            else {
-                status = U_INVALID_FORMAT_ERROR;
-            }
-        }
-    }
-    // do NOT close dateTimeElements
-    
-    if (U_SUCCESS(status)) {
-        UResourceBundle *weekend = calData.getByKey(gWeekend, status);
-        if (U_FAILURE(status)) {
-            status = U_USING_FALLBACK_WARNING;
+        int32_t arrLen;
+        const int32_t *weekDataArr = ures_getIntVector(weekData,&arrLen,&status);
+        if( U_SUCCESS(status) && arrLen == 6
+                && 1 <= weekDataArr[0] && weekDataArr[0] <= 7
+                && 1 <= weekDataArr[1] && weekDataArr[1] <= 7
+                && 1 <= weekDataArr[2] && weekDataArr[2] <= 7
+                && 1 <= weekDataArr[4] && weekDataArr[4] <= 7) {
+            fFirstDayOfWeek = (UCalendarDaysOfWeek)weekDataArr[0];
+            fMinimalDaysInFirstWeek = (uint8_t)weekDataArr[1];
+            fWeekendOnset = (UCalendarDaysOfWeek)weekDataArr[2];
+            fWeekendOnsetMillis = weekDataArr[3];
+            fWeekendCease = (UCalendarDaysOfWeek)weekDataArr[4];
+            fWeekendCeaseMillis = weekDataArr[5];
         } else {
-            int32_t arrLen;
-            const int32_t *weekendArr = ures_getIntVector(weekend, &arrLen, &status);
-            if(U_SUCCESS(status) && arrLen >= 4
-                && 1 <= weekendArr[0] && weekendArr[0] <= 7
-                && 1 <= weekendArr[2] && weekendArr[2] <= 7)
-            {
-                fWeekendOnset = (UCalendarDaysOfWeek)weekendArr[0];
-                fWeekendOnsetMillis = weekendArr[1];
-                fWeekendCease = (UCalendarDaysOfWeek)weekendArr[2];
-                fWeekendCeaseMillis = weekendArr[3];
-            }
-            else {
-                status = U_INVALID_FORMAT_ERROR;
-            }
+            status = U_INVALID_FORMAT_ERROR;
         }
     }
+    ures_close(weekData);
+    ures_close(rb);
 }
 
 /**
@@ -3359,6 +3645,33 @@ Calendar::getLocaleID(ULocDataLocaleType type, UErrorCode& status) const {
     return locBased.getLocaleID(type, status);
 }
 
+void
+Calendar::recalculateStamp() {
+    int32_t index;
+    int32_t currentValue;
+    int32_t j, i;
+
+    fNextStamp = 1;
+
+    for (j = 0; j < UCAL_FIELD_COUNT; j++) {
+        currentValue = STAMP_MAX;
+        index = -1;
+        for (i = 0; i < UCAL_FIELD_COUNT; i++) {
+            if (fStamp[i] > fNextStamp && fStamp[i] < currentValue) {
+                currentValue = fStamp[i];
+                index = i;
+            }
+        }
+
+        if (index >= 0) {
+            fStamp[index] = ++fNextStamp;
+        } else {
+            break;
+        }
+    }
+    fNextStamp++;
+}
+
 // Deprecated function. This doesn't need to be inline.
 void
 Calendar::internalSet(EDateFields field, int32_t value)
@@ -3366,9 +3679,21 @@ Calendar::internalSet(EDateFields field, int32_t value)
     internalSet((UCalendarDateFields) field, value);
 }
 
+BasicTimeZone*
+Calendar::getBasicTimeZone(void) const {
+    if (dynamic_cast<const OlsonTimeZone *>(fZone) != NULL
+        || dynamic_cast<const SimpleTimeZone *>(fZone) != NULL
+        || dynamic_cast<const RuleBasedTimeZone *>(fZone) != NULL
+        || dynamic_cast<const VTimeZone *>(fZone) != NULL) {
+        return (BasicTimeZone*)fZone;
+    }
+    return NULL;
+}
+
 U_NAMESPACE_END
 
 #endif /* #if !UCONFIG_NO_FORMATTING */
 
 
 //eof
+