]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/i18n/smpdtfmt.cpp
ICU-461.12.tar.gz
[apple/icu.git] / icuSources / i18n / smpdtfmt.cpp
index 5b93dc4912a342f67e97017d9a83e9352d68097c..8dde9ac16a94832b44ede63ec0fe888a556e3171 100644 (file)
@@ -1,6 +1,6 @@
 /*
 *******************************************************************************
-* Copyright (C) 1997-2009, International Business Machines Corporation and    *
+* Copyright (C) 1997-2010, International Business Machines Corporation and    *
 * others. All Rights Reserved.                                                *
 *******************************************************************************
 *
@@ -48,7 +48,9 @@
 #include "unicode/vtzone.h"
 #include "olsontz.h"
 #include "util.h"
-#include "gregoimp.h" 
+#include "fphdlimp.h"
+#include "gregoimp.h"
+#include "hebrwcal.h"
 #include "cstring.h"
 #include "uassert.h"
 #include "zstrfmt.h"
@@ -83,15 +85,58 @@ static const UChar gDefGmtNegHmsPat[] = {0x002D, 0x0048, 0x0048, 0x003A, 0x006D,
 static const UChar gDefGmtNegHmPat[]  = {0x002D, 0x0048, 0x0048, 0x003A, 0x006D, 0x006D, 0x0000}; /* -HH:mm */
 static const UChar gDefGmtPosHmsPat[] = {0x002B, 0x0048, 0x0048, 0x003A, 0x006D, 0x006D, 0x003A, 0x0073, 0x0073, 0x0000}; /* +HH:mm:ss */
 static const UChar gDefGmtPosHmPat[]  = {0x002B, 0x0048, 0x0048, 0x003A, 0x006D, 0x006D, 0x0000}; /* +HH:mm */
+static const UChar gUt[]       = {0x0055, 0x0054, 0x0000};  // "UT"
+static const UChar gUtc[]      = {0x0055, 0x0054, 0x0043, 0x0000};  // "UT"
+
 typedef enum GmtPatSize {
     kGmtLen = 3,
     kGmtPatLen = 6,
     kNegHmsLen = 9,
     kNegHmLen = 6,
     kPosHmsLen = 9,
-    kPosHmLen = 6
+    kPosHmLen = 6,
+    kUtLen = 2,
+    kUtcLen = 3
 } GmtPatSize;
 
+// Stuff needed for numbering system overrides
+
+typedef enum OvrStrType {
+    kOvrStrDate = 0,
+    kOvrStrTime = 1,
+    kOvrStrBoth = 2
+} OvrStrType;
+
+static const UDateFormatField kDateFields[] = {
+    UDAT_YEAR_FIELD,
+    UDAT_MONTH_FIELD,
+    UDAT_DATE_FIELD,
+    UDAT_DAY_OF_YEAR_FIELD,
+    UDAT_DAY_OF_WEEK_IN_MONTH_FIELD,
+    UDAT_WEEK_OF_YEAR_FIELD,
+    UDAT_WEEK_OF_MONTH_FIELD,
+    UDAT_YEAR_WOY_FIELD,
+    UDAT_EXTENDED_YEAR_FIELD,
+    UDAT_JULIAN_DAY_FIELD,
+    UDAT_STANDALONE_DAY_FIELD,
+    UDAT_STANDALONE_MONTH_FIELD,
+    UDAT_QUARTER_FIELD,
+    UDAT_STANDALONE_QUARTER_FIELD };
+static const int8_t kDateFieldsCount = 13;
+
+static const UDateFormatField kTimeFields[] = {
+    UDAT_HOUR_OF_DAY1_FIELD,
+    UDAT_HOUR_OF_DAY0_FIELD,
+    UDAT_MINUTE_FIELD,
+    UDAT_SECOND_FIELD,
+    UDAT_FRACTIONAL_SECOND_FIELD,
+    UDAT_HOUR1_FIELD,
+    UDAT_HOUR0_FIELD,
+    UDAT_MILLISECONDS_IN_DAY_FIELD,
+    UDAT_TIMEZONE_RFC_FIELD };
+static const int8_t kTimeFieldsCount = 9;
+
+
 // This is a pattern-of-last-resort used when we can't load a usable pattern out
 // of a resource.
 static const UChar gDefaultPattern[] =
@@ -112,14 +157,6 @@ static const char gDateTimePatternsTag[]="DateTimePatterns";
 
 static const UChar gEtcUTC[] = {0x45, 0x74, 0x63, 0x2F, 0x55, 0x54, 0x43, 0x00}; // "Etc/UTC"
 static const UChar QUOTE = 0x27; // Single quote
