]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/i18n/smpdtfmt.cpp
ICU-491.11.2.tar.gz
[apple/icu.git] / icuSources / i18n / smpdtfmt.cpp
index 8dde9ac16a94832b44ede63ec0fe888a556e3171..3d3c37a564f710cfca6db635fbd27ab673ddb25b 100644 (file)
@@ -1,6 +1,6 @@
 /*
 *******************************************************************************
-* Copyright (C) 1997-2010, International Business Machines Corporation and    *
+* Copyright (C) 1997-2012, International Business Machines Corporation and    *
 * others. All Rights Reserved.                                                *
 *******************************************************************************
 *
 #include "unicode/basictz.h"
 #include "unicode/simpletz.h"
 #include "unicode/rbtz.h"
+#include "unicode/tzfmt.h"
+#include "unicode/utf16.h"
 #include "unicode/vtzone.h"
 #include "olsontz.h"
-#include "util.h"
+#include "patternprops.h"
 #include "fphdlimp.h"
 #include "gregoimp.h"
 #include "hebrwcal.h"
 #include "cstring.h"
 #include "uassert.h"
-#include "zstrfmt.h"
 #include "cmemory.h"
 #include "umutex.h"
-#include "smpdtfst.h"
 #include <float.h>
+#include "smpdtfst.h"
 
 #if defined( U_DEBUG_CALSVC ) || defined (U_DEBUG_CAL)
 #include <stdio.h>
@@ -121,8 +122,9 @@ static const UDateFormatField kDateFields[] = {
     UDAT_STANDALONE_DAY_FIELD,
     UDAT_STANDALONE_MONTH_FIELD,
     UDAT_QUARTER_FIELD,
-    UDAT_STANDALONE_QUARTER_FIELD };
-static const int8_t kDateFieldsCount = 13;
+    UDAT_STANDALONE_QUARTER_FIELD,
+    UDAT_YEAR_NAME_FIELD };
+static const int8_t kDateFieldsCount = 15;
 
 static const UDateFormatField kTimeFields[] = {
     UDAT_HOUR_OF_DAY1_FIELD,
@@ -175,7 +177,7 @@ static const int32_t gFieldRangeBias[] = {
     -1,  // 'k' - UDAT_HOUR_OF_DAY1_FIELD
     -1,  // 'H' - UDAT_HOUR_OF_DAY0_FIELD
      0,  // 'm' - UDAT_MINUTE_FIELD
-     0,  // 's' - UDAT_SEOND_FIELD
+     0,  // 's' - UDAT_SECOND_FIELD
     -1,  // 'S' - UDAT_FRACTIONAL_SECOND_FIELD (0-999?)
     -1,  // 'E' - UDAT_DAY_OF_WEEK_FIELD (1-7?)
     -1,  // 'D' - UDAT_DAY_OF_YEAR_FIELD (1 - 366?)
@@ -197,7 +199,42 @@ static const int32_t gFieldRangeBias[] = {
      1,  // 'L' - UDAT_STANDALONE_MONTH_FIELD
     -1,  // 'Q' - UDAT_QUARTER_FIELD (1-4?)
     -1,  // 'q' - UDAT_STANDALONE_QUARTER_FIELD
-    -1   // 'V' - UDAT_TIMEZONE_SPECIAL_FIELD
+    -1,  // 'V' - UDAT_TIMEZONE_SPECIAL_FIELD
+    -1   // 'U' - UDAT_YEAR_NAME_FIELD
+};
+// A slightly looser range check for lenient parsing
+static const int32_t gFieldRangeBiasLenient[] = {
+    -1,  // 'G' - UDAT_ERA_FIELD
+    -1,  // 'y' - UDAT_YEAR_FIELD
+     8,  // 'M' - UDAT_MONTH_FIELD (allow calendar max + 7, e.g. 19 for grego 1-based month)
+    18,  // 'd' - UDAT_DATE_FIELD (allow calendar max + 18, e.g. 49 for grego; tests require at least 40 for grego)
+    -1,  // 'k' - UDAT_HOUR_OF_DAY1_FIELD
+    -1,  // 'H' - UDAT_HOUR_OF_DAY0_FIELD
+    40,  // 'm' - UDAT_MINUTE_FIELD (allow calendar max + 40, e.g. 99)
+    40,  // 's' - UDAT_SECOND_FIELD (allow calendar max + 40, e.g. 99)
+    -1,  // 'S' - UDAT_FRACTIONAL_SECOND_FIELD (0-999?)
+    -1,  // 'E' - UDAT_DAY_OF_WEEK_FIELD (1-7?)
+    -1,  // 'D' - UDAT_DAY_OF_YEAR_FIELD (1 - 366?)
+    -1,  // 'F' - UDAT_DAY_OF_WEEK_IN_MONTH_FIELD (1-5?)
+    -1,  // 'w' - UDAT_WEEK_OF_YEAR_FIELD (1-52?)
+    -1,  // 'W' - UDAT_WEEK_OF_MONTH_FIELD (1-5?)
+    -1,  // 'a' - UDAT_AM_PM_FIELD
+    -1,  // 'h' - UDAT_HOUR1_FIELD
+    -1,  // 'K' - UDAT_HOUR0_FIELD
+    -1,  // 'z' - UDAT_TIMEZONE_FIELD
+    -1,  // 'Y' - UDAT_YEAR_WOY_FIELD
+    -1,  // 'e' - UDAT_DOW_LOCAL_FIELD
+    -1,  // 'u' - UDAT_EXTENDED_YEAR_FIELD
+    -1,  // 'g' - UDAT_JULIAN_DAY_FIELD
+    -1,  // 'A' - UDAT_MILLISECONDS_IN_DAY_FIELD
+    -1,  // 'Z' - UDAT_TIMEZONE_RFC_FIELD
+    -1,  // 'v' - UDAT_TIMEZONE_GENERIC_FIELD
+    18,  // 'c' - UDAT_STANDALONE_DAY_FIELD (allow calendar max + 18, e.g. 49 for grego)
+     8,  // 'L' - UDAT_STANDALONE_MONTH_FIELD (allow calendar max + 7, e.g. 19 for grego 1-based month)
+    -1,  // 'Q' - UDAT_QUARTER_FIELD (1-4?)
+    -1,  // 'q' - UDAT_STANDALONE_QUARTER_FIELD
+    -1,  // 'V' - UDAT_TIMEZONE_SPECIAL_FIELD
+    -1   // 'U' - UDAT_YEAR_NAME_FIELD
 };
 
 static UMTX LOCK;
@@ -209,18 +246,12 @@ UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SimpleDateFormat)
 SimpleDateFormat::~SimpleDateFormat()
 {
     delete fSymbols;
-    if (fGMTFormatters) {
-        for (int32_t i = 0; i < kNumGMTFormatters; i++) {
-            if (fGMTFormatters[i]) {
-                delete fGMTFormatters[i];
-            }
-        }
-        uprv_free(fGMTFormatters);
-
-    }
     if (fNumberFormatters) {
         uprv_free(fNumberFormatters);
     }
+    if (fTimeZoneFormat) {
+        delete fTimeZoneFormat;
+    }
 
     while (fOverrideList) {
         NSOverride *cur = fOverrideList;
@@ -235,9 +266,10 @@ SimpleDateFormat::~SimpleDateFormat()
 SimpleDateFormat::SimpleDateFormat(UErrorCode& status)
   :   fLocale(Locale::getDefault()),
       fSymbols(NULL),
-      fGMTFormatters(NULL),
+      fTimeZoneFormat(NULL),
       fNumberFormatters(NULL),
-      fOverrideList(NULL)
+      fOverrideList(NULL),
+      fDefaultCapitalizationContext(UDAT_CONTEXT_UNKNOWN)
 {
     construct(kShort, (EStyle) (kShort + kDateOffset), fLocale, status);
     initializeDefaultCentury();
@@ -250,9 +282,10 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
 :   fPattern(pattern),
     fLocale(Locale::getDefault()),
     fSymbols(NULL),
-    fGMTFormatters(NULL),
+    fTimeZoneFormat(NULL),
     fNumberFormatters(NULL),
-    fOverrideList(NULL)
+    fOverrideList(NULL),
+    fDefaultCapitalizationContext(UDAT_CONTEXT_UNKNOWN)
 {
     fDateOverride.setToBogus();
     fTimeOverride.setToBogus();
@@ -269,9 +302,10 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
 :   fPattern(pattern),
     fLocale(Locale::getDefault()),
     fSymbols(NULL),
-    fGMTFormatters(NULL),
+    fTimeZoneFormat(NULL),
     fNumberFormatters(NULL),
-    fOverrideList(NULL)
+    fOverrideList(NULL),
+    fDefaultCapitalizationContext(UDAT_CONTEXT_UNKNOWN)
 {
     fDateOverride.setTo(override);
     fTimeOverride.setToBogus();
@@ -290,9 +324,10 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
                                    UErrorCode& status)
 :   fPattern(pattern),
     fLocale(locale),
-    fGMTFormatters(NULL),
+    fTimeZoneFormat(NULL),
     fNumberFormatters(NULL),
-    fOverrideList(NULL)
+    fOverrideList(NULL),
+    fDefaultCapitalizationContext(UDAT_CONTEXT_UNKNOWN)
 {
 
     fDateOverride.setToBogus();
@@ -311,9 +346,10 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
                                    UErrorCode& status)
 :   fPattern(pattern),
     fLocale(locale),
-    fGMTFormatters(NULL),
+    fTimeZoneFormat(NULL),
     fNumberFormatters(NULL),
-    fOverrideList(NULL)
+    fOverrideList(NULL),
+    fDefaultCapitalizationContext(UDAT_CONTEXT_UNKNOWN)
 {
 
     fDateOverride.setTo(override);
@@ -335,9 +371,10 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
 :   fPattern(pattern),
     fLocale(Locale::getDefault()),
     fSymbols(symbolsToAdopt),
-    fGMTFormatters(NULL),
+    fTimeZoneFormat(NULL),
     fNumberFormatters(NULL),
-    fOverrideList(NULL)
+    fOverrideList(NULL),
+    fDefaultCapitalizationContext(UDAT_CONTEXT_UNKNOWN)
 {
 
     fDateOverride.setToBogus();
@@ -356,9 +393,10 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
 :   fPattern(pattern),
     fLocale(Locale::getDefault()),
     fSymbols(new DateFormatSymbols(symbols)),
-    fGMTFormatters(NULL),
+    fTimeZoneFormat(NULL),
     fNumberFormatters(NULL),
-    fOverrideList(NULL)
+    fOverrideList(NULL),
+    fDefaultCapitalizationContext(UDAT_CONTEXT_UNKNOWN)
 {
 
     fDateOverride.setToBogus();
@@ -378,9 +416,10 @@ SimpleDateFormat::SimpleDateFormat(EStyle timeStyle,
                                    UErrorCode& status)
 :   fLocale(locale),
     fSymbols(NULL),
-    fGMTFormatters(NULL),
+    fTimeZoneFormat(NULL),
     fNumberFormatters(NULL),
-    fOverrideList(NULL)
+    fOverrideList(NULL),
+    fDefaultCapitalizationContext(UDAT_CONTEXT_UNKNOWN)
 {
     construct(timeStyle, dateStyle, fLocale, status);
     if(U_SUCCESS(status)) {
@@ -400,9 +439,10 @@ SimpleDateFormat::SimpleDateFormat(const Locale& locale,
 :   fPattern(gDefaultPattern),
     fLocale(locale),
     fSymbols(NULL),
-    fGMTFormatters(NULL),
+    fTimeZoneFormat(NULL),
     fNumberFormatters(NULL),
-    fOverrideList(NULL)
+    fOverrideList(NULL),
+    fDefaultCapitalizationContext(UDAT_CONTEXT_UNKNOWN)
 {
     if (U_FAILURE(status)) return;
     initializeSymbols(fLocale, initializeCalendar(NULL, fLocale, status),status);
@@ -432,10 +472,12 @@ SimpleDateFormat::SimpleDateFormat(const Locale& locale,
 
 SimpleDateFormat::SimpleDateFormat(const SimpleDateFormat& other)
 :   DateFormat(other),
+    fLocale(other.fLocale),
     fSymbols(NULL),
-    fGMTFormatters(NULL),
+    fTimeZoneFormat(NULL),
     fNumberFormatters(NULL),
-    fOverrideList(NULL)
+    fOverrideList(NULL),
+    fDefaultCapitalizationContext(UDAT_CONTEXT_UNKNOWN)
 {
     *this = other;
 }
@@ -461,6 +503,15 @@ SimpleDateFormat& SimpleDateFormat::operator=(const SimpleDateFormat& other)
 
     fPattern = other.fPattern;
 
+    // TimeZoneFormat in ICU4C only depends on a locale for now
+    if (fLocale != other.fLocale) {
+        delete fTimeZoneFormat;
+        fTimeZoneFormat = NULL; // forces lazy instantiation with the other locale
+        fLocale = other.fLocale;
+    }
+
+    fDefaultCapitalizationContext = other.fDefaultCapitalizationContext;
+
     return *this;
 }
 
@@ -485,7 +536,8 @@ SimpleDateFormat::operator==(const Format& other) const
                 that->fSymbols       != NULL && // Check for pathological object
                 *fSymbols            == *that->fSymbols &&
                 fHaveDefaultCentury  == that->fHaveDefaultCentury &&
-                fDefaultCenturyStart == that->fDefaultCenturyStart);
+                fDefaultCenturyStart == that->fDefaultCenturyStart &&
+                fDefaultCapitalizationContext == that->fDefaultCapitalizationContext);
     }
     return FALSE;
 }
@@ -736,8 +788,7 @@ SimpleDateFormat::initialize(const Locale& locale,
         fNumberFormat->setParseIntegerOnly(TRUE);
         fNumberFormat->setMinimumFractionDigits(0); // To prevent "Jan 1.00, 1997.00"
 
-        // TODO: Really, the default should be lenient...
-        fNumberFormat->setParseStrict(FALSE);
+        //fNumberFormat->setLenient(TRUE); // Java uses a custom DateNumberFormat to format/parse
 
         initNumberFormatters(locale,status);
 
@@ -793,7 +844,22 @@ SimpleDateFormat::format(Calendar& cal, UnicodeString& appendTo, FieldPosition&
 {
   UErrorCode status = U_ZERO_ERROR;
   FieldPositionOnlyHandler handler(pos);
-  return _format(cal, appendTo, handler, status);
+  return _format(cal, fDefaultCapitalizationContext, appendTo, handler, status);
+}
+
+//----------------------------------------------------------------------
+
+UnicodeString&
+SimpleDateFormat::format(Calendar& cal, const UDateFormatContextType* types, const UDateFormatContextValue* values,
+                         int32_t typesAndValuesCount, UnicodeString& appendTo, FieldPosition& pos) const
+{
+  UErrorCode status = U_ZERO_ERROR;
+  FieldPositionOnlyHandler handler(pos);
+  UDateFormatContextValue capitalizationContext = fDefaultCapitalizationContext;
+  if (types != NULL && values != NULL && typesAndValuesCount==1 && types[0]==UDAT_CAPITALIZATION) {
+    capitalizationContext = values[0];
+  }
+  return _format(cal, capitalizationContext, appendTo, handler, status);
 }
 
 //----------------------------------------------------------------------
@@ -803,31 +869,40 @@ SimpleDateFormat::format(Calendar& cal, UnicodeString& appendTo,
                          FieldPositionIterator* posIter, UErrorCode& status) const
 {
   FieldPositionIteratorHandler handler(posIter, status);
-  return _format(cal, appendTo, handler, status);
+  return _format(cal, fDefaultCapitalizationContext, appendTo, handler, status);
 }
 
 //----------------------------------------------------------------------
 
 UnicodeString&
-SimpleDateFormat::_format(Calendar& cal, UnicodeString& appendTo, FieldPositionHandler& handler,
-                          UErrorCode& status) const
+SimpleDateFormat::_format(Calendar& cal, UDateFormatContextValue capitalizationContext,
+                          UnicodeString& appendTo, FieldPositionHandler& handler, UErrorCode& status) const
 {
-    Calendar *workCal = &cal;
-    TimeZone *backupTZ = NULL;
+    if ( U_FAILURE(status) ) {
+       return appendTo; 
+    }
+    Calendar* workCal = &cal;
+    Calendar* calClone = NULL;
     if (&cal != fCalendar && uprv_strcmp(cal.getType(), fCalendar->getType()) != 0) {
         // Different calendar type
         // We use the time and time zone from the input calendar, but
         // do not use the input calendar for field calculation.
-        UDate t = cal.getTime(status);
-        fCalendar->setTime(t, status);
-        backupTZ = fCalendar->getTimeZone().clone();
-        fCalendar->setTimeZone(cal.getTimeZone());
-        workCal = fCalendar;
+        calClone = fCalendar->clone();
+        if (calClone != NULL) {
+            UDate t = cal.getTime(status);
+            calClone->setTime(t, status);
+            calClone->setTimeZone(cal.getTimeZone());
+            workCal = calClone;
+        } else {
+            status = U_MEMORY_ALLOCATION_ERROR;
+            return appendTo;
+        }
     }
 
     UBool inQuote = FALSE;
     UChar prevCh = 0;
     int32_t count = 0;
+    int32_t fieldNum = 0;
 
     // loop through the pattern string character by character
     for (int32_t i = 0; i < fPattern.length() && U_SUCCESS(status); ++i) {
@@ -836,7 +911,7 @@ SimpleDateFormat::_format(Calendar& cal, UnicodeString& appendTo, FieldPositionH
         // Use subFormat() to format a repeated pattern character
         // when a different pattern or non-pattern character is seen
         if (ch != prevCh && count > 0) {
-            subFormat(appendTo, prevCh, count, handler, *workCal, status);
+            subFormat(appendTo, prevCh, count, capitalizationContext, fieldNum++, handler, *workCal, status);
             count = 0;
         }
         if (ch == QUOTE) {
@@ -864,12 +939,11 @@ SimpleDateFormat::_format(Calendar& cal, UnicodeString& appendTo, FieldPositionH
 
     // Format the last item in the pattern, if any
     if (count > 0) {
-        subFormat(appendTo, prevCh, count, handler, *workCal, status);
+        subFormat(appendTo, prevCh, count, capitalizationContext, fieldNum++, handler, *workCal, status);
     }
 
-    if (backupTZ != NULL) {
-        // Restore the original time zone
-        fCalendar->adoptTimeZone(backupTZ);
+    if (calClone != NULL) {
+        delete calClone;
     }
 
     return appendTo;
@@ -906,7 +980,7 @@ SimpleDateFormat::fgPatternCharToLevel[] = {
     //       A   B   C   D   E   F   G   H   I   J   K   L   M   N   O
         -1, 40, -1, -1, 20, 30, 30,  0, 50, -1, -1, 50, 20, 20, -1, -1,
     //   P   Q   R   S   T   U   V   W   X   Y   Z
-        -1, 20, -1, 80, -1, -1,  0, 30, -1, 10,  0, -1, -1, -1, -1, -1,
+        -1, 20, -1, 80, -1, 10,  0, 30, -1, 10,  0, -1, -1, -1, -1, -1,
     //       a   b   c   d   e   f   g   h   i   j   k   l   m   n   o
         -1, 40, -1, 30, 30, 30, -1,  0, 50, -1, -1, 50, -1, 60, -1, -1,
     //   p   q   r   s   t   u   v   w   x   y   z
@@ -932,6 +1006,7 @@ SimpleDateFormat::fgPatternIndexToCalendarField[] =
     /*Q*/   UCAL_MONTH,
     /*q*/   UCAL_MONTH,
     /*V*/   UCAL_ZONE_OFFSET,