-enum {
-    kGMTNegativeHMS = 0,
-    kGMTNegativeHM,
-    kGMTPositiveHMS,
-    kGMTPositiveHM,
-
-    kNumGMTFormatters
-};
 
 /*
  * The field range check bias for each UDateFormatField.
@@ -179,6 +216,17 @@ SimpleDateFormat::~SimpleDateFormat()
             }
         }
         uprv_free(fGMTFormatters);
+
+    }
+    if (fNumberFormatters) {
+        uprv_free(fNumberFormatters);
+    }
+
+    while (fOverrideList) {
+        NSOverride *cur = fOverrideList;
+        fOverrideList = cur->next;
+        delete cur->nf;
+        uprv_free(cur);
     }
 }
 
@@ -187,7 +235,9 @@ SimpleDateFormat::~SimpleDateFormat()
 SimpleDateFormat::SimpleDateFormat(UErrorCode& status)
   :   fLocale(Locale::getDefault()),
       fSymbols(NULL),
-      fGMTFormatters(NULL)
+      fGMTFormatters(NULL),
+      fNumberFormatters(NULL),
+      fOverrideList(NULL)
 {
     construct(kShort, (EStyle) (kShort + kDateOffset), fLocale, status);
     initializeDefaultCentury();
@@ -200,11 +250,37 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
 :   fPattern(pattern),
     fLocale(Locale::getDefault()),
     fSymbols(NULL),
-    fGMTFormatters(NULL)
+    fGMTFormatters(NULL),
+    fNumberFormatters(NULL),
+    fOverrideList(NULL)
+{
+    fDateOverride.setToBogus();
+    fTimeOverride.setToBogus();
+    initializeSymbols(fLocale, initializeCalendar(NULL,fLocale,status), status);
+    initialize(fLocale, status);
+    initializeDefaultCentury();
+
+}
+//----------------------------------------------------------------------
+
+SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
+                                   const UnicodeString& override,
+                                   UErrorCode &status)
+:   fPattern(pattern),
+    fLocale(Locale::getDefault()),
+    fSymbols(NULL),
+    fGMTFormatters(NULL),
+    fNumberFormatters(NULL),
+    fOverrideList(NULL)
 {
+    fDateOverride.setTo(override);
+    fTimeOverride.setToBogus();
     initializeSymbols(fLocale, initializeCalendar(NULL,fLocale,status), status);
     initialize(fLocale, status);
     initializeDefaultCentury();
+
+    processOverrideString(fLocale,override,kOvrStrBoth,status);
+
 }
 
 //----------------------------------------------------------------------
@@ -214,8 +290,14 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
                                    UErrorCode& status)
 :   fPattern(pattern),
     fLocale(locale),
-    fGMTFormatters(NULL)
+    fGMTFormatters(NULL),
+    fNumberFormatters(NULL),
+    fOverrideList(NULL)
 {
+
+    fDateOverride.setToBogus();
+    fTimeOverride.setToBogus();
+
     initializeSymbols(fLocale, initializeCalendar(NULL,fLocale,status), status);
     initialize(fLocale, status);
     initializeDefaultCentury();
@@ -223,14 +305,44 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
 
 //----------------------------------------------------------------------
 
+SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
+                                   const UnicodeString& override,
+                                   const Locale& locale,
+                                   UErrorCode& status)
+:   fPattern(pattern),
+    fLocale(locale),
+    fGMTFormatters(NULL),
+    fNumberFormatters(NULL),
+    fOverrideList(NULL)
+{
+
+    fDateOverride.setTo(override);
+    fTimeOverride.setToBogus();
+
+    initializeSymbols(fLocale, initializeCalendar(NULL,fLocale,status), status);
+    initialize(fLocale, status);
+    initializeDefaultCentury();
+
+    processOverrideString(locale,override,kOvrStrBoth,status);
+
+}
+
+//----------------------------------------------------------------------
+
 SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
                                    DateFormatSymbols* symbolsToAdopt,
                                    UErrorCode& status)
 :   fPattern(pattern),
     fLocale(Locale::getDefault()),
     fSymbols(symbolsToAdopt),
-    fGMTFormatters(NULL)
+    fGMTFormatters(NULL),
+    fNumberFormatters(NULL),
+    fOverrideList(NULL)
 {
+
+    fDateOverride.setToBogus();
+    fTimeOverride.setToBogus();
+
     initializeCalendar(NULL,fLocale,status);
     initialize(fLocale, status);
     initializeDefaultCentury();
@@ -244,8 +356,14 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
 :   fPattern(pattern),
     fLocale(Locale::getDefault()),
     fSymbols(new DateFormatSymbols(symbols)),
-    fGMTFormatters(NULL)
+    fGMTFormatters(NULL),
+    fNumberFormatters(NULL),
+    fOverrideList(NULL)
 {
+
+    fDateOverride.setToBogus();
+    fTimeOverride.setToBogus();
+
     initializeCalendar(NULL, fLocale, status);
     initialize(fLocale, status);
     initializeDefaultCentury();
@@ -260,7 +378,9 @@ SimpleDateFormat::SimpleDateFormat(EStyle timeStyle,
                                    UErrorCode& status)
 :   fLocale(locale),
     fSymbols(NULL),
-    fGMTFormatters(NULL)
+    fGMTFormatters(NULL),
+    fNumberFormatters(NULL),
+    fOverrideList(NULL)
 {
     construct(timeStyle, dateStyle, fLocale, status);
     if(U_SUCCESS(status)) {
@@ -280,7 +400,9 @@ SimpleDateFormat::SimpleDateFormat(const Locale& locale,
 :   fPattern(gDefaultPattern),
     fLocale(locale),
     fSymbols(NULL),
-    fGMTFormatters(NULL)
+    fGMTFormatters(NULL),
+    fNumberFormatters(NULL),
+    fOverrideList(NULL)
 {
     if (U_FAILURE(status)) return;
     initializeSymbols(fLocale, initializeCalendar(NULL, fLocale, status),status);
@@ -297,6 +419,9 @@ SimpleDateFormat::SimpleDateFormat(const Locale& locale,
         }
     }
 
+    fDateOverride.setToBogus();
+    fTimeOverride.setToBogus();
+
     initialize(fLocale, status);
     if(U_SUCCESS(status)) {
       initializeDefaultCentury();
@@ -308,7 +433,9 @@ SimpleDateFormat::SimpleDateFormat(const Locale& locale,
 SimpleDateFormat::SimpleDateFormat(const SimpleDateFormat& other)
 :   DateFormat(other),
     fSymbols(NULL),
-    fGMTFormatters(NULL)
+    fGMTFormatters(NULL),
+    fNumberFormatters(NULL),
+    fOverrideList(NULL)
 {
     *this = other;
 }
@@ -379,6 +506,8 @@ void SimpleDateFormat::construct(EStyle timeStyle,
 
     CalendarData calData(locale, fCalendar?fCalendar->getType():NULL, status);
     UResourceBundle *dateTimePatterns = calData.getByKey(gDateTimePatternsTag, status);
+    UResourceBundle *currentBundle;
+
     if (U_FAILURE(status)) return;
 
     if (ures_getSize(dateTimePatterns) <= kDateTime)
@@ -399,8 +528,10 @@ void SimpleDateFormat::construct(EStyle timeStyle,
         return;
     }
 
-    const UChar *resStr;
-    int32_t resStrLen = 0;
+    const UChar *resStr,*ovrStr;
+    int32_t resStrLen,ovrStrLen = 0;
+    fDateOverride.setToBogus();
+    fTimeOverride.setToBogus();
 
     // if the pattern should include both date and time information, use the date/time
     // pattern string as a guide to tell use how to glue together the appropriate date
@@ -413,7 +544,31 @@ void SimpleDateFormat::construct(EStyle timeStyle,
         // use Formattable::adoptString() so that we can use fastCopyFrom()
         // instead of Formattable::setString()'s unaware, safe, deep string clone
         // see Jitterbug 2296
-        resStr = ures_getStringByIndex(dateTimePatterns, (int32_t)timeStyle, &resStrLen, &status);
+
+        currentBundle = ures_getByIndex(dateTimePatterns, (int32_t)timeStyle, NULL, &status);
+        if (U_FAILURE(status)) {
+           status = U_INVALID_FORMAT_ERROR;
+           return;
+        }
+        switch (ures_getType(currentBundle)) {
+            case URES_STRING: {
+               resStr = ures_getString(currentBundle, &resStrLen, &status);
+               break;
+            }
+            case URES_ARRAY: {
+               resStr = ures_getStringByIndex(currentBundle, 0, &resStrLen, &status);
+               ovrStr = ures_getStringByIndex(currentBundle, 1, &ovrStrLen, &status);
+               fTimeOverride.setTo(TRUE, ovrStr, ovrStrLen);
+               break;
+            }
+            default: {
+               status = U_INVALID_FORMAT_ERROR;
+               ures_close(currentBundle);
+               return;
+            }
+        }
+        ures_close(currentBundle);
+
         UnicodeString *tempus1 = new UnicodeString(TRUE, resStr, resStrLen);
         // NULL pointer check
         if (tempus1 == NULL) {
@@ -421,8 +576,31 @@ void SimpleDateFormat::construct(EStyle timeStyle,
             return;
         }
         timeDateArray[0].adoptString(tempus1);
-        
-        resStr = ures_getStringByIndex(dateTimePatterns, (int32_t)dateStyle, &resStrLen, &status);
+
+        currentBundle = ures_getByIndex(dateTimePatterns, (int32_t)dateStyle, NULL, &status);
+        if (U_FAILURE(status)) {
+           status = U_INVALID_FORMAT_ERROR;
+           return;
+        }
+        switch (ures_getType(currentBundle)) {
+            case URES_STRING: {
+               resStr = ures_getString(currentBundle, &resStrLen, &status);
+               break;
+            }
+            case URES_ARRAY: {
+               resStr = ures_getStringByIndex(currentBundle, 0, &resStrLen, &status);
+               ovrStr = ures_getStringByIndex(currentBundle, 1, &ovrStrLen, &status);
+               fDateOverride.setTo(TRUE, ovrStr, ovrStrLen);
+               break;
+            }
+            default: {
+               status = U_INVALID_FORMAT_ERROR;
+               ures_close(currentBundle);
+               return;
+            }
+        }
+        ures_close(currentBundle);
+
         UnicodeString *tempus2 = new UnicodeString(TRUE, resStr, resStrLen);
         // Null pointer check
         if (tempus2 == NULL) {
@@ -431,21 +609,72 @@ void SimpleDateFormat::construct(EStyle timeStyle,
         }
         timeDateArray[1].adoptString(tempus2);
 
-        resStr = ures_getStringByIndex(dateTimePatterns, (int32_t)kDateTime, &resStrLen, &status);
+        int32_t glueIndex = kDateTime;
+        int32_t patternsSize = ures_getSize(dateTimePatterns);
+        if (patternsSize >= (kDateTimeOffset + kShort + 1)) {
+            // Get proper date time format
+            glueIndex = (int32_t)(kDateTimeOffset + (dateStyle - kDateOffset));
+        }
+
+        resStr = ures_getStringByIndex(dateTimePatterns, glueIndex, &resStrLen, &status);
         MessageFormat::format(UnicodeString(TRUE, resStr, resStrLen), timeDateArray, 2, fPattern, status);
     }
     // if the pattern includes just time data or just date date, load the appropriate
     // pattern string from the resources
     // setTo() - see DateFormatSymbols::assignArray comments
     else if (timeStyle != kNone) {
-        resStr = ures_getStringByIndex(dateTimePatterns, (int32_t)timeStyle, &resStrLen, &status);
+        currentBundle = ures_getByIndex(dateTimePatterns, (int32_t)timeStyle, NULL, &status);
+        if (U_FAILURE(status)) {
+           status = U_INVALID_FORMAT_ERROR;
+           return;
+        }
+        switch (ures_getType(currentBundle)) {
+            case URES_STRING: {
+               resStr = ures_getString(currentBundle, &resStrLen, &status);
+               break;
+            }
+            case URES_ARRAY: {
+               resStr = ures_getStringByIndex(currentBundle, 0, &resStrLen, &status);
+               ovrStr = ures_getStringByIndex(currentBundle, 1, &ovrStrLen, &status);
+               fDateOverride.setTo(TRUE, ovrStr, ovrStrLen);
+               break;
+            }
+            default: {
+               status = U_INVALID_FORMAT_ERROR;
+                ures_close(currentBundle);
+               return;
+            }
+        }
         fPattern.setTo(TRUE, resStr, resStrLen);
+        ures_close(currentBundle);
     }
     else if (dateStyle != kNone) {
-        resStr = ures_getStringByIndex(dateTimePatterns, (int32_t)dateStyle, &resStrLen, &status);
+        currentBundle = ures_getByIndex(dateTimePatterns, (int32_t)dateStyle, NULL, &status);
+        if (U_FAILURE(status)) {
+           status = U_INVALID_FORMAT_ERROR;
+           return;
+        }
+        switch (ures_getType(currentBundle)) {
+            case URES_STRING: {
+               resStr = ures_getString(currentBundle, &resStrLen, &status);
+               break;
+            }
+            case URES_ARRAY: {
+               resStr = ures_getStringByIndex(currentBundle, 0, &resStrLen, &status);
+               ovrStr = ures_getStringByIndex(currentBundle, 1, &ovrStrLen, &status);
+               fDateOverride.setTo(TRUE, ovrStr, ovrStrLen);
+               break;
+            }
+            default: {
+               status = U_INVALID_FORMAT_ERROR;
+               ures_close(currentBundle);
+               return;
+            }
+        }
         fPattern.setTo(TRUE, resStr, resStrLen);
+        ures_close(currentBundle);
     }
-    
+
     // and if it includes _neither_, that's an error
     else
         status = U_INVALID_FORMAT_ERROR;
@@ -500,13 +729,18 @@ SimpleDateFormat::initialize(const Locale& locale,
         // show the decimal point, and recognizes integers only when parsing
 
         fNumberFormat->setGroupingUsed(FALSE);
-        if (fNumberFormat->getDynamicClassID() == DecimalFormat::getStaticClassID())
-            ((DecimalFormat*)fNumberFormat)->setDecimalSeparatorAlwaysShown(FALSE);
+        DecimalFormat* decfmt = dynamic_cast<DecimalFormat*>(fNumberFormat);
+        if (decfmt != NULL) {
+            decfmt->setDecimalSeparatorAlwaysShown(FALSE);
+        }
         fNumberFormat->setParseIntegerOnly(TRUE);
         fNumberFormat->setMinimumFractionDigits(0); // To prevent "Jan 1.00, 1997.00"
-               
-               // TODO: Really, the default should be lenient...
-               fNumberFormat->setParseStrict(FALSE);
+
+        // TODO: Really, the default should be lenient...
+        fNumberFormat->setParseStrict(FALSE);
+
+        initNumberFormatters(locale,status);
+
     }
     else if (U_SUCCESS(status))
     {
@@ -517,7 +751,7 @@ SimpleDateFormat::initialize(const Locale& locale,
 /* Initialize the fields we use to disambiguate ambiguous years. Separate
  * so we can call it from readObject().
  */
-void SimpleDateFormat::initializeDefaultCentury() 
+void SimpleDateFormat::initializeDefaultCentury()
 {
   if(fCalendar) {
     fHaveDefaultCentury = fCalendar->haveDefaultCentury();
@@ -534,7 +768,7 @@ void SimpleDateFormat::initializeDefaultCentury()
 /* Define one-century window into which to disambiguate dates using
  * two-digit years. Make public in JDK 1.2.
  */
-void SimpleDateFormat::parseAmbiguousDatesAsAfter(UDate startDate, UErrorCode& status) 
+void SimpleDateFormat::parseAmbiguousDatesAsAfter(UDate startDate, UErrorCode& status)
 {
     if(U_FAILURE(status)) {
         return;
@@ -543,7 +777,7 @@ void SimpleDateFormat::parseAmbiguousDatesAsAfter(UDate startDate, UErrorCode& s
       status = U_ILLEGAL_ARGUMENT_ERROR;
       return;
     }
-        
+
     fCalendar->setTime(startDate, status);
     if(U_SUCCESS(status)) {
         fHaveDefaultCentury = TRUE;
@@ -551,28 +785,58 @@ void SimpleDateFormat::parseAmbiguousDatesAsAfter(UDate startDate, UErrorCode& s
         fDefaultCenturyStartYear = fCalendar->get(UCAL_YEAR, status);
     }
 }
-    
+
 //----------------------------------------------------------------------
 
 UnicodeString&
 SimpleDateFormat::format(Calendar& cal, UnicodeString& appendTo, FieldPosition& pos) const
 {
-    UErrorCode status = U_ZERO_ERROR;
-    pos.setBeginIndex(0);
-    pos.setEndIndex(0);
+  UErrorCode status = U_ZERO_ERROR;
+  FieldPositionOnlyHandler handler(pos);
+  return _format(cal, appendTo, handler, status);
+}
+
+//----------------------------------------------------------------------
+
+UnicodeString&
+SimpleDateFormat::format(Calendar& cal, UnicodeString& appendTo,
+                         FieldPositionIterator* posIter, UErrorCode& status) const
+{
+  FieldPositionIteratorHandler handler(posIter, status);
+  return _format(cal, appendTo, handler, status);
+}
+
+//----------------------------------------------------------------------
+
+UnicodeString&
+SimpleDateFormat::_format(Calendar& cal, UnicodeString& appendTo, FieldPositionHandler& handler,
+                          UErrorCode& status) const
+{
+    Calendar *workCal = &cal;
+    TimeZone *backupTZ = 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;
+    }
 
     UBool inQuote = FALSE;
     UChar prevCh = 0;
     int32_t count = 0;
-    
+
     // loop through the pattern string character by character
     for (int32_t i = 0; i < fPattern.length() && U_SUCCESS(status); ++i) {
         UChar ch = fPattern[i];
-        
+
         // 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, pos, cal, status);
+            subFormat(appendTo, prevCh, count, handler, *workCal, status);
             count = 0;
         }
         if (ch == QUOTE) {
@@ -584,8 +848,8 @@ SimpleDateFormat::format(Calendar& cal, UnicodeString& appendTo, FieldPosition&
             } else {
                 inQuote = ! inQuote;
             }
-        } 
-        else if ( ! inQuote && ((ch >= 0x0061 /*'a'*/ && ch <= 0x007A /*'z'*/) 
+        }
+        else if ( ! inQuote && ((ch >= 0x0061 /*'a'*/ && ch <= 0x007A /*'z'*/)
                     || (ch >= 0x0041 /*'A'*/ && ch <= 0x005A /*'Z'*/))) {
             // ch is a date-time pattern character to be interpreted
             // by subFormat(); count the number of times it is repeated
@@ -600,31 +864,15 @@ SimpleDateFormat::format(Calendar& cal, UnicodeString& appendTo, FieldPosition&
 
     // Format the last item in the pattern, if any
     if (count > 0) {
-        subFormat(appendTo, prevCh, count, pos, cal, status);
+        subFormat(appendTo, prevCh, count, handler, *workCal, status);
     }
 
-    // and if something failed (e.g., an invalid format character), reset our FieldPosition
-    // to (0, 0) to show that
-    // {sfb} look at this later- are these being set correctly?
-    if (U_FAILURE(status)) {
-        pos.setBeginIndex(0);
-        pos.setEndIndex(0);
+    if (backupTZ != NULL) {
+        // Restore the original time zone
+        fCalendar->adoptTimeZone(backupTZ);
     }
-    
-    return appendTo;
-}
 
-UnicodeString&
-SimpleDateFormat::format(const Formattable& obj, 
-                         UnicodeString& appendTo, 
-                         FieldPosition& pos,
-                         UErrorCode& status) const
-{
-    // this is just here to get around the hiding problem
-    // (the previous format() override would hide the version of
-    // format() on DateFormat that this function correspond to, so we
-    // have to redefine it here)
-    return DateFormat::format(obj, appendTo, pos, status);
+    return appendTo;
 }
 
 //----------------------------------------------------------------------
@@ -642,10 +890,10 @@ SimpleDateFormat::fgCalendarFieldToLevel[] =
     /*wW*/ 20, 30,
     /*dDEF*/ 30, 20, 30, 30,
     /*ahHm*/ 40, 50, 50, 60,
-    /*sS..*/ 70, 80, 
-    /*z?Y*/ 0, 0, 10, 
+    /*sS..*/ 70, 80,
+    /*z?Y*/ 0, 0, 10,
     /*eug*/ 30, 10, 0,
-    /*A*/ 40 
+    /*A*/ 40
 };
 
 
@@ -724,13 +972,13 @@ _appendSymbol(UnicodeString& dst,
 
 //---------------------------------------------------------------------
 void
-SimpleDateFormat::appendGMT(UnicodeString &appendTo, Calendar& cal, UErrorCode& status) const{
+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(appendTo, offset);
+        formatGMTDefault(currentNumberFormat,appendTo, offset);
     } else {
         ((SimpleDateFormat*)this)->initGMTFormatters(status);
         if (U_SUCCESS(status)) {
@@ -769,7 +1017,8 @@ SimpleDateFormat::parseGMT(const UnicodeString &text, ParsePosition &pos) const
 
                 // Try negative Hms
                 fGMTFormatters[kGMTNegativeHMS]->parseObject(text, parsed, pos);
-                if (pos.getErrorIndex() == -1 && pos.getIndex() > start) {
+                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());
@@ -782,7 +1031,8 @@ SimpleDateFormat::parseGMT(const UnicodeString &text, ParsePosition &pos) const
 
                 // Try positive Hms
                 fGMTFormatters[kGMTPositiveHMS]->parseObject(text, parsed, pos);
-                if (pos.getErrorIndex() == -1 && pos.getIndex() > start) {
+                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());
@@ -826,7 +1076,7 @@ SimpleDateFormat::parseGMT(const UnicodeString &text, ParsePosition &pos) const
 }
 
 void
-SimpleDateFormat::formatGMTDefault(UnicodeString &appendTo, int32_t offset) const {
+SimpleDateFormat::formatGMTDefault(NumberFormat *currentNumberFormat,UnicodeString &appendTo, int32_t offset) const {
     if (offset < 0) {
         appendTo += gGmtMinus;
         offset = -offset; // suppress the '-' sign for text display.
@@ -841,31 +1091,35 @@ SimpleDateFormat::formatGMTDefault(UnicodeString &appendTo, int32_t offset) cons
     int32_t hour = offset / 60;
 
 
-    zeroPaddingNumber(appendTo, hour, 2, 2);
+    zeroPaddingNumber(currentNumberFormat,appendTo, hour, 2, 2);
     appendTo += (UChar)0x003A /*':'*/;
-    zeroPaddingNumber(appendTo, min, 2, 2);
+    zeroPaddingNumber(currentNumberFormat,appendTo, min, 2, 2);
     if (sec != 0) {
         appendTo += (UChar)0x003A /*':'*/;
-        zeroPaddingNumber(appendTo, sec, 2, 2);
+        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 + kGmtLen + 1 >= text.length()) {
+    if (start + kUtLen + 1 >= text.length()) {
         pos.setErrorIndex(start);
         return 0;
     }
 
     int32_t cur = start;
     // "GMT"
-    if (text.compare(start, kGmtLen, gGmt) != 0) {
+    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;
     }
-    cur += kGmtLen;
     // Sign
     UBool negative = FALSE;
     if (text.charAt(cur) == (UChar)0x002D /* minus */) {
@@ -881,7 +1135,7 @@ SimpleDateFormat::parseGMTDefault(const UnicodeString &text, ParsePosition &pos)
     pos.setIndex(cur);
 
     Formattable number;
-    parseInt(text, number, 6, pos, FALSE);
+    parseInt(text, number, 6, pos, FALSE,currentNumberFormat);
     numLen = pos.getIndex() - cur;
 
     if (numLen <= 0) {
@@ -903,7 +1157,7 @@ SimpleDateFormat::parseGMTDefault(const UnicodeString &text, ParsePosition &pos)
         if (cur + 2 < text.length() && text.charAt(cur) == (UChar)0x003A /* colon */) {
             cur++;
             pos.setIndex(cur);
-            parseInt(text, number, 2, pos, FALSE);
+            parseInt(text, number, 2, pos, FALSE,currentNumberFormat);
             numLen = pos.getIndex() - cur;
             if (numLen == 2) {
                 // got minute field
@@ -912,7 +1166,7 @@ SimpleDateFormat::parseGMTDefault(const UnicodeString &text, ParsePosition &pos)
                 if (cur + 2 < text.length() && text.charAt(cur) == (UChar)0x003A /* colon */) {
                     cur++;
                     pos.setIndex(cur);
-                    parseInt(text, number, 2, pos, FALSE);
+                    parseInt(text, number, 2, pos, FALSE,currentNumberFormat);
                     numLen = pos.getIndex() - cur;
                     if (numLen == 2) {
                         // got second field
@@ -1040,13 +1294,37 @@ SimpleDateFormat::initGMTFormatters(UErrorCode &status) {
                         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->adoptTimeZone(TimeZone::createTimeZone(UnicodeString(gEtcUTC)));
+                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();
+                    }
+                }
             }
         } else {
             status = U_MEMORY_ALLOCATION_ERROR;
@@ -1055,12 +1333,162 @@ SimpleDateFormat::initGMTFormatters(UErrorCode &status) {
     umtx_unlock(&LOCK);
 }
 
+void
+SimpleDateFormat::initNumberFormatters(const Locale &locale,UErrorCode &status) {
+    if (U_FAILURE(status)) {
+        return;
+    }
+    if ( fDateOverride.isBogus() && fTimeOverride.isBogus() ) {
+        return;
+    }
+    umtx_lock(&LOCK);
+    if (fNumberFormatters == NULL) {
+        fNumberFormatters = (NumberFormat**)uprv_malloc(UDAT_FIELD_COUNT * sizeof(NumberFormat*));
+        if (fNumberFormatters) {
+            for (int32_t i = 0; i < UDAT_FIELD_COUNT; i++) {
+                fNumberFormatters[i] = fNumberFormat;
+            }
+        } else {
+            status = U_MEMORY_ALLOCATION_ERROR;
+        }
+    }
+    umtx_unlock(&LOCK);
+
+    processOverrideString(locale,fDateOverride,kOvrStrDate,status);
+    processOverrideString(locale,fTimeOverride,kOvrStrTime,status);
+
+}
+
+void
+SimpleDateFormat::processOverrideString(const Locale &locale, const UnicodeString &str, int8_t type, UErrorCode &status) {
+    if (str.isBogus()) {
+        return;
+    }
+    int32_t start = 0;
+    int32_t len;
+    UnicodeString nsName;
+    UnicodeString ovrField;
+    UBool moreToProcess = TRUE;
+
+    while (moreToProcess) {
+        int32_t delimiterPosition = str.indexOf(ULOC_KEYWORD_ITEM_SEPARATOR_UNICODE,start);
+        if (delimiterPosition == -1) {
+            moreToProcess = FALSE;
+            len = str.length() - start;
+        } else {
+            len = delimiterPosition - start;
+        }
+        UnicodeString currentString(str,start,len);
+        int32_t equalSignPosition = currentString.indexOf(ULOC_KEYWORD_ASSIGN_UNICODE,0);
+        if (equalSignPosition == -1) { // Simple override string such as "hebrew"
+            nsName.setTo(currentString);
+            ovrField.setToBogus();
+        } else { // Field specific override string such as "y=hebrew"
+            nsName.setTo(currentString,equalSignPosition+1);
+            ovrField.setTo(currentString,0,1); // We just need the first character.
+        }
+
+        int32_t nsNameHash = nsName.hashCode();
+        // See if the numbering system is in the override list, if not, then add it.
+        NSOverride *cur = fOverrideList;
+        NumberFormat *nf = NULL;
+        UBool found = FALSE;
+        while ( cur && !found ) {
+            if ( cur->hash == nsNameHash ) {
+                nf = cur->nf;
+                found = TRUE;
+            }
+            cur = cur->next;
+        }
+
+        if (!found) {
+           cur = (NSOverride *)uprv_malloc(sizeof(NSOverride));
+           if (cur) {
+               char kw[ULOC_KEYWORD_AND_VALUES_CAPACITY];
+               uprv_strcpy(kw,"numbers=");
+               nsName.extract(0,len,kw+8,ULOC_KEYWORD_AND_VALUES_CAPACITY-8,US_INV);
+
+               Locale ovrLoc(locale.getLanguage(),locale.getCountry(),locale.getVariant(),kw);
+               nf = NumberFormat::createInstance(ovrLoc,status);
+
+               // no matter what the locale's default number format looked like, we want
+               // to modify it so that it doesn't use thousands separators, doesn't always
+               // show the decimal point, and recognizes integers only when parsing
+
+               if (U_SUCCESS(status)) {
+                   nf->setGroupingUsed(FALSE);
+                   DecimalFormat* decfmt = dynamic_cast<DecimalFormat*>(nf);
+                   if (decfmt != NULL) {
+                       decfmt->setDecimalSeparatorAlwaysShown(FALSE);
+                   }
+                   nf->setParseIntegerOnly(TRUE);
+                   nf->setMinimumFractionDigits(0); // To prevent "Jan 1.00, 1997.00"
+
+                   cur->nf = nf;
+                   cur->hash = nsNameHash;
+                   cur->next = fOverrideList;
+                   fOverrideList = cur;
+               }
+               else {
+                   // clean up before returning
+                   if (cur != NULL) {
+                       uprv_free(cur);
+                   }
+                  return;
+               }
+
+           } else {
+               status = U_MEMORY_ALLOCATION_ERROR;
+               return;
+           }
+        }
+
+        // Now that we have an appropriate number formatter, fill in the appropriate spaces in the
+        // number formatters table.
+
+        if (ovrField.isBogus()) {
+            switch (type) {
+                case kOvrStrDate:
+                case kOvrStrBoth: {
+                    for ( int8_t i=0 ; i<kDateFieldsCount; i++ ) {
+                        fNumberFormatters[kDateFields[i]] = nf;
+                    }
+                    if (type==kOvrStrDate) {
+                        break;
+                    }
+                }
+                case kOvrStrTime : {
+                    for ( int8_t i=0 ; i<kTimeFieldsCount; i++ ) {
+                        fNumberFormatters[kTimeFields[i]] = nf;
+                    }
+                    break;
+                }
+            }
+        } else {
+           UChar ch = ovrField.charAt(0);
+           UChar *patternCharPtr = u_strchr(DateFormatSymbols::getPatternUChars(), ch);
+           UDateFormatField patternCharIndex;
+
+           // if the pattern character is unrecognized, signal an error and bail out
+           if (patternCharPtr == NULL) {
+               status = U_INVALID_FORMAT_ERROR;
+               return;
+           }
+           patternCharIndex = (UDateFormatField)(patternCharPtr - DateFormatSymbols::getPatternUChars());
+
+           // Set the number formatter in the table
+           fNumberFormatters[patternCharIndex] = nf;
+        }
+
+        start = delimiterPosition + 1;
+    }
+}
 //---------------------------------------------------------------------
 void
 SimpleDateFormat::subFormat(UnicodeString &appendTo,
                             UChar ch,
                             int32_t count,
-                            FieldPosition& pos,
+                            FieldPositionHandler& handler,
                             Calendar& cal,
                             UErrorCode& status) const
 {
@@ -1075,6 +1503,9 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
     UDateFormatField patternCharIndex;
     const int32_t maxIntCount = 10;
     int32_t beginOffset = appendTo.length();
+    NumberFormat *currentNumberFormat;
+
+    UBool isHebrewCalendar = !strcmp(cal.getType(),"hebrew");
 
     // if the pattern character is unrecognized, signal an error and dump out
     if (patternCharPtr == NULL)
@@ -1090,8 +1521,9 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
         return;
     }
 
+    currentNumberFormat = getNumberFormatByIndex(patternCharIndex);
     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:
@@ -1111,30 +1543,37 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
 //AD 123     123     23     123     0123     00123
 //AD 1234   1234     34    1234     1234     01234
 //AD 12345 12345     45   12345    12345     12345
-        case UDAT_YEAR_FIELD:
+    case UDAT_YEAR_FIELD:
     case UDAT_YEAR_WOY_FIELD:
         if(count == 2)
-            zeroPaddingNumber(appendTo, value, 2, 2);
-        else 
-            zeroPaddingNumber(appendTo, value, count, maxIntCount);
-        break; 
+            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
     // appropriate number of digits
     // for "MMMMM", use the narrow form
     case UDAT_MONTH_FIELD:
-        if (count == 5) 
+        if ( isHebrewCalendar ) {
+           HebrewCalendar *hc = (HebrewCalendar*)&cal;
+           if (hc->isLeapYear(hc->get(UCAL_YEAR,status)) && value == 6 && count >= 3 )
+               value = 13; // Show alternate form for Adar II in leap years in Hebrew calendar.
+           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) 
+        else if (count == 4)
             _appendSymbol(appendTo, value, fSymbols->fMonths,
                           fSymbols->fMonthsCount);
-        else if (count == 3) 
+        else if (count == 3)
             _appendSymbol(appendTo, value, fSymbols->fShortMonths,
                           fSymbols->fShortMonthsCount);
-        else 
-            zeroPaddingNumber(appendTo, value + 1, count, maxIntCount);
+        else
+            zeroPaddingNumber(currentNumberFormat,appendTo, value + 1, count, maxIntCount);
         break;
 
     // for "LLLL", write out the whole month name, for "LLL", write out the month
@@ -1142,42 +1581,42 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
     // appropriate number of digits
     // for "LLLLL", use the narrow form
     case UDAT_STANDALONE_MONTH_FIELD:
-        if (count == 5) 
+        if (count == 5)
             _appendSymbol(appendTo, value, fSymbols->fStandaloneNarrowMonths,
                           fSymbols->fStandaloneNarrowMonthsCount);
-        else if (count == 4) 
+        else if (count == 4)
             _appendSymbol(appendTo, value, fSymbols->fStandaloneMonths,
                           fSymbols->fStandaloneMonthsCount);
-        else if (count == 3) 
+        else if (count == 3)
             _appendSymbol(appendTo, value, fSymbols->fStandaloneShortMonths,
                           fSymbols->fStandaloneShortMonthsCount);
-        else 
-            zeroPaddingNumber(appendTo, value + 1, count, maxIntCount);
+        else
+            zeroPaddingNumber(currentNumberFormat,appendTo, value + 1, count, maxIntCount);
         break;
 
     // for "k" and "kk", write out the hour, adjusting midnight to appear as "24"
     case UDAT_HOUR_OF_DAY1_FIELD:
-        if (value == 0) 
-            zeroPaddingNumber(appendTo, cal.getMaximum(UCAL_HOUR_OF_DAY) + 1, count, maxIntCount);
-        else 
-            zeroPaddingNumber(appendTo, value, count, maxIntCount);
+        if (value == 0)
+            zeroPaddingNumber(currentNumberFormat,appendTo, cal.getMaximum(UCAL_HOUR_OF_DAY) + 1, count, maxIntCount);
+        else
+            zeroPaddingNumber(currentNumberFormat,appendTo, value, count, maxIntCount);
         break;
 
     case UDAT_FRACTIONAL_SECOND_FIELD:
         // Fractional seconds left-justify
         {
-            fNumberFormat->setMinimumIntegerDigits((count > 3) ? 3 : count);
-            fNumberFormat->setMaximumIntegerDigits(maxIntCount);
+            currentNumberFormat->setMinimumIntegerDigits((count > 3) ? 3 : count);
+            currentNumberFormat->setMaximumIntegerDigits(maxIntCount);
             if (count == 1) {
-                value = (value + 50) / 100;
+                value /= 100;
             } else if (count == 2) {
-                value = (value + 5) / 10;
+                value /= 10;
             }
             FieldPosition p(0);
-            fNumberFormat->format(value, appendTo, p);
+            currentNumberFormat->format(value, appendTo, p);
             if (count > 3) {
-                fNumberFormat->setMinimumIntegerDigits(count - 3);
-                fNumberFormat->format((int32_t)0, appendTo, p);
+                currentNumberFormat->setMinimumIntegerDigits(count - 3);
+                currentNumberFormat->format((int32_t)0, appendTo, p);
             }
         }
         break;
@@ -1188,7 +1627,7 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
     // for "EEE" or "EE" or "E" or "eee", write out the abbreviated day-of-the-week name
     case UDAT_DOW_LOCAL_FIELD:
         if ( count < 3 ) {
-            zeroPaddingNumber(appendTo, value, count, maxIntCount);
+            zeroPaddingNumber(currentNumberFormat,appendTo, value, count, maxIntCount);
             break;
         }
         // fall through to EEEEE-EEE handling, but for that we don't want local day-of-week,
@@ -1199,10 +1638,10 @@ 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) 
+        else if (count == 4)
             _appendSymbol(appendTo, value, fSymbols->fWeekdays,
                           fSymbols->fWeekdaysCount);
         else
@@ -1215,7 +1654,7 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
     // for "ccccc", use the narrow day-of-the-week name
     case UDAT_STANDALONE_DAY_FIELD:
         if ( count < 3 ) {
-            zeroPaddingNumber(appendTo, value, 1, maxIntCount);
+            zeroPaddingNumber(currentNumberFormat,appendTo, value, 1, maxIntCount);
             break;
         }
         // fall through to alpha DOW handling, but for that we don't want local day-of-week,
@@ -1224,10 +1663,10 @@ 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) 
+        else if (count == 4)
             _appendSymbol(appendTo, value, fSymbols->fStandaloneWeekdays,
                           fSymbols->fStandaloneWeekdaysCount);
         else // count == 3
@@ -1244,10 +1683,10 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
     // for "h" and "hh", write out the hour, adjusting noon and midnight to show up
     // as "12"
     case UDAT_HOUR1_FIELD:
-        if (value == 0) 
-            zeroPaddingNumber(appendTo, cal.getLeastMaximum(UCAL_HOUR) + 1, count, maxIntCount);
-        else 
-            zeroPaddingNumber(appendTo, value, count, maxIntCount);
+        if (value == 0)
+            zeroPaddingNumber(currentNumberFormat,appendTo, cal.getLeastMaximum(UCAL_HOUR) + 1, count, maxIntCount);
+        else
+            zeroPaddingNumber(currentNumberFormat,appendTo, value, count, maxIntCount);
         break;
 
     // for the "z" symbols, we have to check our time zone data first.  If we have a
@@ -1256,9 +1695,9 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
     // If we don't have a localized time zone name,
     // then the time zone shows up as "GMT+hh:mm" or "GMT-hh:mm" (where "hh:mm" is the
     // offset from GMT) regardless of how many z's were in the pattern symbol
-    case UDAT_TIMEZONE_FIELD: 
+    case UDAT_TIMEZONE_FIELD:
     case UDAT_TIMEZONE_GENERIC_FIELD:
-    case UDAT_TIMEZONE_SPECIAL_FIELD: 
+    case UDAT_TIMEZONE_SPECIAL_FIELD:
         {
             UnicodeString zoneString;
             const ZoneStringFormat *zsf = fSymbols->getZoneStringFormat();
@@ -1293,7 +1732,7 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
                 }
             }
             if (zoneString.isEmpty()) {
-                appendGMT(appendTo, cal, status);
+                appendGMT(currentNumberFormat,appendTo, cal, status);
             } else {
                 appendTo += zoneString;
             }
@@ -1307,59 +1746,65 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
             formatRFC822TZ(appendTo, value);
         } else {
             // long form, localized GMT pattern
-            appendGMT(appendTo, cal, status);
+            appendGMT(currentNumberFormat,appendTo, cal, status);
         }
         break;
 
     case UDAT_QUARTER_FIELD:
-        if (count >= 4) 
+        if (count >= 4)
             _appendSymbol(appendTo, value/3, fSymbols->fQuarters,
                           fSymbols->fQuartersCount);
-        else if (count == 3) 
+        else if (count == 3)
             _appendSymbol(appendTo, value/3, fSymbols->fShortQuarters,
                           fSymbols->fShortQuartersCount);
-        else 
-            zeroPaddingNumber(appendTo, (value/3) + 1, count, maxIntCount);
+        else
+            zeroPaddingNumber(currentNumberFormat,appendTo, (value/3) + 1, count, maxIntCount);
         break;
 
     case UDAT_STANDALONE_QUARTER_FIELD:
-        if (count >= 4) 
+        if (count >= 4)
             _appendSymbol(appendTo, value/3, fSymbols->fStandaloneQuarters,
                           fSymbols->fStandaloneQuartersCount);
-        else if (count == 3) 
+        else if (count == 3)
             _appendSymbol(appendTo, value/3, fSymbols->fStandaloneShortQuarters,
                           fSymbols->fStandaloneShortQuartersCount);
-        else 
-            zeroPaddingNumber(appendTo, (value/3) + 1, count, maxIntCount);
+        else
+            zeroPaddingNumber(currentNumberFormat,appendTo, (value/3) + 1, count, maxIntCount);
         break;
 
 
     // all of the other pattern symbols can be formatted as simple numbers with
     // appropriate zero padding
     default:
-        zeroPaddingNumber(appendTo, value, count, maxIntCount);
+        zeroPaddingNumber(currentNumberFormat,appendTo, value, count, maxIntCount);
         break;
     }
 
-    // if the field we're formatting is the one the FieldPosition says it's interested
-    // in, fill in the FieldPosition with this field's positions
-    if (pos.getBeginIndex() == pos.getEndIndex() &&
-        pos.getField() == fgPatternIndexToDateFormatField[patternCharIndex]) {
-        pos.setBeginIndex(beginOffset);
-        pos.setEndIndex(appendTo.length());
+    handler.addAttribute(fgPatternIndexToDateFormatField[patternCharIndex], beginOffset, appendTo.length());
+}
+
+//----------------------------------------------------------------------
+
+NumberFormat *
+SimpleDateFormat::getNumberFormatByIndex(UDateFormatField index) const {
+    if (fNumberFormatters != NULL) {
+        return fNumberFormatters[index];
+    } else {
+        return fNumberFormat;
     }
 }
 
 //----------------------------------------------------------------------
 void
-SimpleDateFormat::zeroPaddingNumber(UnicodeString &appendTo, int32_t value, int32_t minDigits, int32_t maxDigits) const
+SimpleDateFormat::zeroPaddingNumber(NumberFormat *currentNumberFormat,UnicodeString &appendTo,
+                                    int32_t value, int32_t minDigits, int32_t maxDigits) const
 {
-    if (fNumberFormat!=NULL) {
+    if (currentNumberFormat!=NULL) {
         FieldPosition pos(0);
 
-        fNumberFormat->setMinimumIntegerDigits(minDigits);
-        fNumberFormat->setMaximumIntegerDigits(maxDigits);
-        fNumberFormat->format(value, appendTo, pos);  // 3rd arg is there to speed up processing
+        currentNumberFormat->setMinimumIntegerDigits(minDigits);
+        currentNumberFormat->setMaximumIntegerDigits(maxDigits);
+        currentNumberFormat->format(value, appendTo, pos);  // 3rd arg is there to speed up processing
     }
 }
 
@@ -1387,9 +1832,11 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition&
     UErrorCode status = U_ZERO_ERROR;
     int32_t pos = parsePos.getIndex();
     int32_t start = pos;
+
     UBool ambiguousYear[] = { FALSE };
+    int32_t saveHebrewMonth = -1;
     int32_t count = 0;
-    
+
     UBool lenient = isLenient();
 
     // hack, reset tztype, cast away const
@@ -1407,6 +1854,21 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition&
 
     const UnicodeString numericFormatChars(NUMERIC_FORMAT_CHARS);
 
+    TimeZone *backupTZ = 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)) {
+            goto ExitParse;
+        }
+        backupTZ = fCalendar->getTimeZone().clone();
+        fCalendar->setTimeZone(cal.getTimeZone());
+        workCal = fCalendar;
+    }
+
     for (int32_t i=0; i<fPattern.length(); ++i) {
         UChar ch = fPattern.charAt(i);
 
@@ -1472,14 +1934,13 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition&
                 if (fieldPat == abutPat) {
                     count -= abutPass++;
                     if (count == 0) {
-                        parsePos.setIndex(start);
-                        parsePos.setErrorIndex(pos);
-                        return;
+                        status = U_PARSE_ERROR;
+                        goto ExitParse;
                     }
                 }
 
                 pos = subParse(text, pos, ch, count,
-                               TRUE, FALSE, ambiguousYear, cal);
+                               TRUE, FALSE, ambiguousYear, saveHebrewMonth, *workCal, i);
 
                 // If the parse fails anywhere in the run, back up to the
                 // start of the run and retry.
@@ -1494,9 +1955,28 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition&
             // fields.
             else {
                 int32_t s = subParse(text, pos, ch, count,
-                                     FALSE, TRUE, ambiguousYear, cal);
-                
-                if (s <= 0) {
+                               FALSE, TRUE, ambiguousYear, saveHebrewMonth, *workCal, i);
+
+                if (s == -pos-1) {
+                    // era not present, in special cases allow this to continue
+                    s++;
+
+                    if (i+1 < fPattern.length()) {
+                        // move to next pattern character
+                        UChar ch = fPattern.charAt(i+1);
+
+                        // check for whitespace
+                        if (uprv_isRuleWhiteSpace(ch)) {
+                            i++;
+                            // Advance over run in pattern
+                            while ((i+1)<fPattern.length() &&
+                                   uprv_isRuleWhiteSpace(fPattern.charAt(i+1))) {
+                                ++i;
+                            }
+                        }
+                    }
+                }
+                else if (s <= 0) {
                     status = U_PARSE_ERROR;
                     goto ExitParse;
                 }
@@ -1508,7 +1988,7 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition&
         // quoted characters and non-alphabetic unquoted
         // characters.
         else {
-                
+
             abutPat = -1; // End of any abutting fields
             
             if (! matchLiterals(fPattern, i, text, pos, lenient)) {
@@ -1557,8 +2037,8 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition&
             copy = cal.clone();
             // Check for failed cloning.
             if (copy == NULL) {
-               status = U_MEMORY_ALLOCATION_ERROR;
-               goto ExitParse;
+                status = U_MEMORY_ALLOCATION_ERROR;
+                goto ExitParse;
             }
             UDate parsedDate = copy->getTime(status);
             // {sfb} check internalGetDefaultCenturyStart
@@ -1573,16 +2053,16 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition&
             copy = cal.clone();
             // Check for failed cloning.
             if (copy == NULL) {
-               status = U_MEMORY_ALLOCATION_ERROR;
-               goto ExitParse;
+                status = U_MEMORY_ALLOCATION_ERROR;
+                goto ExitParse;
             }
             const TimeZone & tz = cal.getTimeZone();
             BasicTimeZone *btz = NULL;
 
-            if (tz.getDynamicClassID() == OlsonTimeZone::getStaticClassID()
-                || tz.getDynamicClassID() == SimpleTimeZone::getStaticClassID()
-                || tz.getDynamicClassID() == RuleBasedTimeZone::getStaticClassID()
-                || tz.getDynamicClassID() == VTimeZone::getStaticClassID()) {
+            if (dynamic_cast<const OlsonTimeZone *>(&tz) != NULL
+                || dynamic_cast<const SimpleTimeZone *>(&tz) != NULL
+                || dynamic_cast<const RuleBasedTimeZone *>(&tz) != NULL
+                || dynamic_cast<const VTimeZone *>(&tz) != NULL) {
                 btz = (BasicTimeZone*)&tz;
             }
 
@@ -1678,13 +2158,25 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition&
             delete copy;
         }
     }
-ExitParse: 
+ExitParse:
+    // Set the parsed result if local calendar is used
+    // instead of the input calendar
+    if (U_SUCCESS(status) && workCal != &cal) {
+        cal.setTimeZone(workCal->getTimeZone());
+        cal.setTime(workCal->getTime(status), status);
+    }
+
+    // Restore the original time zone if required
+    if (backupTZ != NULL) {
+        fCalendar->adoptTimeZone(backupTZ);
+    }
+
     // If any Calendar calls failed, we pretend that we
     // couldn't parse the string, when in reality this isn't quite accurate--
     // we did parse it; the Calendar calls just failed.
-    if (U_FAILURE(status)) { 
+    if (U_FAILURE(status)) {
         parsePos.setErrorIndex(pos);
-        parsePos.setIndex(start); 
+        parsePos.setIndex(start);
     }
 }
 
@@ -1738,7 +2230,7 @@ int32_t SimpleDateFormat::matchQuarterString(const UnicodeString& text,
 
         lcase.fastCopyFrom(data[i]).foldCase();
         int32_t length = lcase.length();
-                    
+
         if (length > bestMatchLength &&
             lcaseText.compareBetween(0, length, lcase, 0, length) == 0)
         {
@@ -1777,7 +2269,7 @@ int32_t SimpleDateFormat::matchQuarterString(const UnicodeString& text,
             }
         }
     }
-    
+
     return -start;
 }
 
@@ -1828,7 +2320,7 @@ UBool SimpleDateFormat::matchLiterals(const UnicodeString &pattern,
             t += 1;
         }
     }
-    
+        
     for (p = 0; p < literal.length() && t < text.length(); p += 1, t += 1) {
         UBool needWhitespace = FALSE;
         
@@ -1945,7 +2437,7 @@ int32_t SimpleDateFormat::matchString(const UnicodeString& text,
 
         lcase.fastCopyFrom(data[i]).foldCase();
         int32_t length = lcase.length();
-                    
+
         if (length > bestMatchLength &&
             lcaseText.compareBetween(0, length, lcase, 0, length) == 0)
         {
@@ -1955,7 +2447,13 @@ int32_t SimpleDateFormat::matchString(const UnicodeString& text,
     }
     if (bestMatch >= 0)
     {
-        cal.set(field, bestMatch);
+        // Adjustment for Hebrew Calendar month Adar II
+        if (!strcmp(cal.getType(),"hebrew") && field==UCAL_MONTH && bestMatch==13) {
+            cal.set(field,6);
+        }
+        else {
+            cal.set(field, bestMatch);
+        }
 
         // Once we have a match, we have to determine the length of the
         // original source string.  This will usually be == the length of
@@ -1984,7 +2482,7 @@ int32_t SimpleDateFormat::matchString(const UnicodeString& text,
             }
         }
     }
-    
+
     return -start;
 }
 
@@ -2007,13 +2505,16 @@ SimpleDateFormat::set2DigitYearStart(UDate d, UErrorCode& status)
  * indicating matching failure, otherwise.
  */
 int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UChar ch, int32_t count,
-                           UBool obeyCount, UBool allowNegative, UBool ambiguousYear[], Calendar& cal) const
+                           UBool obeyCount, UBool allowNegative, UBool ambiguousYear[], int32_t& saveHebrewMonth, Calendar& cal,
+                           int32_t patLoc) const
 {
     Formattable number;
     int32_t value = 0;
     int32_t i;
+    int32_t ps = 0;
     ParsePosition pos(0);
-    int32_t patternCharIndex;
+    UDateFormatField patternCharIndex;
+    NumberFormat *currentNumberFormat;
     UnicodeString temp;
     UChar *patternCharPtr = u_strchr(DateFormatSymbols::getPatternUChars(), ch);
     UBool lenient = isLenient();
@@ -2028,7 +2529,7 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
     }
 
     patternCharIndex = (UDateFormatField)(patternCharPtr - DateFormatSymbols::getPatternUChars());
-
+    currentNumberFormat = getNumberFormatByIndex(patternCharIndex);
     UCalendarDateFields field = fgPatternIndexToCalendarField[patternCharIndex];
 
     // If there are any spaces here, skip over them.  If we hit the end
@@ -2039,8 +2540,7 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
         }
         
         UChar32 c = text.char32At(start);
-        
-        if (!u_isUWhiteSpace(c)) {
+        if (!u_isUWhiteSpace(c) /*||*/ && !uprv_isRuleWhiteSpace(c)) {
             break;
         }
         
@@ -2083,20 +2583,34 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
             src = &text;
         }
 
-        parseInt(*src, number, pos, allowNegative);
+        parseInt(*src, number, pos, allowNegative,currentNumberFormat);
+
+        int32_t txtLoc = pos.getIndex();
 
-        if (pos.getIndex() > parseStart) {
+        if (txtLoc > parseStart) {
             value = number.getLong();
             gotNumber = TRUE;
             
+            // suffix processing
+            if (value < 0 ) {
+                txtLoc = checkIntSuffix(text, txtLoc, patLoc+1, TRUE);
+                if (txtLoc != pos.getIndex()) {
+                    value *= -1;
+                }
+            }
+            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;
             }
-        }
             
+            pos.setIndex(txtLoc);
+        }
     }
     
     // Make sure that we got a number if
@@ -2148,17 +2662,24 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
             // we check the rest of the fields below.
             break;
     }
-    
+
     switch (patternCharIndex) {
     case UDAT_ERA_FIELD:
         if (count == 5) {
-            return matchString(text, start, UCAL_ERA, fSymbols->fNarrowEras, fSymbols->fNarrowErasCount, cal);
-        }
-        if (count == 4) {
-            return matchString(text, start, UCAL_ERA, fSymbols->fEraNames, fSymbols->fEraNamesCount, cal);
+            ps = matchString(text, start, UCAL_ERA, fSymbols->fNarrowEras, fSymbols->fNarrowErasCount, cal);
+        } else if (count == 4) {
+            ps = matchString(text, start, UCAL_ERA, fSymbols->fEraNames, fSymbols->fEraNamesCount, cal);
+        } else {
+            ps = matchString(text, start, UCAL_ERA, fSymbols->fEras, fSymbols->fErasCount, cal);
         }
 
-        return matchString(text, start, UCAL_ERA, fSymbols->fEras, fSymbols->fErasCount, cal);
+        // check return position, if it equals -start, then matchString error
+        // special case the return code so we don't necessarily fail out until we
+        // verify no year information also
+        if (ps == -start)
+            ps--;
+
+        return ps;
 
     case UDAT_YEAR_FIELD:
         // If there are 3 or more YEAR pattern characters, this indicates
@@ -2187,6 +2708,17 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
             }
         }
         cal.set(UCAL_YEAR, value);
+
+        // Delayed checking for adjustment of Hebrew month numbers in non-leap years.
+        if (saveHebrewMonth >= 0) {
+            HebrewCalendar *hc = (HebrewCalendar*)&cal;
+            if (!hc->isLeapYear(value) && saveHebrewMonth >= 6) {
+               cal.set(UCAL_MONTH,saveHebrewMonth);
+            } else {
+               cal.set(UCAL_MONTH,saveHebrewMonth-1);
+            }
+            saveHebrewMonth = -1;
+        }
         return pos.getIndex();
 
     case UDAT_YEAR_WOY_FIELD:
@@ -2207,10 +2739,27 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
     case UDAT_MONTH_FIELD:
         if (gotNumber) // i.e., M or MM.
         {
-            // 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);
+            // When parsing month numbers from the Hebrew Calendar, we might need to adjust the month depending on whether
+            // or not it was a leap year.  We may or may not yet know what year it is, so might have to delay checking until
+            // the year is parsed.
+            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 {
+                // 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., MMM or MMMM
@@ -2250,11 +2799,11 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
 
     case UDAT_HOUR_OF_DAY1_FIELD:
         // [We computed 'value' above.]
-        if (value == cal.getMaximum(UCAL_HOUR_OF_DAY) + 1) 
+        if (value == cal.getMaximum(UCAL_HOUR_OF_DAY) + 1)
             value = 0;
             
         // fall through to set field
-        
+            
     case UDAT_HOUR_OF_DAY0_FIELD:
         cal.set(UCAL_HOUR_OF_DAY, value);
         return pos.getIndex();
@@ -2329,15 +2878,15 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
 
     case UDAT_HOUR1_FIELD:
         // [We computed 'value' above.]
-        if (value == cal.getLeastMaximum(UCAL_HOUR)+1) 
+        if (value == cal.getLeastMaximum(UCAL_HOUR)+1)
             value = 0;
             
         // fall through to set field
-        
+            
     case UDAT_HOUR0_FIELD:
         cal.set(UCAL_HOUR, value);
         return pos.getIndex();
-
+            
     case UDAT_QUARTER_FIELD:
         if (gotNumber) // i.e., Q or QQ.
         {
@@ -2416,7 +2965,7 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
                     // Parse digits
                     int32_t orgPos = start + 1;
                     pos.setIndex(orgPos);
-                    parseInt(text, number, 6, pos, FALSE);
+                    parseInt(text, number, 6, pos, FALSE,currentNumberFormat);
                     int32_t numLen = pos.getIndex() - orgPos;
                     if (numLen <= 0) {
                         break;
@@ -2465,7 +3014,7 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
             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);
@@ -2508,6 +3057,8 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
                             zsinfo = zsf->findGenericLocation(text, start, matchLen, status);
                         }
                         break;
+                    default:
+                        break;
                 }
 
                 if (U_SUCCESS(status) && zsinfo != NULL) {
@@ -2528,6 +3079,22 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
                     return start + matchLen;
                 }
             }
+            // 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"));
+                cal.adoptTimeZone(tz);
+                return start + gmtLen;
+            }
+
             // complete failure
             return -start;
         }
@@ -2545,7 +3112,7 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
         } else {
             src = &text;
         }