+    /*U*/   UCAL_YEAR,
 };
 
 // Map index into pattern character string to DateFormat field number
@@ -951,6 +1026,7 @@ SimpleDateFormat::fgPatternIndexToDateFormatField[] = {
     /*Q*/   UDAT_QUARTER_FIELD,
     /*q*/   UDAT_STANDALONE_QUARTER_FIELD,
     /*V*/   UDAT_TIMEZONE_SPECIAL_FIELD,
+    /*U*/   UDAT_YEAR_NAME_FIELD,
 };
 
 //----------------------------------------------------------------------
@@ -970,369 +1046,21 @@ _appendSymbol(UnicodeString& dst,
     }
 }
 
-//---------------------------------------------------------------------
-void
-SimpleDateFormat::appendGMT(NumberFormat *currentNumberFormat,UnicodeString &appendTo, Calendar& cal, UErrorCode& status) const{
-    int32_t offset = cal.get(UCAL_ZONE_OFFSET, status) + cal.get(UCAL_DST_OFFSET, status);
-    if (U_FAILURE(status)) {
-        return;
-    }
-    if (isDefaultGMTFormat()) {
-        formatGMTDefault(currentNumberFormat,appendTo, offset);
-    } else {
-        ((SimpleDateFormat*)this)->initGMTFormatters(status);
-        if (U_SUCCESS(status)) {
-            int32_t type;
-            if (offset < 0) {
-                offset = -offset;
-                type = (offset % U_MILLIS_PER_MINUTE) == 0 ? kGMTNegativeHM : kGMTNegativeHMS;
-            } else {
-                type = (offset % U_MILLIS_PER_MINUTE) == 0 ? kGMTPositiveHM : kGMTPositiveHMS;
-            }
-            Formattable param(offset, Formattable::kIsDate);
-            FieldPosition fpos(0);
-            fGMTFormatters[type]->format(&param, 1, appendTo, fpos, status);
-        }
-    }
-}
-
-int32_t
-SimpleDateFormat::parseGMT(const UnicodeString &text, ParsePosition &pos) const {
-    if (!isDefaultGMTFormat()) {
-        int32_t start = pos.getIndex();
-
-        // Quick check
-        UBool prefixMatch = FALSE;
-        int32_t prefixLen = fSymbols->fGmtFormat.indexOf((UChar)0x007B /* '{' */);
-        if (prefixLen > 0 && text.compare(start, prefixLen, fSymbols->fGmtFormat, 0, prefixLen) == 0) {
-            prefixMatch = TRUE;
-        }
-        if (prefixMatch) {
-            // Prefix matched
-            UErrorCode status = U_ZERO_ERROR;
-            ((SimpleDateFormat*)this)->initGMTFormatters(status);
-            if (U_SUCCESS(status)) {
-                Formattable parsed;
-                int32_t parsedCount;
-
-                // Try negative Hms
-                fGMTFormatters[kGMTNegativeHMS]->parseObject(text, parsed, pos);
-                if (pos.getErrorIndex() == -1 &&
-                    (pos.getIndex() - start) >= fGMTFormatHmsMinLen[kGMTNegativeHMSMinLenIdx]) {
-                    parsed.getArray(parsedCount);
-                    if (parsedCount == 1 && parsed[0].getType() == Formattable::kDate) {
-                        return (int32_t)(-1 * (int64_t)parsed[0].getDate());
-                    }
-                }
-
-                // Reset ParsePosition
-                pos.setIndex(start);
-                pos.setErrorIndex(-1);
-
-                // Try positive Hms
-                fGMTFormatters[kGMTPositiveHMS]->parseObject(text, parsed, pos);
-                if (pos.getErrorIndex() == -1 &&
-                    (pos.getIndex() - start) >= fGMTFormatHmsMinLen[kGMTPositiveHMSMinLenIdx]) {
-                    parsed.getArray(parsedCount);
-                    if (parsedCount == 1 && parsed[0].getType() == Formattable::kDate) {
-                        return (int32_t)((int64_t)parsed[0].getDate());
-                    }
-                }
-
-                // Reset ParsePosition
-                pos.setIndex(start);
-                pos.setErrorIndex(-1);
-
-                // Try negative Hm
-                fGMTFormatters[kGMTNegativeHM]->parseObject(text, parsed, pos);
-                if (pos.getErrorIndex() == -1 && pos.getIndex() > start) {
-                    parsed.getArray(parsedCount);
-                    if (parsedCount == 1 && parsed[0].getType() == Formattable::kDate) {
-                        return (int32_t)(-1 * (int64_t)parsed[0].getDate());
-                    }
-                }
-
-                // Reset ParsePosition
-                pos.setIndex(start);
-                pos.setErrorIndex(-1);
-
-                // Try positive Hm
-                fGMTFormatters[kGMTPositiveHM]->parseObject(text, parsed, pos);
-                if (pos.getErrorIndex() == -1 && pos.getIndex() > start) {
-                    parsed.getArray(parsedCount);
-                    if (parsedCount == 1 && parsed[0].getType() == Formattable::kDate) {
-                        return (int32_t)((int64_t)parsed[0].getDate());
-                    }
-                }
-
-                // Reset ParsePosition
-                pos.setIndex(start);
-                pos.setErrorIndex(-1);
-            }
-            // fall through to the default GMT parsing method
-        }
-    }
-    return parseGMTDefault(text, pos);
-}
-
-void
-SimpleDateFormat::formatGMTDefault(NumberFormat *currentNumberFormat,UnicodeString &appendTo, int32_t offset) const {
-    if (offset < 0) {
-        appendTo += gGmtMinus;
-        offset = -offset; // suppress the '-' sign for text display.
-    }else{
-        appendTo += gGmtPlus;
-    }
-
-    offset /= U_MILLIS_PER_SECOND; // now in seconds
-    int32_t sec = offset % 60;
-    offset /= 60;
-    int32_t min = offset % 60;
-    int32_t hour = offset / 60;
-
-
-    zeroPaddingNumber(currentNumberFormat,appendTo, hour, 2, 2);
-    appendTo += (UChar)0x003A /*':'*/;
-    zeroPaddingNumber(currentNumberFormat,appendTo, min, 2, 2);
-    if (sec != 0) {
-        appendTo += (UChar)0x003A /*':'*/;
-        zeroPaddingNumber(currentNumberFormat,appendTo, sec, 2, 2);
-    }
-}
-
-int32_t
-SimpleDateFormat::parseGMTDefault(const UnicodeString &text, ParsePosition &pos) const {
-    int32_t start = pos.getIndex();
-    NumberFormat *currentNumberFormat = getNumberFormatByIndex(UDAT_TIMEZONE_RFC_FIELD);
-
-    if (start + kUtLen + 1 >= text.length()) {
-        pos.setErrorIndex(start);
-        return 0;
-    }
-
-    int32_t cur = start;
-    // "GMT"
-    if (text.compare(start, kGmtLen, gGmt) == 0) {
-        cur += kGmtLen;
-    } else if (text.compare(start, kUtLen, gUt) == 0) {
-        cur += kUtLen;
-    } else {
-        pos.setErrorIndex(start);
-        return 0;
-    }
-    // Sign
-    UBool negative = FALSE;
-    if (text.charAt(cur) == (UChar)0x002D /* minus */) {
-        negative = TRUE;
-    } else if (text.charAt(cur) != (UChar)0x002B /* plus */) {
-        pos.setErrorIndex(cur);
-        return 0;
-    }
-    cur++;
-
-    // Numbers
-    int32_t numLen;
-    pos.setIndex(cur);
-
-    Formattable number;
-    parseInt(text, number, 6, pos, FALSE,currentNumberFormat);
-    numLen = pos.getIndex() - cur;
-
-    if (numLen <= 0) {
-        pos.setIndex(start);
-        pos.setErrorIndex(cur);
-        return 0;
-    }
-
-    int32_t numVal = number.getLong();
-
-    int32_t hour = 0;
-    int32_t min = 0;
-    int32_t sec = 0;
-
-    if (numLen <= 2) {
-        // H[H][:mm[:ss]]
-        hour = numVal;
-        cur += numLen;
-        if (cur + 2 < text.length() && text.charAt(cur) == (UChar)0x003A /* colon */) {
-            cur++;
-            pos.setIndex(cur);
-            parseInt(text, number, 2, pos, FALSE,currentNumberFormat);
-            numLen = pos.getIndex() - cur;
-            if (numLen == 2) {
-                // got minute field
-                min = number.getLong();
-                cur += numLen;
-                if (cur + 2 < text.length() && text.charAt(cur) == (UChar)0x003A /* colon */) {
-                    cur++;
-                    pos.setIndex(cur);
-                    parseInt(text, number, 2, pos, FALSE,currentNumberFormat);
-                    numLen = pos.getIndex() - cur;
-                    if (numLen == 2) {
-                        // got second field
-                        sec = number.getLong();
-                    } else {
-                        // reset position
-                        pos.setIndex(cur - 1);
-                        pos.setErrorIndex(-1);
-                    }
-                }
-            } else {
-                // reset postion
-                pos.setIndex(cur - 1);
-                pos.setErrorIndex(-1);
-            }
-        }
-    } else if (numLen == 3 || numLen == 4) {
-        // Hmm or HHmm
-        hour = numVal / 100;
-        min = numVal % 100;
-    } else if (numLen == 5 || numLen == 6) {
-        // Hmmss or HHmmss
-        hour = numVal / 10000;
-        min = (numVal % 10000) / 100;
-        sec = numVal % 100;
-    } else {
-        // HHmmss followed by bogus numbers
-        pos.setIndex(cur + 6);
-
-        int32_t shift = numLen - 6;
-        while (shift > 0) {
-            numVal /= 10;
-            shift--;
-        }
-        hour = numVal / 10000;
-        min = (numVal % 10000) / 100;
-        sec = numVal % 100;
-    }
-
-    int32_t offset = ((hour*60 + min)*60 + sec)*1000;
-    if (negative) {
-        offset = -offset;
-    }
-    return offset;
-}
-
-UBool
-SimpleDateFormat::isDefaultGMTFormat() const {
-    // GMT pattern
-    if (fSymbols->fGmtFormat.length() == 0) {
-        // No GMT pattern is set
-        return TRUE;
-    } else if (fSymbols->fGmtFormat.compare(gDefGmtPat, kGmtPatLen) != 0) {
-        return FALSE;
-    }
-    // Hour patterns
-    if (fSymbols->fGmtHourFormats == NULL || fSymbols->fGmtHourFormatsCount != DateFormatSymbols::GMT_HOUR_COUNT) {
-        // No Hour pattern is set
-        return TRUE;
-    } else if ((fSymbols->fGmtHourFormats[DateFormatSymbols::GMT_NEGATIVE_HMS].compare(gDefGmtNegHmsPat, kNegHmsLen) != 0)
-        || (fSymbols->fGmtHourFormats[DateFormatSymbols::GMT_NEGATIVE_HM].compare(gDefGmtNegHmPat, kNegHmLen) != 0)
-        || (fSymbols->fGmtHourFormats[DateFormatSymbols::GMT_POSITIVE_HMS].compare(gDefGmtPosHmsPat, kPosHmsLen) != 0)
-        || (fSymbols->fGmtHourFormats[DateFormatSymbols::GMT_POSITIVE_HM].compare(gDefGmtPosHmPat, kPosHmLen) != 0)) {
-        return FALSE;
-    }
-    return TRUE;
-}
-
-void
-SimpleDateFormat::formatRFC822TZ(UnicodeString &appendTo, int32_t offset) const {
-    UChar sign = 0x002B /* '+' */;
-    if (offset < 0) {
-        offset = -offset;
-        sign = 0x002D /* '-' */;
-    }
-    appendTo.append(sign);
-
-    int32_t offsetH = offset / U_MILLIS_PER_HOUR;
-    offset = offset % U_MILLIS_PER_HOUR;
-    int32_t offsetM = offset / U_MILLIS_PER_MINUTE;
-    offset = offset % U_MILLIS_PER_MINUTE;
-    int32_t offsetS = offset / U_MILLIS_PER_SECOND;
-
-    int32_t num = 0, denom = 0;
-    if (offsetS == 0) {
-        offset = offsetH*100 + offsetM; // HHmm
-        num = offset % 10000;
-        denom = 1000;
-    } else {
-        offset = offsetH*10000 + offsetM*100 + offsetS; // HHmmss
-        num = offset % 1000000;
-        denom = 100000;
-    }
-    while (denom >= 1) {
-        UChar digit = (UChar)0x0030 + (num / denom);
-        appendTo.append(digit);
-        num = num % denom;
-        denom /= 10;
-    }
-}
-
-void
-SimpleDateFormat::initGMTFormatters(UErrorCode &status) {
-    if (U_FAILURE(status)) {
-        return;
-    }
-    umtx_lock(&LOCK);
-    if (fGMTFormatters == NULL) {
-        fGMTFormatters = (MessageFormat**)uprv_malloc(kNumGMTFormatters * sizeof(MessageFormat*));
-        if (fGMTFormatters) {
-            for (int32_t i = 0; i < kNumGMTFormatters; i++) {
-                const UnicodeString *hourPattern = NULL; //initialized it to avoid warning
-                switch (i) {
-                    case kGMTNegativeHMS:
-                        hourPattern = &(fSymbols->fGmtHourFormats[DateFormatSymbols::GMT_NEGATIVE_HMS]);
-                        break;
-                    case kGMTNegativeHM:
-                        hourPattern = &(fSymbols->fGmtHourFormats[DateFormatSymbols::GMT_NEGATIVE_HM]);
-                        break;
-                    case kGMTPositiveHMS:
-                        hourPattern = &(fSymbols->fGmtHourFormats[DateFormatSymbols::GMT_POSITIVE_HMS]);
-                        break;
-                    case kGMTPositiveHM:
-                        hourPattern = &(fSymbols->fGmtHourFormats[DateFormatSymbols::GMT_POSITIVE_HM]);
-                        break;
-                }
-                fGMTFormatters[i] = new MessageFormat(fSymbols->fGmtFormat, status);
-                GregorianCalendar *gcal = new GregorianCalendar(TimeZone::createTimeZone(UnicodeString(gEtcUTC)), status);
-                if (U_FAILURE(status)) {
-                    break;
-                }
-                SimpleDateFormat *sdf = (SimpleDateFormat*)this->clone();
-                sdf->adoptCalendar(gcal);
-                sdf->applyPattern(*hourPattern);
-                
-                // This prevents a hours format pattern like "-HH:mm:ss" from matching
-                // in a string like "GMT-07:00 10:08:11 PM"
-                sdf->setLenient(FALSE);
-                
-                fGMTFormatters[i]->adoptFormat(0, sdf);
-
-                // For parsing, we only allow Hms patterns to be equal or longer
-                // than its length with fixed minutes/seconds digits.
-                // See #6880
-                if (i == kGMTNegativeHMS || i == kGMTPositiveHMS) {
-                    UnicodeString tmp;
-                    Formattable tmpParam(60*60*1000, Formattable::kIsDate);
-                    FieldPosition fpos(0);
-                    fGMTFormatters[i]->format(&tmpParam, 1, tmp, fpos, status);
-                    if (U_FAILURE(status)) {
-                        break;
-                    }
-                    if (i == kGMTNegativeHMS) {
-                        fGMTFormatHmsMinLen[kGMTNegativeHMSMinLenIdx] = tmp.length();
-                    } else {
-                        fGMTFormatHmsMinLen[kGMTPositiveHMSMinLenIdx] = tmp.length();
-                    }
-                }
-            }
+static inline void
+_appendSymbolWithMonthPattern(UnicodeString& dst, int32_t value, const UnicodeString* symbols, int32_t symbolsCount,
+              const UnicodeString* monthPattern, UErrorCode& status) {
+    U_ASSERT(0 <= value && value < symbolsCount);
+    if (0 <= value && value < symbolsCount) {
+        if (monthPattern == NULL) {
+            dst += symbols[value];
         } else {
-            status = U_MEMORY_ALLOCATION_ERROR;
+            Formattable monthName((const UnicodeString&)(symbols[value]));
+            MessageFormat::format(*monthPattern, &monthName, 1, dst, status);
         }
     }
-    umtx_unlock(&LOCK);
 }
 
+//----------------------------------------------------------------------
 void
 SimpleDateFormat::initNumberFormatters(const Locale &locale,UErrorCode &status) {
     if (U_FAILURE(status)) {
@@ -1371,7 +1099,7 @@ SimpleDateFormat::processOverrideString(const Locale &locale, const UnicodeStrin
     UBool moreToProcess = TRUE;
 
     while (moreToProcess) {
-        int32_t delimiterPosition = str.indexOf(ULOC_KEYWORD_ITEM_SEPARATOR_UNICODE,start);
+        int32_t delimiterPosition = str.indexOf((UChar)ULOC_KEYWORD_ITEM_SEPARATOR_UNICODE,start);
         if (delimiterPosition == -1) {
             moreToProcess = FALSE;
             len = str.length() - start;
@@ -1379,7 +1107,7 @@ SimpleDateFormat::processOverrideString(const Locale &locale, const UnicodeStrin
             len = delimiterPosition - start;
         }
         UnicodeString currentString(str,start,len);
-        int32_t equalSignPosition = currentString.indexOf(ULOC_KEYWORD_ASSIGN_UNICODE,0);
+        int32_t equalSignPosition = currentString.indexOf((UChar)ULOC_KEYWORD_ASSIGN_UNICODE,0);
         if (equalSignPosition == -1) { // Simple override string such as "hebrew"
             nsName.setTo(currentString);
             ovrField.setToBogus();
@@ -1488,6 +1216,8 @@ void
 SimpleDateFormat::subFormat(UnicodeString &appendTo,
                             UChar ch,
                             int32_t count,
+                            UDateFormatContextValue capitalizationContext,
+                            int32_t fieldNum,
                             FieldPositionHandler& handler,
                             Calendar& cal,
                             UErrorCode& status) const
@@ -1504,13 +1234,17 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
     const int32_t maxIntCount = 10;
     int32_t beginOffset = appendTo.length();
     NumberFormat *currentNumberFormat;
+    DateFormatSymbols::ECapitalizationContextUsageType capContextUsageType = DateFormatSymbols::kCapContextUsageOther;
 
-    UBool isHebrewCalendar = !strcmp(cal.getType(),"hebrew");
+    UBool isHebrewCalendar = (uprv_strcmp(cal.getType(),"hebrew") == 0);
+    UBool isChineseCalendar = (uprv_strcmp(cal.getType(),"chinese") == 0);
 
     // if the pattern character is unrecognized, signal an error and dump out
     if (patternCharPtr == NULL)
     {
-        status = U_INVALID_FORMAT_ERROR;
+        if (ch != 0x6C) { // pattern char 'l' (SMALL LETTER L) just gets ignored
+            status = U_INVALID_FORMAT_ERROR;
+        }
         return;
     }
 
@@ -1522,20 +1256,38 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
     }
 
     currentNumberFormat = getNumberFormatByIndex(patternCharIndex);
+    UnicodeString hebr("hebr", 4, US_INV);
+    
     switch (patternCharIndex) {
 
     // for any "G" symbol, write out the appropriate era string
     // "GGGG" is wide era name, "GGGGG" is narrow era name, anything else is abbreviated name
     case UDAT_ERA_FIELD:
-        if (count == 5)
-           _appendSymbol(appendTo, value, fSymbols->fNarrowEras, fSymbols->fNarrowErasCount);
-        else if (count == 4)
-           _appendSymbol(appendTo, value, fSymbols->fEraNames, fSymbols->fEraNamesCount);
-        else
-           _appendSymbol(appendTo, value, fSymbols->fEras, fSymbols->fErasCount);
+        if (isChineseCalendar) {
+            zeroPaddingNumber(currentNumberFormat,appendTo, value, 1, 9); // as in ICU4J
+        } else {
+            if (count == 5) {
+                _appendSymbol(appendTo, value, fSymbols->fNarrowEras, fSymbols->fNarrowErasCount);
+                capContextUsageType = DateFormatSymbols::kCapContextUsageEraNarrow;
+            } else if (count == 4) {
+                _appendSymbol(appendTo, value, fSymbols->fEraNames, fSymbols->fEraNamesCount);
+                capContextUsageType = DateFormatSymbols::kCapContextUsageEraWide;
+            } else {
+                _appendSymbol(appendTo, value, fSymbols->fEras, fSymbols->fErasCount);
+                capContextUsageType = DateFormatSymbols::kCapContextUsageEraAbbrev;
+            }
+        }
         break;
 
-    // OLD: for "yyyy", write out the whole year; for "yy", write out the last 2 digits
+     case UDAT_YEAR_NAME_FIELD:
+        if (fSymbols->fShortYearNames != NULL && value <= fSymbols->fShortYearNamesCount) {
+            // the Calendar YEAR field runs 1 through 60 for cyclic years
+            _appendSymbol(appendTo, value - 1, fSymbols->fShortYearNames, fSymbols->fShortYearNamesCount);
+            break;
+        }
+        // else fall through to numeric year handling, do not break here
+
+   // OLD: for "yyyy", write out the whole year; for "yy", write out the last 2 digits
     // NEW: UTS#35:
 //Year         y     yy     yyy     yyyy     yyyyy
 //AD 1         1     01     001     0001     00001
@@ -1545,17 +1297,21 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
 //AD 12345 12345     45   12345    12345     12345
     case UDAT_YEAR_FIELD:
     case UDAT_YEAR_WOY_FIELD:
+        if (fDateOverride.compare(hebr)==0 && value>5000 && value<6000) {
+            value-=5000;
+        }
         if(count == 2)
             zeroPaddingNumber(currentNumberFormat, appendTo, value, 2, 2);
         else
             zeroPaddingNumber(currentNumberFormat, appendTo, value, count, maxIntCount);
         break;
 
-    // for "MMMM", write out the whole month name, for "MMM", write out the month
-    // abbreviation, for "M" or "MM", write out the month as a number with the
+    // for "MMMM"/"LLLL", write out the whole month name, for "MMM"/"LLL", write out the month
+    // abbreviation, for "M"/"L" or "MM"/"LL", write out the month as a number with the
     // appropriate number of digits
-    // for "MMMMM", use the narrow form
+    // for "MMMMM"/"LLLLL", use the narrow form
     case UDAT_MONTH_FIELD:
+    case UDAT_STANDALONE_MONTH_FIELD:
         if ( isHebrewCalendar ) {
            HebrewCalendar *hc = (HebrewCalendar*)&cal;
            if (hc->isLeapYear(hc->get(UCAL_YEAR,status)) && value == 6 && count >= 3 )
@@ -1563,35 +1319,46 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
            if (!hc->isLeapYear(hc->get(UCAL_YEAR,status)) && value >= 6 && count < 3 )
                value--; // Adjust the month number down 1 in Hebrew non-leap years, i.e. Adar is 6, not 7.
         }
-        if (count == 5)
-            _appendSymbol(appendTo, value, fSymbols->fNarrowMonths,
-                          fSymbols->fNarrowMonthsCount);
-        else if (count == 4)
-            _appendSymbol(appendTo, value, fSymbols->fMonths,
-                          fSymbols->fMonthsCount);
-        else if (count == 3)
-            _appendSymbol(appendTo, value, fSymbols->fShortMonths,
-                          fSymbols->fShortMonthsCount);
-        else
-            zeroPaddingNumber(currentNumberFormat,appendTo, value + 1, count, maxIntCount);
-        break;
-
-    // for "LLLL", write out the whole month name, for "LLL", write out the month
-    // abbreviation, for "L" or "LL", write out the month as a number with the
-    // appropriate number of digits
-    // for "LLLLL", use the narrow form
-    case UDAT_STANDALONE_MONTH_FIELD:
-        if (count == 5)
-            _appendSymbol(appendTo, value, fSymbols->fStandaloneNarrowMonths,
-                          fSymbols->fStandaloneNarrowMonthsCount);
-        else if (count == 4)
-            _appendSymbol(appendTo, value, fSymbols->fStandaloneMonths,
-                          fSymbols->fStandaloneMonthsCount);
-        else if (count == 3)
-            _appendSymbol(appendTo, value, fSymbols->fStandaloneShortMonths,
-                          fSymbols->fStandaloneShortMonthsCount);
-        else
-            zeroPaddingNumber(currentNumberFormat,appendTo, value + 1, count, maxIntCount);
+        {
+            int32_t isLeapMonth = (fSymbols->fLeapMonthPatterns != NULL && fSymbols->fLeapMonthPatternsCount >= DateFormatSymbols::kMonthPatternsCount)?
+                        cal.get(UCAL_IS_LEAP_MONTH, status): 0;
+            // should consolidate the next section by using arrays of pointers & counts for the right symbols...
+            if (count == 5) {
+                if (patternCharIndex == UDAT_MONTH_FIELD) {
+                    _appendSymbolWithMonthPattern(appendTo, value, fSymbols->fNarrowMonths, fSymbols->fNarrowMonthsCount,
+                            (isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternFormatNarrow]): NULL, status);
+                } else {
+                    _appendSymbolWithMonthPattern(appendTo, value, fSymbols->fStandaloneNarrowMonths, fSymbols->fStandaloneNarrowMonthsCount,
+                            (isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternStandaloneNarrow]): NULL, status);
+                }
+                capContextUsageType = DateFormatSymbols::kCapContextUsageMonthNarrow;
+            } else if (count == 4) {
+                if (patternCharIndex == UDAT_MONTH_FIELD) {
+                    _appendSymbolWithMonthPattern(appendTo, value, fSymbols->fMonths, fSymbols->fMonthsCount,
+                            (isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternFormatWide]): NULL, status);
+                    capContextUsageType = DateFormatSymbols::kCapContextUsageMonthFormat;
+                } else {
+                    _appendSymbolWithMonthPattern(appendTo, value, fSymbols->fStandaloneMonths, fSymbols->fStandaloneMonthsCount,
+                            (isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternStandaloneWide]): NULL, status);
+                    capContextUsageType = DateFormatSymbols::kCapContextUsageMonthStandalone;
+                }
+            } else if (count == 3) {
+                if (patternCharIndex == UDAT_MONTH_FIELD) {
+                    _appendSymbolWithMonthPattern(appendTo, value, fSymbols->fShortMonths, fSymbols->fShortMonthsCount,
+                            (isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternFormatAbbrev]): NULL, status);
+                    capContextUsageType = DateFormatSymbols::kCapContextUsageMonthFormat;
+                } else {
+                    _appendSymbolWithMonthPattern(appendTo, value, fSymbols->fStandaloneShortMonths, fSymbols->fStandaloneShortMonthsCount,
+                            (isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternStandaloneAbbrev]): NULL, status);
+                    capContextUsageType = DateFormatSymbols::kCapContextUsageMonthStandalone;
+                }
+            } else {
+                UnicodeString monthNumber;
+                zeroPaddingNumber(currentNumberFormat,monthNumber, value + 1, count, maxIntCount);
+                _appendSymbolWithMonthPattern(appendTo, 0, &monthNumber, 1,
+                        (isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternNumeric]): NULL, status);
+            }
+        }
         break;
 
     // for "k" and "kk", write out the hour, adjusting midnight to appear as "24"
@@ -1638,15 +1405,19 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
         }
         // fall through, do not break here
     case UDAT_DAY_OF_WEEK_FIELD:
-        if (count == 5)
+        if (count == 5) {
             _appendSymbol(appendTo, value, fSymbols->fNarrowWeekdays,
                           fSymbols->fNarrowWeekdaysCount);
-        else if (count == 4)
+            capContextUsageType = DateFormatSymbols::kCapContextUsageDayNarrow;
+        } else if (count == 4) {
             _appendSymbol(appendTo, value, fSymbols->fWeekdays,
                           fSymbols->fWeekdaysCount);
-        else
+            capContextUsageType = DateFormatSymbols::kCapContextUsageDayFormat;
+        } else {
             _appendSymbol(appendTo, value, fSymbols->fShortWeekdays,
                           fSymbols->fShortWeekdaysCount);
+            capContextUsageType = DateFormatSymbols::kCapContextUsageDayFormat;
+        }
         break;
 
     // for "ccc", write out the abbreviated day-of-the-week name
@@ -1663,15 +1434,19 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
         if (U_FAILURE(status)) {
             return;
         }
-        if (count == 5)
+        if (count == 5) {
             _appendSymbol(appendTo, value, fSymbols->fStandaloneNarrowWeekdays,
                           fSymbols->fStandaloneNarrowWeekdaysCount);
-        else if (count == 4)
+            capContextUsageType = DateFormatSymbols::kCapContextUsageDayNarrow;
+        } else if (count == 4) {
             _appendSymbol(appendTo, value, fSymbols->fStandaloneWeekdays,
                           fSymbols->fStandaloneWeekdaysCount);
-        else // count == 3
+            capContextUsageType = DateFormatSymbols::kCapContextUsageDayStandalone;
+        } else { // count == 3
             _appendSymbol(appendTo, value, fSymbols->fStandaloneShortWeekdays,
                           fSymbols->fStandaloneShortWeekdaysCount);
+            capContextUsageType = DateFormatSymbols::kCapContextUsageDayStandalone;
+        }
         break;
 
     // for and "a" symbol, write out the whole AM/PM string
@@ -1698,55 +1473,56 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
     case UDAT_TIMEZONE_FIELD:
     case UDAT_TIMEZONE_GENERIC_FIELD:
     case UDAT_TIMEZONE_SPECIAL_FIELD:
+    case UDAT_TIMEZONE_RFC_FIELD: // 'Z' - TIMEZONE_RFC
         {
             UnicodeString zoneString;
-            const ZoneStringFormat *zsf = fSymbols->getZoneStringFormat();
-            if (zsf) {
-                if (patternCharIndex == UDAT_TIMEZONE_FIELD) {
+            const TimeZone& tz = cal.getTimeZone();
+            UDate date = cal.getTime(status);
+            if (U_SUCCESS(status)) {
+                if (patternCharIndex == UDAT_TIMEZONE_RFC_FIELD) {
+                    if (count < 4) {
+                        // "Z"
+                        tzFormat()->format(UTZFMT_STYLE_RFC822, tz, date, zoneString);
+                    } else if (count == 5) {
+                        // "ZZZZZ"
+                        tzFormat()->format(UTZFMT_STYLE_ISO8601, tz, date, zoneString);
+                    } else {
+                        // "ZZ", "ZZZ", "ZZZZ"
+                        tzFormat()->format(UTZFMT_STYLE_LOCALIZED_GMT, tz, date, zoneString);
+                    }
+                } else if (patternCharIndex == UDAT_TIMEZONE_FIELD) {
                     if (count < 4) {
                         // "z", "zz", "zzz"
-                        zsf->getSpecificShortString(cal, TRUE /*commonly used only*/,
-                            zoneString, status);
+                        tzFormat()->format(UTZFMT_STYLE_SPECIFIC_SHORT, tz, date, zoneString);
+                        capContextUsageType = DateFormatSymbols::kCapContextUsageMetazoneShort;
                     } else {
                         // "zzzz"
-                        zsf->getSpecificLongString(cal, zoneString, status);
+                        tzFormat()->format(UTZFMT_STYLE_SPECIFIC_LONG, tz, date, zoneString);
+                        capContextUsageType = DateFormatSymbols::kCapContextUsageMetazoneLong;
                     }
                 } else if (patternCharIndex == UDAT_TIMEZONE_GENERIC_FIELD) {
                     if (count == 1) {
                         // "v"
-                        zsf->getGenericShortString(cal, TRUE /*commonly used only*/,
-                            zoneString, status);
+                        tzFormat()->format(UTZFMT_STYLE_GENERIC_SHORT, tz, date, zoneString);
+                        capContextUsageType = DateFormatSymbols::kCapContextUsageMetazoneShort;
                     } else if (count == 4) {
                         // "vvvv"
-                        zsf->getGenericLongString(cal, zoneString, status);
+                        tzFormat()->format(UTZFMT_STYLE_GENERIC_LONG, tz, date, zoneString);
+                        capContextUsageType = DateFormatSymbols::kCapContextUsageMetazoneLong;
                     }
                 } else { // patternCharIndex == UDAT_TIMEZONE_SPECIAL_FIELD
                     if (count == 1) {
                         // "V"
-                        zsf->getSpecificShortString(cal, FALSE /*ignore commonly used*/,
-                            zoneString, status);
+                        tzFormat()->format(UTZFMT_STYLE_SPECIFIC_SHORT, tz, date, zoneString);
+                        capContextUsageType = DateFormatSymbols::kCapContextUsageMetazoneShort;
                     } else if (count == 4) {
                         // "VVVV"
-                        zsf->getGenericLocationString(cal, zoneString, status);
+                        tzFormat()->format(UTZFMT_STYLE_GENERIC_LOCATION, tz, date, zoneString);
+                        capContextUsageType = DateFormatSymbols::kCapContextUsageZoneLong;
                     }
                 }
             }
-            if (zoneString.isEmpty()) {
-                appendGMT(currentNumberFormat,appendTo, cal, status);
-            } else {
-                appendTo += zoneString;
-            }
-        }
-        break;
-
-    case UDAT_TIMEZONE_RFC_FIELD: // 'Z' - TIMEZONE_RFC
-        if (count < 4) {
-            // RFC822 format, must use ASCII digits
-            value = (cal.get(UCAL_ZONE_OFFSET, status) + cal.get(UCAL_DST_OFFSET, status));
-            formatRFC822TZ(appendTo, value);
-        } else {
-            // long form, localized GMT pattern
-            appendGMT(currentNumberFormat,appendTo, cal, status);
+            appendTo += zoneString;
         }
         break;
 
@@ -1779,6 +1555,31 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
         zeroPaddingNumber(currentNumberFormat,appendTo, value, count, maxIntCount);
         break;
     }
+#if !UCONFIG_NO_BREAK_ITERATION
+    if (fieldNum == 0) {
+        // first field, check to see whether we need to titlecase it
+        UBool titlecase = FALSE;
+        switch (capitalizationContext) {
+            case UDAT_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE:
+                titlecase = TRUE;
+                break;
+            case UDAT_CAPITALIZATION_FOR_UI_LIST_OR_MENU:
+               titlecase = fSymbols->fCapitalization[capContextUsageType][0];
+               break;
+            case UDAT_CAPITALIZATION_FOR_STANDALONE:
+               titlecase = fSymbols->fCapitalization[capContextUsageType][1];
+               break;
+            default:
+                // titlecase = FALSE;
+                break;
+        }
+        if (titlecase) {
+            UnicodeString firstField(appendTo, beginOffset);
+            firstField.toTitle(NULL, fLocale, U_TITLECASE_NO_LOWERCASE | U_TITLECASE_NO_BREAK_ADJUSTMENT);
+            appendTo.replaceBetween(beginOffset, appendTo.length(), firstField);
+        }
+    }
+#endif
 
     handler.addAttribute(fgPatternIndexToDateFormatField[patternCharIndex], beginOffset, appendTo.length());
 }
@@ -1840,7 +1641,7 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition&
     UBool lenient = isLenient();
 
     // hack, reset tztype, cast away const
-    ((SimpleDateFormat*)this)->tztype = TZTYPE_UNK;
+    ((SimpleDateFormat*)this)->tztype = UTZFMT_TIME_TYPE_UNKNOWN;
 
     // For parsing abutting numeric fields. 'abutPat' is the
     // offset into 'pattern' of the first of 2 or more abutting
@@ -1853,20 +1654,36 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition&
     UBool inQuote = FALSE;
 
     const UnicodeString numericFormatChars(NUMERIC_FORMAT_CHARS);
+    MessageFormat * numericLeapMonthFormatter = NULL;
 
-    TimeZone *backupTZ = NULL;
+    Calendar* calClone = NULL;
     Calendar *workCal = &cal;
     if (&cal != fCalendar && uprv_strcmp(cal.getType(), fCalendar->getType()) != 0) {
         // Different calendar type
         // We use the time/zone from the input calendar, but
         // do not use the input calendar for field calculation.
-        fCalendar->setTime(cal.getTime(status),status);
-        if (U_FAILURE(status)) {
+        calClone = fCalendar->clone();
+        if (calClone != NULL) {
+            calClone->setTime(cal.getTime(status),status);
+            if (U_FAILURE(status)) {
+                goto ExitParse;
+            }
+            calClone->setTimeZone(cal.getTimeZone());
+            workCal = calClone;
+        } else {
+            status = U_MEMORY_ALLOCATION_ERROR;
             goto ExitParse;
         }
-        backupTZ = fCalendar->getTimeZone().clone();
-        fCalendar->setTimeZone(cal.getTimeZone());
-        workCal = fCalendar;
+    }
+    
+    if (fSymbols->fLeapMonthPatterns != NULL && fSymbols->fLeapMonthPatternsCount >= DateFormatSymbols::kMonthPatternsCount) {
+        numericLeapMonthFormatter = new MessageFormat(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternNumeric], fLocale, status);
+        if (numericLeapMonthFormatter == NULL) {
+             status = U_MEMORY_ALLOCATION_ERROR;
+             goto ExitParse;
+        } else if (U_FAILURE(status)) {
+             goto ExitParse; // this will delete numericLeapMonthFormatter
+        }
     }
 
     for (int32_t i=0; i<fPattern.length(); ++i) {
@@ -1940,7 +1757,7 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition&
                 }
 
                 pos = subParse(text, pos, ch, count,
-                               TRUE, FALSE, ambiguousYear, saveHebrewMonth, *workCal, i);
+                               TRUE, FALSE, ambiguousYear, saveHebrewMonth, *workCal, i, numericLeapMonthFormatter);
 
                 // If the parse fails anywhere in the run, back up to the
                 // start of the run and retry.