-        parseInt(*src, number, pos, allowNegative);
+        parseInt(*src, number, pos, allowNegative,currentNumberFormat);
         if (pos.getIndex() != parseStart) {
             int32_t value = number.getLong();
             
@@ -2557,7 +3124,7 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
                 return pos.getIndex();
             }
         }
-            
+
         return -start;
     }
 }
@@ -2569,8 +3136,9 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
 void SimpleDateFormat::parseInt(const UnicodeString& text,
                                 Formattable& number,
                                 ParsePosition& pos,
-                                UBool allowNegative) const {
-    parseInt(text, number, -1, pos, allowNegative);
+                                UBool allowNegative,
+                                NumberFormat *fmt) const {
+    parseInt(text, number, -1, pos, allowNegative,fmt);
 }
 
 /**
@@ -2580,17 +3148,16 @@ void SimpleDateFormat::parseInt(const UnicodeString& text,
                                 Formattable& number,
                                 int32_t maxDigits,
                                 ParsePosition& pos,
-                                UBool allowNegative) const {
+                                UBool allowNegative,
+                                NumberFormat *fmt) const {
     UnicodeString oldPrefix;
     DecimalFormat* df = NULL;
-    if (!allowNegative &&
-        fNumberFormat->getDynamicClassID() == DecimalFormat::getStaticClassID()) {
-        df = (DecimalFormat*)fNumberFormat;
+    if (!allowNegative && (df = dynamic_cast<DecimalFormat*>(fmt)) != NULL) {
         df->getNegativePrefix(oldPrefix);
         df->setNegativePrefix(SUPPRESS_NEGATIVE_PREFIX);
     }
     int32_t oldPos = pos.getIndex();
-    fNumberFormat->parse(text, number, pos);
+    fmt->parse(text, number, pos);
     if (df != NULL) {
         df->setNegativePrefix(oldPrefix);
     }
@@ -2626,21 +3193,21 @@ void SimpleDateFormat::translatePattern(const UnicodeString& originalPattern,
   // an error if a particular "pattern character" doesn't appear in "from".
   // Depending on the values of "from" and "to" this can convert from generic
   // to localized patterns or localized to generic.
-  if (U_FAILURE(status)) 
+  if (U_FAILURE(status))
     return;
-  
+
   translatedPattern.remove();
   UBool inQuote = FALSE;
   for (int32_t i = 0; i < originalPattern.length(); ++i) {
     UChar c = originalPattern[i];
     if (inQuote) {
-      if (c == QUOTE) 
+      if (c == QUOTE)
     inQuote = FALSE;
     }
     else {
-      if (c == QUOTE) 
+      if (c == QUOTE)
     inQuote = TRUE;
-      else if ((c >= 0x0061 /*'a'*/ && c <= 0x007A) /*'z'*/ 
+      else if ((c >= 0x0061 /*'a'*/ && c <= 0x007A) /*'z'*/
            || (c >= 0x0041 /*'A'*/ && c <= 0x005A /*'Z'*/)) {
     int32_t ci = from.indexOf(c);
     if (ci == -1) {
@@ -2727,7 +3294,7 @@ void SimpleDateFormat::adoptCalendar(Calendar* calendarToAdopt)
 {
   UErrorCode status = U_ZERO_ERROR;
   DateFormat::adoptCalendar(calendarToAdopt);
-  delete fSymbols; 
+  delete fSymbols;
   fSymbols=NULL;
   initializeSymbols(fLocale, fCalendar, status);  // we need new symbols
   initializeDefaultCentury();  // we need a new century (possibly)
@@ -2744,7 +3311,7 @@ SimpleDateFormat::isFieldUnitIgnored(UCalendarDateFields field) const {
 
 
 UBool
-SimpleDateFormat::isFieldUnitIgnored(const UnicodeString& pattern, 
+SimpleDateFormat::isFieldUnitIgnored(const UnicodeString& pattern,
                                      UCalendarDateFields field) {
     int32_t fieldLevel = fgCalendarFieldToLevel[field];
     int32_t level;
@@ -2769,8 +3336,8 @@ SimpleDateFormat::isFieldUnitIgnored(const UnicodeString& pattern,
             } else {
                 inQuote = ! inQuote;
             }
-        } 
-        else if ( ! inQuote && ((ch >= 0x0061 /*'a'*/ && ch <= 0x007A /*'z'*/) 
+        }
+        else if ( ! inQuote && ((ch >= 0x0061 /*'a'*/ && ch <= 0x007A /*'z'*/)
                     || (ch >= 0x0041 /*'A'*/ && ch <= 0x005A /*'Z'*/))) {
             prevCh = ch;
             ++count;
@@ -2786,14 +3353,159 @@ SimpleDateFormat::isFieldUnitIgnored(const UnicodeString& pattern,
     return TRUE;
 }
 
-
+//----------------------------------------------------------------------
 
 const Locale&
 SimpleDateFormat::getSmpFmtLocale(void) const {
     return fLocale;
 }
 
+//----------------------------------------------------------------------
+
+int32_t
+SimpleDateFormat::checkIntSuffix(const UnicodeString& text, int32_t start,
+                                 int32_t patLoc, UBool isNegative) const {
+    // local variables
+    UnicodeString suf;
+    int32_t patternMatch;
+    int32_t textPreMatch;
+    int32_t textPostMatch;
+
+    // check that we are still in range
+    if ( (start > text.length()) ||
+         (start < 0) ||
+         (patLoc < 0) ||
+         (patLoc > fPattern.length())) {
+        // out of range, don't advance location in text
+        return start;
+    }
+
+    // get the suffix
+    DecimalFormat* decfmt = dynamic_cast<DecimalFormat*>(fNumberFormat);
+    if (decfmt != NULL) {
+        if (isNegative) {
+            suf = decfmt->getNegativeSuffix(suf);
+        }
+        else {
+            suf = decfmt->getPositiveSuffix(suf);
+        }
+    }
+
+    // check for suffix
+    if (suf.length() <= 0) {
+        return start;
+    }
+
+    // check suffix will be encountered in the pattern
+    patternMatch = compareSimpleAffix(suf,fPattern,patLoc);
+
+    // check if a suffix will be encountered in the text
+    textPreMatch = compareSimpleAffix(suf,text,start);
+
+    // check if a suffix was encountered in the text
+    textPostMatch = compareSimpleAffix(suf,text,start-suf.length());
 
+    // check for suffix match
+    if ((textPreMatch >= 0) && (patternMatch >= 0) && (textPreMatch == patternMatch)) {
+        return start;
+    }
+    else if ((textPostMatch >= 0) && (patternMatch >= 0) && (textPostMatch == patternMatch)) {
+        return  start - suf.length();
+    }
+
+    // should not get here
+    return start;
+}
+
+//----------------------------------------------------------------------
+
+int32_t
+SimpleDateFormat::compareSimpleAffix(const UnicodeString& affix,
+                   const UnicodeString& input,
+                   int32_t pos) const {
+    int32_t start = pos;
+    for (int32_t i=0; i<affix.length(); ) {
+        UChar32 c = affix.char32At(i);
+        int32_t len = U16_LENGTH(c);
+        if (uprv_isRuleWhiteSpace(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
+            // U+0020 is UWhiteSpace.  So we have to first do a direct
+            // match of the run of RULE whitespace in the pattern,
+            // then match any extra characters.
+            UBool literalMatch = FALSE;
+            while (pos < input.length() &&
+                   input.char32At(pos) == c) {
+                literalMatch = TRUE;
+                i += len;
+                pos += len;
+                if (i == affix.length()) {
+                    break;
+                }
+                c = affix.char32At(i);
+                len = U16_LENGTH(c);
+                if (!uprv_isRuleWhiteSpace(c)) {
+                    break;
+                }
+            }
+
+            // Advance over run in pattern
+            i = skipRuleWhiteSpace(affix, i);
+
+            // Advance over run in input text
+            // Must see at least one white space char in input,
+            // unless we've already matched some characters literally.
+            int32_t s = pos;
+            pos = skipUWhiteSpace(input, pos);
+            if (pos == s && !literalMatch) {
+                return -1;
+            }
+
+            // If we skip UWhiteSpace in the input text, we need to skip it in the pattern.
+            // Otherwise, the previous lines may have skipped over text (such as U+00A0) that
+            // is also in the affix.
+            i = skipUWhiteSpace(affix, i);
+        } else {
+            if (pos < input.length() &&
+                input.char32At(pos) == c) {
+                i += len;
+                pos += len;
+            } else {
+                return -1;
+            }
+        }
+    }
+    return pos - start;
+}
+
+//----------------------------------------------------------------------
+
+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;
+}
+
+//----------------------------------------------------------------------
+
+int32_t
+SimpleDateFormat::skipUWhiteSpace(const UnicodeString& text, int32_t pos) const {
+    while (pos < text.length()) {
+        UChar32 c = text.char32At(pos);
+        if (!u_isUWhiteSpace(c)) {
+            break;
+        }
+        pos += U16_LENGTH(c);
+    }
+    return pos;
+}
 
 U_NAMESPACE_END