@@ -1953,9 +1770,9 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition&
 
             // Handle non-numeric fields and non-abutting numeric
             // fields.
-            else {
+            else if (ch != 0x6C) { // pattern char 'l' (SMALL LETTER L) just gets ignored
                 int32_t s = subParse(text, pos, ch, count,
-                               FALSE, TRUE, ambiguousYear, saveHebrewMonth, *workCal, i);
+                               FALSE, TRUE, ambiguousYear, saveHebrewMonth, *workCal, i, numericLeapMonthFormatter);
 
                 if (s == -pos-1) {
                     // era not present, in special cases allow this to continue
@@ -1966,11 +1783,11 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition&
                         UChar ch = fPattern.charAt(i+1);
 
                         // check for whitespace
-                        if (uprv_isRuleWhiteSpace(ch)) {
+                        if (PatternProps::isWhiteSpace(ch)) {
                             i++;
                             // Advance over run in pattern
                             while ((i+1)<fPattern.length() &&
-                                   uprv_isRuleWhiteSpace(fPattern.charAt(i+1))) {
+                                   PatternProps::isWhiteSpace(fPattern.charAt(i+1))) {
                                 ++i;
                             }
                         }
@@ -2026,7 +1843,7 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition&
     // when the two-digit year is equal to the start year, and thus might fall at the
     // front or the back of the default century.  This only works because we adjust
     // the year correctly to start with in other cases -- see subParse().
-    if (ambiguousYear[0] || tztype != TZTYPE_UNK) // If this is true then the two-digit year == the default start year
+    if (ambiguousYear[0] || tztype != UTZFMT_TIME_TYPE_UNKNOWN) // If this is true then the two-digit year == the default start year
     {
         // We need a copy of the fields, and we need to avoid triggering a call to
         // complete(), which will recalculate the fields.  Since we can't access
@@ -2049,7 +1866,7 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition&
             delete copy;
         }
 
-        if (tztype != TZTYPE_UNK) {
+        if (tztype != UTZFMT_TIME_TYPE_UNKNOWN) {
             copy = cal.clone();
             // Check for failed cloning.
             if (copy == NULL) {
@@ -2075,7 +1892,7 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition&
             // matches the rule used by the parsed time zone.
             int32_t raw, dst;
             if (btz != NULL) {
-                if (tztype == TZTYPE_STD) {
+                if (tztype == UTZFMT_TIME_TYPE_STANDARD) {
                     btz->getOffsetFromLocal(localMillis,
                         BasicTimeZone::kStandard, BasicTimeZone::kStandard, raw, dst, status);
                 } else {
@@ -2090,7 +1907,7 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition&
 
             // Now, compare the results with parsed type, either standard or daylight saving time
             int32_t resolvedSavings = dst;
-            if (tztype == TZTYPE_STD) {
+            if (tztype == UTZFMT_TIME_TYPE_STANDARD) {
                 if (dst != 0) {
                     // Override DST_OFFSET = 0 in the result calendar
                     resolvedSavings = 0;
@@ -2166,9 +1983,11 @@ ExitParse:
         cal.setTime(workCal->getTime(status), status);
     }
 
-    // Restore the original time zone if required
-    if (backupTZ != NULL) {
-        fCalendar->adoptTimeZone(backupTZ);
+    if (numericLeapMonthFormatter != NULL) {
+        delete numericLeapMonthFormatter;
+    }
+    if (calClone != NULL) {
+        delete calClone;
     }
 
     // If any Calendar calls failed, we pretend that we
@@ -2324,7 +2143,7 @@ UBool SimpleDateFormat::matchLiterals(const UnicodeString &pattern,
     for (p = 0; p < literal.length() && t < text.length(); p += 1, t += 1) {
         UBool needWhitespace = FALSE;
         
-        while (p < literal.length() && uprv_isRuleWhiteSpace(literal.charAt(p))) {
+        while (p < literal.length() && PatternProps::isWhiteSpace(literal.charAt(p))) {
             needWhitespace = TRUE;
             p += 1;
         }
@@ -2335,7 +2154,7 @@ UBool SimpleDateFormat::matchLiterals(const UnicodeString &pattern,
             while (t < text.length()) {
                 UChar tch = text.charAt(t);
                 
-                if (!u_isUWhiteSpace(tch) && !uprv_isRuleWhiteSpace(tch)) {
+                if (!u_isUWhiteSpace(tch) && !PatternProps::isWhiteSpace(tch)) {
                     break;
                 }
                 
@@ -2407,6 +2226,7 @@ int32_t SimpleDateFormat::matchString(const UnicodeString& text,
                               UCalendarDateFields field,
                               const UnicodeString* data,
                               int32_t dataCount,
+                              const UnicodeString* monthPattern,
                               Calendar& cal) const
 {
     int32_t i = 0;
@@ -2419,6 +2239,8 @@ int32_t SimpleDateFormat::matchString(const UnicodeString& text,
     // We keep track of the longest match, and return that.  Note that this
     // unfortunately requires us to test all array elements.
     int32_t bestMatchLength = 0, bestMatch = -1;
+    UnicodeString bestMatchName;
+    int32_t isLeapMonth = 0;
 
     // {sfb} kludge to support case-insensitive comparison
     // {markus 2002oct11} do not just use caseCompareBetween because we do not know
@@ -2443,6 +2265,28 @@ int32_t SimpleDateFormat::matchString(const UnicodeString& text,
         {
             bestMatch = i;
             bestMatchLength = length;
+            bestMatchName.setTo(data[i]);
+            isLeapMonth = 0;
+        }
+
+        if (monthPattern != NULL) {
+            UErrorCode status = U_ZERO_ERROR;
+            UnicodeString leapMonthName;
+            Formattable monthName((const UnicodeString&)(data[i]));
+            MessageFormat::format(*monthPattern, &monthName, 1, leapMonthName, status);
+            if (U_SUCCESS(status)) {
+                lcase.fastCopyFrom(leapMonthName).foldCase();
+                length = lcase.length();
+
+                if (length > bestMatchLength &&
+                    lcaseText.compareBetween(0, length, lcase, 0, length) == 0)
+                {
+                    bestMatch = i;
+                    bestMatchLength = length;
+                    bestMatchName.setTo(leapMonthName);
+                    isLeapMonth = 1;
+                }
+            }
         }
     }
     if (bestMatch >= 0)
@@ -2452,13 +2296,19 @@ int32_t SimpleDateFormat::matchString(const UnicodeString& text,
             cal.set(field,6);
         }
         else {
+            if (field == UCAL_YEAR) {
+                bestMatch++; // only get here for cyclic year names, which match 1-based years 1-60
+            }
             cal.set(field, bestMatch);
         }
+        if (monthPattern != NULL) {
+            cal.set(UCAL_IS_LEAP_MONTH, isLeapMonth);
+        }
 
         // Once we have a match, we have to determine the length of the
         // original source string.  This will usually be == the length of
         // the case folded string, but it may differ (e.g. sharp s).
-        lcase.fastCopyFrom(data[bestMatch]).foldCase();
+        lcase.fastCopyFrom(bestMatchName).foldCase();
 
         // Most of the time, the length will be the same as the length
         // of the string from the locale data.  Sometimes it will be
@@ -2466,7 +2316,7 @@ int32_t SimpleDateFormat::matchString(const UnicodeString& text,
         // adding a character at a time, until we have a match.  We do
         // this all in one loop, where we try 'len' first (at index
         // i==0).
-        int32_t len = data[bestMatch].length(); // 99+% of the time
+        int32_t len = bestMatchName.length(); // 99+% of the time
         int32_t n = text.length() - start;
         for (i=0; i<=n; ++i) {
             int32_t j=i;
@@ -2506,7 +2356,7 @@ SimpleDateFormat::set2DigitYearStart(UDate d, UErrorCode& status)
  */
 int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UChar ch, int32_t count,
                            UBool obeyCount, UBool allowNegative, UBool ambiguousYear[], int32_t& saveHebrewMonth, Calendar& cal,
-                           int32_t patLoc) const
+                           int32_t patLoc, MessageFormat * numericLeapMonthFormatter) const
 {
     Formattable number;
     int32_t value = 0;
@@ -2518,6 +2368,7 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
     UnicodeString temp;
     UChar *patternCharPtr = u_strchr(DateFormatSymbols::getPatternUChars(), ch);
     UBool lenient = isLenient();
+    int32_t tzParseOptions = (lenient)? UTZFMT_PARSE_OPTION_ALL_STYLES: UTZFMT_PARSE_OPTION_NONE;
     UBool gotNumber = FALSE;
 
 #if defined (U_DEBUG_CAL)
@@ -2531,6 +2382,12 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
     patternCharIndex = (UDateFormatField)(patternCharPtr - DateFormatSymbols::getPatternUChars());
     currentNumberFormat = getNumberFormatByIndex(patternCharIndex);
     UCalendarDateFields field = fgPatternIndexToCalendarField[patternCharIndex];
+    UnicodeString hebr("hebr", 4, US_INV);
+
+    if (numericLeapMonthFormatter != NULL) {
+        numericLeapMonthFormatter->setFormats((const Format **)&currentNumberFormat, 1);
+    }
+    UBool isChineseCalendar = (uprv_strcmp(cal.getType(),"chinese") == 0);
 
     // If there are any spaces here, skip over them.  If we hit the end
     // of the string, then fail.
@@ -2538,52 +2395,68 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
         if (start >= text.length()) {
             return -start;
         }
-        
         UChar32 c = text.char32At(start);
-        if (!u_isUWhiteSpace(c) /*||*/ && !uprv_isRuleWhiteSpace(c)) {
+        if (!u_isUWhiteSpace(c) /*||*/ && !PatternProps::isWhiteSpace(c)) {
             break;
         }
-        
-        start += UTF_CHAR_LENGTH(c);
+        start += U16_LENGTH(c);
     }
-    
     pos.setIndex(start);
 
     // We handle a few special cases here where we need to parse
     // a number value.  We handle further, more generic cases below.  We need
     // to handle some of them here because some fields require extra processing on
     // the parsed value.
-    if (patternCharIndex == UDAT_HOUR_OF_DAY1_FIELD ||
-        patternCharIndex == UDAT_HOUR_OF_DAY0_FIELD ||
-        patternCharIndex == UDAT_HOUR1_FIELD ||
-        patternCharIndex == UDAT_HOUR0_FIELD ||
-        patternCharIndex == UDAT_DOW_LOCAL_FIELD ||
-        patternCharIndex == UDAT_STANDALONE_DAY_FIELD ||
-        patternCharIndex == UDAT_MONTH_FIELD ||
-        patternCharIndex == UDAT_STANDALONE_MONTH_FIELD ||
-        patternCharIndex == UDAT_QUARTER_FIELD ||
-        patternCharIndex == UDAT_STANDALONE_QUARTER_FIELD ||
-        patternCharIndex == UDAT_YEAR_FIELD ||
-        patternCharIndex == UDAT_YEAR_WOY_FIELD ||
-        patternCharIndex == UDAT_FRACTIONAL_SECOND_FIELD)
+    if (patternCharIndex == UDAT_HOUR_OF_DAY1_FIELD ||                       // k
+        patternCharIndex == UDAT_HOUR_OF_DAY0_FIELD ||                       // H
+        patternCharIndex == UDAT_HOUR1_FIELD ||                              // h
+        patternCharIndex == UDAT_HOUR0_FIELD ||                              // K
+        (patternCharIndex == UDAT_DOW_LOCAL_FIELD && count <= 2) ||          // e
+        (patternCharIndex == UDAT_STANDALONE_DAY_FIELD && count <= 2) ||     // c
+        (patternCharIndex == UDAT_MONTH_FIELD && count <= 2) ||              // M
+        (patternCharIndex == UDAT_STANDALONE_MONTH_FIELD && count <= 2) ||   // L
+        (patternCharIndex == UDAT_QUARTER_FIELD && count <= 2) ||            // Q
+        (patternCharIndex == UDAT_STANDALONE_QUARTER_FIELD && count <= 2) || // q
+        patternCharIndex == UDAT_YEAR_FIELD ||                               // y
+        patternCharIndex == UDAT_YEAR_WOY_FIELD ||                           // Y
+        patternCharIndex == UDAT_YEAR_NAME_FIELD ||                          // U (falls back to numeric)
+        (patternCharIndex == UDAT_ERA_FIELD && isChineseCalendar) ||         // G
+        patternCharIndex == UDAT_FRACTIONAL_SECOND_FIELD)                    // S
     {
         int32_t parseStart = pos.getIndex();
         // It would be good to unify this with the obeyCount logic below,
         // but that's going to be difficult.
         const UnicodeString* src;
 
-        if (obeyCount) {
-            if ((start+count) > text.length()) {
-                return -start;
+        UBool parsedNumericLeapMonth = FALSE;
+        if (numericLeapMonthFormatter != NULL && (patternCharIndex == UDAT_MONTH_FIELD || patternCharIndex == UDAT_STANDALONE_MONTH_FIELD)) {
+            int32_t argCount;
+            Formattable * args = numericLeapMonthFormatter->parse(text, pos, argCount);
+            if (args != NULL && argCount == 1 && pos.getIndex() > parseStart && args[0].isNumeric()) {
+                parsedNumericLeapMonth = TRUE;
+                number.setLong(args[0].getLong());
+                cal.set(UCAL_IS_LEAP_MONTH, 1);
+                delete[] args;
+            } else {
+                pos.setIndex(parseStart);
+                cal.set(UCAL_IS_LEAP_MONTH, 0);
             }
-
-            text.extractBetween(0, start + count, temp);
-            src = &temp;
-        } else {
-            src = &text;
         }
 
-        parseInt(*src, number, pos, allowNegative,currentNumberFormat);
+        if (!parsedNumericLeapMonth) {
+            if (obeyCount) {
+                if ((start+count) > text.length()) {
+                    return -start;
+                }
+
+                text.extractBetween(0, start + count, temp);
+                src = &temp;
+            } else {
+                src = &text;
+            }
+
+            parseInt(*src, number, pos, allowNegative,currentNumberFormat);
+        }
 
         int32_t txtLoc = pos.getIndex();
 
@@ -2601,14 +2474,20 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
             else {
                 txtLoc = checkIntSuffix(text, txtLoc, patLoc+1, FALSE);
             }
-            
+
             // Check the range of the value
-            int32_t bias = gFieldRangeBias[patternCharIndex];
-            
-            if (bias >= 0 && (value > cal.getMaximum(field) + bias || value < cal.getMinimum(field) + bias)) {
-                return -start;
+            if (!lenient) {
+                int32_t bias = gFieldRangeBias[patternCharIndex];
+                if (bias >= 0 && (value > cal.getMaximum(field) + bias || value < cal.getMinimum(field) + bias)) {
+                    return -start;
+                }
+            } else {
+                int32_t bias = gFieldRangeBiasLenient[patternCharIndex];
+                if (bias >= 0 && (value > cal.getMaximum(field) + bias)) {
+                    return -start;
+                }
             }
-            
+
             pos.setIndex(txtLoc);
         }
     }
@@ -2638,26 +2517,6 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
             
             break;
             
-        case UDAT_DOW_LOCAL_FIELD:
-        case UDAT_STANDALONE_DAY_FIELD:
-        case UDAT_MONTH_FIELD:
-        case UDAT_STANDALONE_MONTH_FIELD:
-        case UDAT_QUARTER_FIELD:
-        case UDAT_STANDALONE_QUARTER_FIELD:
-            // in strict mode, these can only
-            // be a number if count <= 2
-            if (!lenient && gotNumber && count > 2) {
-                // We have a string pattern in strict mode
-                // but the input parsed as a number. Ignore
-                // the fact that the input parsed as a number
-                // and try to match it as a string. (Some
-                // locales have numbers for the month names.)
-                gotNumber = FALSE;
-                pos.setIndex(start);
-            }
-            
-            break;
-            
         default:
             // we check the rest of the fields below.
             break;
@@ -2665,12 +2524,19 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
 
     switch (patternCharIndex) {
     case UDAT_ERA_FIELD:
+        if (isChineseCalendar) {
+            if (!gotNumber) {
+                return -start;
+            }
+            cal.set(UCAL_ERA, value);
+            return pos.getIndex();
+        }
         if (count == 5) {
-            ps = matchString(text, start, UCAL_ERA, fSymbols->fNarrowEras, fSymbols->fNarrowErasCount, cal);
+            ps = matchString(text, start, UCAL_ERA, fSymbols->fNarrowEras, fSymbols->fNarrowErasCount, NULL, cal);
         } else if (count == 4) {
-            ps = matchString(text, start, UCAL_ERA, fSymbols->fEraNames, fSymbols->fEraNamesCount, cal);
+            ps = matchString(text, start, UCAL_ERA, fSymbols->fEraNames, fSymbols->fEraNamesCount, NULL, cal);
         } else {
-            ps = matchString(text, start, UCAL_ERA, fSymbols->fEras, fSymbols->fErasCount, cal);
+            ps = matchString(text, start, UCAL_ERA, fSymbols->fEras, fSymbols->fErasCount, NULL, cal);
         }
 
         // check return position, if it equals -start, then matchString error
@@ -2688,7 +2554,9 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
         // we made adjustments to place the 2-digit year in the proper
         // century, for parsed strings from "00" to "99".  Any other string
         // is treated literally:  "2250", "-1", "1", "002".
-        if ((pos.getIndex() - start) == 2
+        if (fDateOverride.compare(hebr)==0 && value < 1000) {
+            value += 5000;
+        } else if ((pos.getIndex() - start) == 2 && !isChineseCalendar
             && u_isdigit(text.charAt(start))
             && u_isdigit(text.charAt(start+1)))
         {
@@ -2723,7 +2591,9 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
 
     case UDAT_YEAR_WOY_FIELD:
         // Comment is the same as for UDAT_Year_FIELDs - look above
-        if ((pos.getIndex() - start) == 2
+        if (fDateOverride.compare(hebr)==0 && value < 1000) {
+            value += 5000;
+        } else if ((pos.getIndex() - start) == 2
             && u_isdigit(text.charAt(start))
             && u_isdigit(text.charAt(start+1))
             && fHaveDefaultCentury )
@@ -2736,7 +2606,21 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
         cal.set(UCAL_YEAR_WOY, value);
         return pos.getIndex();
 
+    case UDAT_YEAR_NAME_FIELD:
+        if (fSymbols->fShortYearNames != NULL) {
+            int32_t newStart = matchString(text, start, UCAL_YEAR, fSymbols->fShortYearNames, fSymbols->fShortYearNamesCount, NULL, cal);
+            if (newStart > 0) {
+                return newStart;
+            }
+        }
+        if (gotNumber && (lenient || value > fSymbols->fShortYearNamesCount)) {
+            cal.set(UCAL_YEAR, value);
+            return pos.getIndex();
+        }
+        return -start;
+
     case UDAT_MONTH_FIELD:
+    case UDAT_STANDALONE_MONTH_FIELD:
         if (gotNumber) // i.e., M or MM.
         {
             // When parsing month numbers from the Hebrew Calendar, we might need to adjust the month depending on whether
@@ -2756,46 +2640,45 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
                 }
             } else {
                 // Don't want to parse the month if it is a string
-                // while pattern uses numeric style: M or MM.
+                // while pattern uses numeric style: M/MM, L/LL
                 // [We computed 'value' above.]
                 cal.set(UCAL_MONTH, value - 1);
             }
             return pos.getIndex();
         } else {
-            // count >= 3 // i.e., MMM or MMMM
-            // Want to be able to parse both short and long forms.
-            // Try count == 4 first:
-            int32_t newStart = 0;
-
-            if ((newStart = matchString(text, start, UCAL_MONTH,
-                                      fSymbols->fMonths, fSymbols->fMonthsCount, cal)) > 0)
-                return newStart;
-            else // count == 4 failed, now try count == 3
-                return matchString(text, start, UCAL_MONTH,
-                                   fSymbols->fShortMonths, fSymbols->fShortMonthsCount, cal);
-        }
-
-    case UDAT_STANDALONE_MONTH_FIELD:
-        if (gotNumber) // i.e., L or LL.
-        {
-            // Don't want to parse the month if it is a string
-            // while pattern uses numeric style: M or MM.
-            // [We computed 'value' above.]
-            cal.set(UCAL_MONTH, value - 1);
-            return pos.getIndex();
-        } else {
-            // count >= 3 // i.e., LLL or LLLL
+            // count >= 3 // i.e., MMM/MMMM, LLL/LLLL
             // Want to be able to parse both short and long forms.
             // Try count == 4 first:
+            UnicodeString * wideMonthPat = NULL;
+            UnicodeString * shortMonthPat = NULL;
+            if (fSymbols->fLeapMonthPatterns != NULL && fSymbols->fLeapMonthPatternsCount >= DateFormatSymbols::kMonthPatternsCount) {
+                if (patternCharIndex==UDAT_MONTH_FIELD) {
+                    wideMonthPat = &fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternFormatWide];
+                    shortMonthPat = &fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternFormatAbbrev];
+                } else {
+                    wideMonthPat = &fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternStandaloneWide];
+                    shortMonthPat = &fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternStandaloneAbbrev];
+                }
+            }
             int32_t newStart = 0;
-
-            if ((newStart = matchString(text, start, UCAL_MONTH,
-                                      fSymbols->fStandaloneMonths, fSymbols->fStandaloneMonthsCount, cal)) > 0)
+            if (patternCharIndex==UDAT_MONTH_FIELD) {
+                newStart = matchString(text, start, UCAL_MONTH, fSymbols->fMonths, fSymbols->fMonthsCount, wideMonthPat, cal); // try MMMM
+                if (newStart > 0) {
+                    return newStart;
+                }
+                newStart = matchString(text, start, UCAL_MONTH, fSymbols->fShortMonths, fSymbols->fShortMonthsCount, shortMonthPat, cal); // try MMM
+            } else {
+                newStart = matchString(text, start, UCAL_MONTH, fSymbols->fStandaloneMonths, fSymbols->fStandaloneMonthsCount, wideMonthPat, cal); // try LLLL
+                if (newStart > 0) {
+                    return newStart;
+                }
+                newStart = matchString(text, start, UCAL_MONTH, fSymbols->fStandaloneShortMonths, fSymbols->fStandaloneShortMonthsCount, shortMonthPat, cal); // try LLL
+            }
+            if (newStart > 0 || !lenient)  // currently we do not try to parse MMMMM/LLLLL: #8860
                 return newStart;
-            else // count == 4 failed, now try count == 3
-                return matchString(text, start, UCAL_MONTH,
-                                   fSymbols->fStandaloneShortMonths, fSymbols->fStandaloneShortMonthsCount, cal);
+            // else we allowing parsing as number, below
         }
+        break;
 
     case UDAT_HOUR_OF_DAY1_FIELD:
         // [We computed 'value' above.]
@@ -2842,17 +2725,21 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
             // Try count == 4 (EEEE) first:
             int32_t newStart = 0;
             if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK,
-                                      fSymbols->fWeekdays, fSymbols->fWeekdaysCount, cal)) > 0)
+                                      fSymbols->fWeekdays, fSymbols->fWeekdaysCount, NULL, cal)) > 0)
                 return newStart;
             // EEEE failed, now try EEE
             else if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK,
-                                   fSymbols->fShortWeekdays, fSymbols->fShortWeekdaysCount, cal)) > 0)
+                                   fSymbols->fShortWeekdays, fSymbols->fShortWeekdaysCount, NULL, cal)) > 0)
                 return newStart;
             // EEE failed, now try EEEEE
-            else
-                return matchString(text, start, UCAL_DAY_OF_WEEK,
-                                   fSymbols->fNarrowWeekdays, fSymbols->fNarrowWeekdaysCount, cal);
+            else if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK,
+                                   fSymbols->fNarrowWeekdays, fSymbols->fNarrowWeekdaysCount, NULL, cal)) > 0)
+                return newStart;
+            else if (!lenient || patternCharIndex == UDAT_DAY_OF_WEEK_FIELD)
+                return newStart;
+            // else we allowing parsing as number, below
         }
+        break;
 
     case UDAT_STANDALONE_DAY_FIELD:
         {
@@ -2866,15 +2753,19 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
             // Try count == 4 (cccc) first:
             int32_t newStart = 0;
             if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK,
-                                      fSymbols->fStandaloneWeekdays, fSymbols->fStandaloneWeekdaysCount, cal)) > 0)
+                                      fSymbols->fStandaloneWeekdays, fSymbols->fStandaloneWeekdaysCount, NULL, cal)) > 0)
+                return newStart;
+            else if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK,
+                                          fSymbols->fStandaloneShortWeekdays, fSymbols->fStandaloneShortWeekdaysCount, NULL, cal)) > 0)
                 return newStart;
-            else // cccc failed, now try ccc
-                return matchString(text, start, UCAL_DAY_OF_WEEK,
-                                   fSymbols->fStandaloneShortWeekdays, fSymbols->fStandaloneShortWeekdaysCount, cal);
+            else if (!lenient)
+                return newStart;
+            // else we allowing parsing as number, below
         }
+        break;
 
     case UDAT_AM_PM_FIELD:
-        return matchString(text, start, UCAL_AM_PM, fSymbols->fAmPms, fSymbols->fAmPmsCount, cal);
+        return matchString(text, start, UCAL_AM_PM, fSymbols->fAmPms, fSymbols->fAmPmsCount, NULL, cal);
 
     case UDAT_HOUR1_FIELD:
         // [We computed 'value' above.]
@@ -2886,7 +2777,7 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
     case UDAT_HOUR0_FIELD:
         cal.set(UCAL_HOUR, value);
         return pos.getIndex();
-            
+
     case UDAT_QUARTER_FIELD:
         if (gotNumber) // i.e., Q or QQ.
         {
@@ -2904,10 +2795,14 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
             if ((newStart = matchQuarterString(text, start, UCAL_MONTH,
                                       fSymbols->fQuarters, fSymbols->fQuartersCount, cal)) > 0)
                 return newStart;
-            else // count == 4 failed, now try count == 3
-                return matchQuarterString(text, start, UCAL_MONTH,
-                                   fSymbols->fShortQuarters, fSymbols->fShortQuartersCount, cal);
+            else if ((newStart = matchQuarterString(text, start, UCAL_MONTH,
+                                          fSymbols->fShortQuarters, fSymbols->fShortQuartersCount, cal)) > 0)
+                return newStart;
+            else if (!lenient)
+                return newStart;
+            // else we allowing parsing as number, below
         }
+        break;
 
     case UDAT_STANDALONE_QUARTER_FIELD:
         if (gotNumber) // i.e., q or qq.
@@ -2926,207 +2821,144 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
             if ((newStart = matchQuarterString(text, start, UCAL_MONTH,
                                       fSymbols->fStandaloneQuarters, fSymbols->fStandaloneQuartersCount, cal)) > 0)
                 return newStart;
-            else // count == 4 failed, now try count == 3
-                return matchQuarterString(text, start, UCAL_MONTH,
-                                   fSymbols->fStandaloneShortQuarters, fSymbols->fStandaloneShortQuartersCount, cal);
+            else if ((newStart = matchQuarterString(text, start, UCAL_MONTH,
+                                          fSymbols->fStandaloneShortQuarters, fSymbols->fStandaloneShortQuartersCount, cal)) > 0)
+                return newStart;
+            else if (!lenient)
+                return newStart;
+            // else we allowing parsing as number, below
         }
+        break;
 
     case UDAT_TIMEZONE_FIELD:
-    case UDAT_TIMEZONE_RFC_FIELD:
-    case UDAT_TIMEZONE_GENERIC_FIELD:
-    case UDAT_TIMEZONE_SPECIAL_FIELD:
         {
-            int32_t offset = 0;
-            UBool parsed = FALSE;
-
-            // Step 1
-            // Check if this is a long GMT offset string (either localized or default)
-            offset = parseGMT(text, pos);
-            if (pos.getIndex() - start > 0) {
-                parsed = TRUE;
-            }
-            if (!parsed) {
-                // Step 2
-                // Check if this is an RFC822 time zone offset.
-                // ICU supports the standard RFC822 format [+|-]HHmm
-                // and its extended form [+|-]HHmmSS.
-                do {
-                    int32_t sign = 0;
-                    UChar signChar = text.charAt(start);
-                    if (signChar == (UChar)0x002B /* '+' */) {
-                        sign = 1;
-                    } else if (signChar == (UChar)0x002D /* '-' */) {
-                        sign = -1;
-                    } else {
-                        // Not an RFC822 offset string
-                        break;
-                    }
-
-                    // Parse digits
-                    int32_t orgPos = start + 1;
-                    pos.setIndex(orgPos);
-                    parseInt(text, number, 6, pos, FALSE,currentNumberFormat);
-                    int32_t numLen = pos.getIndex() - orgPos;
-                    if (numLen <= 0) {
-                        break;
-                    }
-
-                    // Followings are possible format (excluding sign char)
-                    // HHmmSS
-                    // HmmSS
-                    // HHmm
-                    // Hmm
-                    // HH
-                    // H
-                    int32_t val = number.getLong();
-                    int32_t hour = 0, min = 0, sec = 0;
-                    switch(numLen) {
-                    case 1: // H
-                    case 2: // HH
-                        hour = val;
-                        break;
-                    case 3: // Hmm
-                    case 4: // HHmm
-                        hour = val / 100;
-                        min = val % 100;
-                        break;
-                    case 5: // Hmmss
-                    case 6: // HHmmss
-                        hour = val / 10000;
-                        min = (val % 10000) / 100;
-                        sec = val % 100;
-                        break;
-                    }
-                    if (hour > 23 || min > 59 || sec > 59) {
-                        // Invalid value range
-                        break;
-                    }
-                    offset = (((hour * 60) + min) * 60 + sec) * 1000 * sign;
-                    parsed = TRUE;
-                } while (FALSE);
-
-                if (!parsed) {
-                    // Failed to parse.  Reset the position.
-                    pos.setIndex(start);
-                }
+            UTimeZoneFormatTimeType tzTimeType = UTZFMT_TIME_TYPE_UNKNOWN;
+            UTimeZoneFormatStyle style = (count < 4) ? UTZFMT_STYLE_SPECIFIC_SHORT : UTZFMT_STYLE_SPECIFIC_LONG;
+            TimeZone *tz  = tzFormat()->parse(style, text, pos, tzParseOptions, &tzTimeType);
+            if (tz != NULL) {
+                ((SimpleDateFormat*)this)->tztype = tzTimeType;
+                cal.adoptTimeZone(tz);
+                return pos.getIndex();
             }
-
-            if (parsed) {
-                // offset was successfully parsed as either a long GMT string or RFC822 zone offset
-                // string.  Create normalized zone ID for the offset.
-
-                UnicodeString tzID(gGmt);
-                formatRFC822TZ(tzID, offset);
-                //TimeZone *customTZ = TimeZone::createTimeZone(tzID);
-                TimeZone *customTZ = new SimpleTimeZone(offset, tzID);    // faster than TimeZone::createTimeZone
-                cal.adoptTimeZone(customTZ);
-
+        }
+        break;
+    case UDAT_TIMEZONE_RFC_FIELD:
+        {
+            UTimeZoneFormatTimeType tzTimeType = UTZFMT_TIME_TYPE_UNKNOWN;
+            UTimeZoneFormatStyle style = (count < 4) ? UTZFMT_STYLE_RFC822 : ((count == 5) ? UTZFMT_STYLE_ISO8601: UTZFMT_STYLE_LOCALIZED_GMT);
+            TimeZone *tz  = tzFormat()->parse(style, text, pos, &tzTimeType);
+            if (tz != NULL) {
+                ((SimpleDateFormat*)this)->tztype = tzTimeType;
+                cal.adoptTimeZone(tz);
                 return pos.getIndex();
             }
-
-            // Step 3
-            // At this point, check for named time zones by looking through
-            // the locale data from the DateFormatZoneData strings.
-            // Want to be able to parse both short and long forms.
-            // optimize for calendar's current time zone
-            const ZoneStringFormat *zsf = fSymbols->getZoneStringFormat();
-            if (zsf) {
-                UErrorCode status = U_ZERO_ERROR;
-                const ZoneStringInfo *zsinfo = NULL;
-                int32_t matchLen;
-
-                switch (patternCharIndex) {
-                    case UDAT_TIMEZONE_FIELD: // 'z'
-                        if (count < 4) {
-                            zsinfo = zsf->findSpecificShort(text, start, matchLen, status);
-                        } else {
-                            zsinfo = zsf->findSpecificLong(text, start, matchLen, status);
-                        }
-                        break;
-                    case UDAT_TIMEZONE_GENERIC_FIELD: // 'v'
-                        if (count == 1) {
-                            zsinfo = zsf->findGenericShort(text, start, matchLen, status);
-                        } else if (count == 4) {
-                            zsinfo = zsf->findGenericLong(text, start, matchLen, status);
-                        }
-                        break;
-                    case UDAT_TIMEZONE_SPECIAL_FIELD: // 'V'
-                        if (count == 1) {
-                            zsinfo = zsf->findSpecificShort(text, start, matchLen, status);
-                        } else if (count == 4) {
-                            zsinfo = zsf->findGenericLocation(text, start, matchLen, status);
-                        }
-                        break;
-                    default:
-                        break;
-                }
-
-                if (U_SUCCESS(status) && zsinfo != NULL) {
-                    if (zsinfo->isStandard()) {
-                        ((SimpleDateFormat*)this)->tztype = TZTYPE_STD;
-                    } else if (zsinfo->isDaylight()) {
-                        ((SimpleDateFormat*)this)->tztype = TZTYPE_DST;
-                    }
-                    UnicodeString tzid;
-                    zsinfo->getID(tzid);
-
-                    UnicodeString current;
-                    cal.getTimeZone().getID(current);
-                    if (tzid != current) {
-                        TimeZone *tz = TimeZone::createTimeZone(tzid);
-                        cal.adoptTimeZone(tz);
-                    }
-                    return start + matchLen;
-                }
+            return -start;
+        }
+    case UDAT_TIMEZONE_GENERIC_FIELD:
+        {
+            UTimeZoneFormatTimeType tzTimeType = UTZFMT_TIME_TYPE_UNKNOWN;
+            UTimeZoneFormatStyle style = (count < 4) ? UTZFMT_STYLE_GENERIC_SHORT : UTZFMT_STYLE_GENERIC_LONG;
+            TimeZone *tz  = tzFormat()->parse(style, text, pos, tzParseOptions, &tzTimeType);
+            if (tz != NULL) {
+                ((SimpleDateFormat*)this)->tztype = tzTimeType;
+                cal.adoptTimeZone(tz);
+                return pos.getIndex();
             }
-            // Step 4
-            // Final attempt - is this standalone GMT/UT/UTC?
-            int32_t gmtLen = 0;
-            if (text.compare(start, kGmtLen, gGmt) == 0) {
-                gmtLen = kGmtLen;
-            } else if (text.compare(start, kUtcLen, gUtc) == 0) {
-                gmtLen = kUtcLen;
-            } else if (text.compare(start, kUtLen, gUt) == 0) {
-                gmtLen = kUtLen;
-            }
-            if (gmtLen > 0) {
-                TimeZone *tz = TimeZone::createTimeZone(UnicodeString("Etc/GMT"));
+            return -start;
+        }
+    case UDAT_TIMEZONE_SPECIAL_FIELD:
+        {
+            UTimeZoneFormatTimeType tzTimeType = UTZFMT_TIME_TYPE_UNKNOWN;
+            UTimeZoneFormatStyle style = (count < 4) ? UTZFMT_STYLE_SPECIFIC_SHORT : UTZFMT_STYLE_GENERIC_LOCATION;
+            TimeZone *tz  = tzFormat()->parse(style, text, pos, &tzTimeType);
+            if (tz != NULL) {
+                ((SimpleDateFormat*)this)->tztype = tzTimeType;
                 cal.adoptTimeZone(tz);
-                return start + gmtLen;
+                return pos.getIndex();
             }
-
-            // complete failure
             return -start;
         }
 
     default:
         // Handle "generic" fields
-        int32_t parseStart = pos.getIndex();
-        const UnicodeString* src;
-        if (obeyCount) {
-            if ((start+count) > text.length()) {
+        // this is now handled below, outside the switch block
+        break;
+    }
+    // Handle "generic" fields:
+    // switch default case now handled here (outside switch block) to allow
+    // parsing of some string fields as digits for lenient case
+
+    int32_t parseStart = pos.getIndex();
+    const UnicodeString* src;
+    if (obeyCount) {
+        if ((start+count) > text.length()) {
+            return -start;
+        }
+        text.extractBetween(0, start + count, temp);
+        src = &temp;
+    } else {
+        src = &text;
+    }
+    parseInt(*src, number, pos, allowNegative,currentNumberFormat);
+    if (pos.getIndex() != parseStart) {
+        int32_t value = number.getLong();
+
+        // Don't need suffix processing here (as in number processing at the beginning of the function);
+        // the new fields being handled as numeric values (month, weekdays, quarters) should not have suffixes.
+
+        // Check the range of the value
+        if (!lenient) {
+            int32_t bias = gFieldRangeBias[patternCharIndex];
+            if (bias >= 0 && (value > cal.getMaximum(field) + bias || value < cal.getMinimum(field) + bias)) {
                 return -start;
             }
-            text.extractBetween(0, start + count, temp);
-            src = &temp;
         } else {
-            src = &text;
-        }
-        parseInt(*src, number, pos, allowNegative,currentNumberFormat);
-        if (pos.getIndex() != parseStart) {
-            int32_t value = number.getLong();
-            
-            // Check the range of the value
-            int32_t bias = gFieldRangeBias[patternCharIndex];
-            
-            if (bias < 0 || (value >= cal.getMinimum(field) + bias && value <= cal.getMaximum(field) + bias)) {
-                cal.set(field, value);
-                return pos.getIndex();
+            int32_t bias = gFieldRangeBiasLenient[patternCharIndex];
+            if (bias >= 0 && (value > cal.getMaximum(field) + bias)) {
+                return -start;
             }
         }
 
-        return -start;
+        // For the following, need to repeat some of the "if (gotNumber)" code above:
+        // UDAT_[STANDALONE_]MONTH_FIELD, UDAT_DOW_LOCAL_FIELD, UDAT_STANDALONE_DAY_FIELD,
+        // UDAT_[STANDALONE_]QUARTER_FIELD
+        switch (patternCharIndex) {
+        case UDAT_MONTH_FIELD:
+            // See notes under UDAT_MONTH_FIELD case above
+            if (!strcmp(cal.getType(),"hebrew")) {
+                HebrewCalendar *hc = (HebrewCalendar*)&cal;
+                if (cal.isSet(UCAL_YEAR)) {
+                   UErrorCode status = U_ZERO_ERROR;
+                   if (!hc->isLeapYear(hc->get(UCAL_YEAR,status)) && value >= 6) {
+                       cal.set(UCAL_MONTH, value);
+                   } else {
+                       cal.set(UCAL_MONTH, value - 1);
+                   }
+                } else {
+                    saveHebrewMonth = value;
+                }
+            } else {
+                cal.set(UCAL_MONTH, value - 1);
+            }
+            break;
+        case UDAT_STANDALONE_MONTH_FIELD:
+            cal.set(UCAL_MONTH, value - 1);
+            break;
+        case UDAT_DOW_LOCAL_FIELD:
+        case UDAT_STANDALONE_DAY_FIELD:
+            cal.set(UCAL_DOW_LOCAL, value);
+            break;
+        case UDAT_QUARTER_FIELD:
+        case UDAT_STANDALONE_QUARTER_FIELD:
+             cal.set(UCAL_MONTH, (value - 1) * 3);
+             break;
+        default:
+            cal.set(field, value);
+            break;
+        }
+        return pos.getIndex();
     }
+    return -start;
 }
 
 /**
@@ -3154,7 +2986,7 @@ void SimpleDateFormat::parseInt(const UnicodeString& text,
     DecimalFormat* df = NULL;
     if (!allowNegative && (df = dynamic_cast<DecimalFormat*>(fmt)) != NULL) {
         df->getNegativePrefix(oldPrefix);
-        df->setNegativePrefix(SUPPRESS_NEGATIVE_PREFIX);
+        df->setNegativePrefix(UnicodeString(TRUE, SUPPRESS_NEGATIVE_PREFIX, -1));
     }
     int32_t oldPos = pos.getIndex();
     fmt->parse(text, number, pos);
@@ -3240,7 +3072,9 @@ UnicodeString&
 SimpleDateFormat::toLocalizedPattern(UnicodeString& result,
                                      UErrorCode& status) const
 {
-    translatePattern(fPattern, result, DateFormatSymbols::getPatternUChars(), fSymbols->fLocalPatternChars, status);
+    translatePattern(fPattern, result,
+                     UnicodeString(DateFormatSymbols::getPatternUChars()),
+                     fSymbols->fLocalPatternChars, status);
     return result;
 }
 
@@ -3258,7 +3092,9 @@ void
 SimpleDateFormat::applyLocalizedPattern(const UnicodeString& pattern,
                                         UErrorCode &status)
 {
-    translatePattern(pattern, fPattern, fSymbols->fLocalPatternChars, DateFormatSymbols::getPatternUChars(), status);
+    translatePattern(pattern, fPattern,
+                     fSymbols->fLocalPatternChars,
+                     UnicodeString(DateFormatSymbols::getPatternUChars()), status);
 }
 
 //----------------------------------------------------------------------
@@ -3286,6 +3122,27 @@ SimpleDateFormat::setDateFormatSymbols(const DateFormatSymbols& newFormatSymbols
     fSymbols = new DateFormatSymbols(newFormatSymbols);
 }
 
+//----------------------------------------------------------------------
+const TimeZoneFormat*
+SimpleDateFormat::getTimeZoneFormat(void) const {
+    return (const TimeZoneFormat*)tzFormat();
+}
+
+//----------------------------------------------------------------------
+void
+SimpleDateFormat::adoptTimeZoneFormat(TimeZoneFormat* timeZoneFormatToAdopt)
+{
+    delete fTimeZoneFormat;
+    fTimeZoneFormat = timeZoneFormatToAdopt;
+}
+
+//----------------------------------------------------------------------
+void
+SimpleDateFormat::setTimeZoneFormat(const TimeZoneFormat& newTimeZoneFormat)
+{
+    delete fTimeZoneFormat;
+    fTimeZoneFormat = new TimeZoneFormat(newTimeZoneFormat);
+}
 
 //----------------------------------------------------------------------
 
@@ -3304,6 +3161,37 @@ void SimpleDateFormat::adoptCalendar(Calendar* calendarToAdopt)
 //----------------------------------------------------------------------
 
 
+void SimpleDateFormat::setDefaultContext(UDateFormatContextType type,
+                                         UDateFormatContextValue value, UErrorCode& status)
+{
+    if (U_FAILURE(status))
+        return;
+    if (type != UDAT_CAPITALIZATION) {
+        status = U_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+    fDefaultCapitalizationContext = value;
+}
+
+
+//----------------------------------------------------------------------
+
+
+int32_t SimpleDateFormat::getDefaultContext(UDateFormatContextType type, UErrorCode& status) const
+{
+    if (U_FAILURE(status))
+        return 0;
+    if (type != UDAT_CAPITALIZATION) {
+        status = U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+    return (int32_t)fDefaultCapitalizationContext;
+}
+
+
+//----------------------------------------------------------------------
+
+
 UBool
 SimpleDateFormat::isFieldUnitIgnored(UCalendarDateFields field) const {
     return isFieldUnitIgnored(fPattern, field);
@@ -3427,12 +3315,12 @@ SimpleDateFormat::compareSimpleAffix(const UnicodeString& affix,
     for (int32_t i=0; i<affix.length(); ) {
         UChar32 c = affix.char32At(i);
         int32_t len = U16_LENGTH(c);
-        if (uprv_isRuleWhiteSpace(c)) {
+        if (PatternProps::isWhiteSpace(c)) {
             // We may have a pattern like: \u200F \u0020
             //        and input text like: \u200F \u0020
-            // Note that U+200F and U+0020 are RuleWhiteSpace but only
+            // Note that U+200F and U+0020 are Pattern_White_Space but only
             // U+0020 is UWhiteSpace.  So we have to first do a direct
-            // match of the run of RULE whitespace in the pattern,
+            // match of the run of Pattern_White_Space in the pattern,
             // then match any extra characters.
             UBool literalMatch = FALSE;
             while (pos < input.length() &&
@@ -3445,13 +3333,13 @@ SimpleDateFormat::compareSimpleAffix(const UnicodeString& affix,
                 }
                 c = affix.char32At(i);
                 len = U16_LENGTH(c);
-                if (!uprv_isRuleWhiteSpace(c)) {
+                if (!PatternProps::isWhiteSpace(c)) {
                     break;
                 }
             }
 
             // Advance over run in pattern
-            i = skipRuleWhiteSpace(affix, i);
+            i = skipPatternWhiteSpace(affix, i);
 
             // Advance over run in input text
             // Must see at least one white space char in input,
@@ -3482,15 +3370,9 @@ SimpleDateFormat::compareSimpleAffix(const UnicodeString& affix,
 //----------------------------------------------------------------------
 
 int32_t
-SimpleDateFormat::skipRuleWhiteSpace(const UnicodeString& text, int32_t pos) const {
-    while (pos < text.length()) {
-        UChar32 c = text.char32At(pos);
-        if (!uprv_isRuleWhiteSpace(c)) {
-            break;
-        }
-        pos += U16_LENGTH(c);
-    }
-    return pos;
+SimpleDateFormat::skipPatternWhiteSpace(const UnicodeString& text, int32_t pos) const {
+    const UChar* s = text.getBuffer();
+    return (int32_t)(PatternProps::skipWhiteSpace(s + pos, text.length() - pos) - s);
 }
 
 //----------------------------------------------------------------------
@@ -3507,6 +3389,29 @@ SimpleDateFormat::skipUWhiteSpace(const UnicodeString& text, int32_t pos) const
     return pos;
 }
 
+//----------------------------------------------------------------------
+
+// Lazy TimeZoneFormat instantiation, semantically const.
+TimeZoneFormat *
+SimpleDateFormat::tzFormat() const {
+    if (fTimeZoneFormat == NULL) {
+        umtx_lock(&LOCK);
+        {
+            if (fTimeZoneFormat == NULL) {
+                UErrorCode status = U_ZERO_ERROR;
+                TimeZoneFormat *tzfmt = TimeZoneFormat::createInstance(fLocale, status);
+                if (U_FAILURE(status)) {
+                    return NULL;
+                }
+
+                const_cast<SimpleDateFormat *>(this)->fTimeZoneFormat = tzfmt;
+            }
+        }
+        umtx_unlock(&LOCK);
+    }
+    return fTimeZoneFormat;
+}
+
 U_NAMESPACE_END
 
 #endif /* #if !UCONFIG_NO_FORMATTING */