]> granicus.if.org Git - icu/commitdiff
ICU-9867 New time zone pattern letters/types support for CLDR 23/ICU 51.
authorYoshito Umaoka <y.umaoka@gmail.com>
Mon, 11 Feb 2013 00:23:55 +0000 (00:23 +0000)
committerYoshito Umaoka <y.umaoka@gmail.com>
Mon, 11 Feb 2013 00:23:55 +0000 (00:23 +0000)
X-SVN-Rev: 33159

21 files changed:
icu4c/source/i18n/dtfmtsym.cpp
icu4c/source/i18n/smpdtfmt.cpp
icu4c/source/i18n/timezone.cpp
icu4c/source/i18n/tzfmt.cpp
icu4c/source/i18n/tznames.cpp
icu4c/source/i18n/tznames_impl.cpp
icu4c/source/i18n/tznames_impl.h
icu4c/source/i18n/ucln_in.h
icu4c/source/i18n/unicode/smpdtfmt.h
icu4c/source/i18n/unicode/tzfmt.h
icu4c/source/i18n/unicode/tznames.h
icu4c/source/i18n/unicode/udat.h
icu4c/source/i18n/zonemeta.cpp
icu4c/source/i18n/zonemeta.h
icu4c/source/test/cintltst/cdattst.c
icu4c/source/test/intltest/dtfmttst.cpp
icu4c/source/test/intltest/dtifmtts.cpp
icu4c/source/test/intltest/tzfmttst.cpp
icu4c/source/test/intltest/tzfmttst.h
icu4c/source/test/intltest/tzregts.cpp
icu4c/source/test/intltest/tztest.cpp

index a9034a80879467c93c4f7796bf61f3d86b3012db..270cfe1ea4bfcf2b2f3506ee1fa503543815a884 100644 (file)
  * resource data.
  */
 
-#define PATTERN_CHARS_LEN 31
+#define PATTERN_CHARS_LEN 34
 
 /**
  * Unlocalized date-time pattern characters. For example: 'y', 'd', etc. All
  * locales use the same these unlocalized pattern characters.
  */
 static const UChar gPatternChars[] = {
-    // GyMdkHmsSEDFwWahKzYeugAZvcLQqVU
+    // GyMdkHmsSEDFwWahKzYeugAZvcLQqVUOXx
     0x47, 0x79, 0x4D, 0x64, 0x6B, 0x48, 0x6D, 0x73, 0x53, 0x45,
     0x44, 0x46, 0x77, 0x57, 0x61, 0x68, 0x4B, 0x7A, 0x59, 0x65,
-    0x75, 0x67, 0x41, 0x5A, 0x76, 0x63, 0x4c, 0x51, 0x71, 0x56, 0x55, 0
+    0x75, 0x67, 0x41, 0x5A, 0x76, 0x63, 0x4c, 0x51, 0x71, 0x56,
+    0x55, 0x4F, 0x58, 0x78, 0
 };
 
 /* length of an array */
index 79e03affd4349aba15abbdc2173aa818d011c6f6..8ebd0d171f263ec5504073141c1d2b07360ddf92 100644 (file)
@@ -137,8 +137,9 @@ static const UDateFormatField kTimeFields[] = {
     UDAT_HOUR1_FIELD,
     UDAT_HOUR0_FIELD,
     UDAT_MILLISECONDS_IN_DAY_FIELD,
-    UDAT_TIMEZONE_RFC_FIELD };
-static const int8_t kTimeFieldsCount = 9;
+    UDAT_TIMEZONE_RFC_FIELD,
+    UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD };
+static const int8_t kTimeFieldsCount = 10;
 
 
 // This is a pattern-of-last-resort used when we can't load a usable pattern out
@@ -203,6 +204,9 @@ static const int32_t gFieldRangeBias[] = {
     -1,  // 'q' - UDAT_STANDALONE_QUARTER_FIELD
     -1   // 'V' - UDAT_TIMEZONE_SPECIAL_FIELD
     -1,  // 'U' - UDAT_YEAR_NAME_FIELD
+    -1,  // 'O' - UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD
+    -1,  // 'X' - UDAT_TIMEZONE_ISO_FIELD
+    -1,  // 'x' - UDAT_TIMEZONE_ISO_LOCAL_FIELD
 };
 
 // When calendar uses hebr numbering (i.e. he@calendar=hebrew),
@@ -936,13 +940,13 @@ SimpleDateFormat::fgCalendarFieldToLevel[] =
 const int32_t
 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,
+        -1, 40, -1, -1, 20, 30, 30,  0, 50, -1, -1, 50, 20, 20, -1,  0,
     //   P   Q   R   S   T   U   V   W   X   Y   Z
-        -1, 20, -1, 80, -1, 10,  0, 30, -1, 10,  0, -1, -1, -1, -1, -1,
+        -1, 20, -1, 80, -1, 10,  0, 30,  0, 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
-        -1, 20, -1, 70, -1, 10,  0, 20, -1, 10,  0, -1, -1, -1, -1, -1
+        -1, 20, -1, 70, -1, 10,  0, 20,  0, 10,  0, -1, -1, -1, -1, -1
 };
 
 
@@ -965,6 +969,8 @@ SimpleDateFormat::fgPatternIndexToCalendarField[] =
     /*q*/   UCAL_MONTH,
     /*V*/   UCAL_ZONE_OFFSET,
     /*U*/   UCAL_YEAR,
+    /*O*/   UCAL_ZONE_OFFSET,
+    /*Xx*/  UCAL_ZONE_OFFSET, UCAL_ZONE_OFFSET,
 };
 
 // Map index into pattern character string to DateFormat field number
@@ -985,6 +991,8 @@ SimpleDateFormat::fgPatternIndexToDateFormatField[] = {
     /*q*/   UDAT_STANDALONE_QUARTER_FIELD,
     /*V*/   UDAT_TIMEZONE_SPECIAL_FIELD,
     /*U*/   UDAT_YEAR_NAME_FIELD,
+    /*O*/   UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD,
+    /*Xx*/  UDAT_TIMEZONE_ISO_FIELD, UDAT_TIMEZONE_ISO_LOCAL_FIELD,
 };
 
 //----------------------------------------------------------------------
@@ -1428,43 +1436,42 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
             zeroPaddingNumber(currentNumberFormat,appendTo, value, count, maxIntCount);
         break;
 
-    // for the "z" symbols, we have to check our time zone data first.  If we have a
-    // localized name for the time zone, then "zzzz" / "zzz" indicate whether
-    // daylight time is in effect (long/short) and "zz" / "z" do not (long/short).
-    // 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_GENERIC_FIELD:
-    case UDAT_TIMEZONE_SPECIAL_FIELD:
-    case UDAT_TIMEZONE_RFC_FIELD: // 'Z' - TIMEZONE_RFC
+    case UDAT_TIMEZONE_FIELD: // 'z'
+    case UDAT_TIMEZONE_RFC_FIELD: // 'Z'
+    case UDAT_TIMEZONE_GENERIC_FIELD: // 'v'
+    case UDAT_TIMEZONE_SPECIAL_FIELD: // 'V'
+    case UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD: // 'O'
+    case UDAT_TIMEZONE_ISO_FIELD: // 'X'
+    case UDAT_TIMEZONE_ISO_LOCAL_FIELD: // 'x'
         {
             UnicodeString zoneString;
             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 (patternCharIndex == UDAT_TIMEZONE_FIELD) {
                     if (count < 4) {
                         // "z", "zz", "zzz"
                         tzFormat()->format(UTZFMT_STYLE_SPECIFIC_SHORT, tz, date, zoneString);
                         capContextUsageType = DateFormatSymbols::kCapContextUsageMetazoneShort;
                     } else {
-                        // "zzzz"
+                        // "zzzz" or longer
                         tzFormat()->format(UTZFMT_STYLE_SPECIFIC_LONG, tz, date, zoneString);
                         capContextUsageType = DateFormatSymbols::kCapContextUsageMetazoneLong;
                     }
-                } else if (patternCharIndex == UDAT_TIMEZONE_GENERIC_FIELD) {
+                }
+                else if (patternCharIndex == UDAT_TIMEZONE_RFC_FIELD) {
+                    if (count < 4) {
+                        // "Z"
+                        tzFormat()->format(UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL, tz, date, zoneString);
+                    } else if (count == 5) {
+                        // "ZZZZZ"
+                        tzFormat()->format(UTZFMT_STYLE_ISO_EXTENDED_FULL, tz, date, zoneString);
+                    } else {
+                        // "ZZ", "ZZZ", "ZZZZ"
+                        tzFormat()->format(UTZFMT_STYLE_LOCALIZED_GMT, tz, date, zoneString);
+                    }
+                }
+                else if (patternCharIndex == UDAT_TIMEZONE_GENERIC_FIELD) {
                     if (count == 1) {
                         // "v"
                         tzFormat()->format(UTZFMT_STYLE_GENERIC_SHORT, tz, date, zoneString);
@@ -1474,17 +1481,71 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
                         tzFormat()->format(UTZFMT_STYLE_GENERIC_LONG, tz, date, zoneString);
                         capContextUsageType = DateFormatSymbols::kCapContextUsageMetazoneLong;
                     }
-                } else { // patternCharIndex == UDAT_TIMEZONE_SPECIAL_FIELD
+                }
+                else if (patternCharIndex == UDAT_TIMEZONE_SPECIAL_FIELD) {
                     if (count == 1) {
                         // "V"
-                        tzFormat()->format(UTZFMT_STYLE_SPECIFIC_SHORT, tz, date, zoneString);
-                        capContextUsageType = DateFormatSymbols::kCapContextUsageMetazoneShort;
+                        tzFormat()->format(UTZFMT_STYLE_ZONE_ID_SHORT, tz, date, zoneString);
+                    } else if (count == 2) {
+                        // "VV"
+                        tzFormat()->format(UTZFMT_STYLE_ZONE_ID, tz, date, zoneString);
+                    } else if (count == 3) {
+                        // "VVV"
+                        tzFormat()->format(UTZFMT_STYLE_EXEMPLAR_LOCATION, tz, date, zoneString);
                     } else if (count == 4) {
                         // "VVVV"
                         tzFormat()->format(UTZFMT_STYLE_GENERIC_LOCATION, tz, date, zoneString);
                         capContextUsageType = DateFormatSymbols::kCapContextUsageZoneLong;
                     }
                 }
+                else if (patternCharIndex == UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD) {
+                    if (count == 1) {
+                        // "O"
+                        tzFormat()->format(UTZFMT_STYLE_LOCALIZED_GMT_SHORT, tz, date, zoneString);
+                    } else if (count == 4) {
+                        // "OOOO"
+                        tzFormat()->format(UTZFMT_STYLE_LOCALIZED_GMT, tz, date, zoneString);
+                    }
+                }
+                else if (patternCharIndex == UDAT_TIMEZONE_ISO_FIELD) {
+                    if (count == 1) {
+                        // "X"
+                        tzFormat()->format(UTZFMT_STYLE_ISO_BASIC_SHORT, tz, date, zoneString);
+                    } else if (count == 2) {
+                        // "XX"
+                        tzFormat()->format(UTZFMT_STYLE_ISO_BASIC_FIXED, tz, date, zoneString);
+                    } else if (count == 3) {
+                        // "XXX"
+                        tzFormat()->format(UTZFMT_STYLE_ISO_EXTENDED_FIXED, tz, date, zoneString);
+                    } else if (count == 4) {
+                        // "XXXX"
+                        tzFormat()->format(UTZFMT_STYLE_ISO_BASIC_FULL, tz, date, zoneString);
+                    } else if (count == 5) {
+                        // "XXXXX"
+                        tzFormat()->format(UTZFMT_STYLE_ISO_EXTENDED_FULL, tz, date, zoneString);
+                    }
+                }
+                else if (patternCharIndex == UDAT_TIMEZONE_ISO_LOCAL_FIELD) {
+                    if (count == 1) {
+                        // "x"
+                        tzFormat()->format(UTZFMT_STYLE_ISO_BASIC_LOCAL_SHORT, tz, date, zoneString);
+                    } else if (count == 2) {
+                        // "xx"
+                        tzFormat()->format(UTZFMT_STYLE_ISO_BASIC_LOCAL_FIXED, tz, date, zoneString);
+                    } else if (count == 3) {
+                        // "xxx"
+                        tzFormat()->format(UTZFMT_STYLE_ISO_EXTENDED_LOCAL_FIXED, tz, date, zoneString);
+                    } else if (count == 4) {
+                        // "xxxx"
+                        tzFormat()->format(UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL, tz, date, zoneString);
+                    } else if (count == 5) {
+                        // "xxxxx"
+                        tzFormat()->format(UTZFMT_STYLE_ISO_EXTENDED_LOCAL_FULL, tz, date, zoneString);
+                    }
+                }
+                else {
+                    U_ASSERT(FALSE);
+                }
             }
             appendTo += zoneString;
         }
@@ -2831,7 +2892,7 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
         }
         break;
 
-    case UDAT_TIMEZONE_FIELD:
+    case UDAT_TIMEZONE_FIELD: // 'z'
         {
             UTimeZoneFormatTimeType tzTimeType = UTZFMT_TIME_TYPE_UNKNOWN;
             UTimeZoneFormatStyle style = (count < 4) ? UTZFMT_STYLE_SPECIFIC_SHORT : UTZFMT_STYLE_SPECIFIC_LONG;
@@ -2843,10 +2904,11 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
             }
         }
         break;
-    case UDAT_TIMEZONE_RFC_FIELD:
+    case UDAT_TIMEZONE_RFC_FIELD: // 'Z'
         {
             UTimeZoneFormatTimeType tzTimeType = UTZFMT_TIME_TYPE_UNKNOWN;
-            UTimeZoneFormatStyle style = (count < 4) ? UTZFMT_STYLE_RFC822 : ((count == 5) ? UTZFMT_STYLE_ISO8601: UTZFMT_STYLE_LOCALIZED_GMT);
+            UTimeZoneFormatStyle style = (count < 4) ?
+                UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL : ((count == 5) ? UTZFMT_STYLE_ISO_EXTENDED_FULL: UTZFMT_STYLE_LOCALIZED_GMT);
             TimeZone *tz  = tzFormat()->parse(style, text, pos, &tzTimeType);
             if (tz != NULL) {
                 ((SimpleDateFormat*)this)->tztype = tzTimeType;
@@ -2855,7 +2917,7 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
             }
             return -start;
         }
-    case UDAT_TIMEZONE_GENERIC_FIELD:
+    case UDAT_TIMEZONE_GENERIC_FIELD: // 'v'
         {
             UTimeZoneFormatTimeType tzTimeType = UTZFMT_TIME_TYPE_UNKNOWN;
             UTimeZoneFormatStyle style = (count < 4) ? UTZFMT_STYLE_GENERIC_SHORT : UTZFMT_STYLE_GENERIC_LONG;
@@ -2867,10 +2929,94 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
             }
             return -start;
         }
-    case UDAT_TIMEZONE_SPECIAL_FIELD:
+    case UDAT_TIMEZONE_SPECIAL_FIELD: // 'V'
         {
             UTimeZoneFormatTimeType tzTimeType = UTZFMT_TIME_TYPE_UNKNOWN;
-            UTimeZoneFormatStyle style = (count < 4) ? UTZFMT_STYLE_SPECIFIC_SHORT : UTZFMT_STYLE_GENERIC_LOCATION;
+            UTimeZoneFormatStyle style;
+            switch (count) {
+            case 1:
+                style = UTZFMT_STYLE_ZONE_ID_SHORT;
+                break;
+            case 2:
+                style = UTZFMT_STYLE_ZONE_ID;
+                break;
+            case 3:
+                style = UTZFMT_STYLE_EXEMPLAR_LOCATION;
+                break;
+            default:
+                style = UTZFMT_STYLE_GENERIC_LOCATION;
+                break;
+            }
+            TimeZone *tz  = tzFormat()->parse(style, text, pos, &tzTimeType);
+            if (tz != NULL) {
+                ((SimpleDateFormat*)this)->tztype = tzTimeType;
+                cal.adoptTimeZone(tz);
+                return pos.getIndex();
+            }
+            return -start;
+        }
+    case UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD: // 'O'
+        {
+            UTimeZoneFormatTimeType tzTimeType = UTZFMT_TIME_TYPE_UNKNOWN;
+            UTimeZoneFormatStyle style = (count < 4) ? UTZFMT_STYLE_LOCALIZED_GMT_SHORT : 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();
+            }
+            return -start;
+        }
+    case UDAT_TIMEZONE_ISO_FIELD: // 'X'
+        {
+            UTimeZoneFormatTimeType tzTimeType = UTZFMT_TIME_TYPE_UNKNOWN;
+            UTimeZoneFormatStyle style;
+            switch (count) {
+            case 1:
+                style = UTZFMT_STYLE_ISO_BASIC_SHORT;
+                break;
+            case 2:
+                style = UTZFMT_STYLE_ISO_BASIC_FIXED;
+                break;
+            case 3:
+                style = UTZFMT_STYLE_ISO_EXTENDED_FIXED;
+                break;
+            case 4:
+                style = UTZFMT_STYLE_ISO_BASIC_FULL;
+                break;
+            default:
+                style = UTZFMT_STYLE_ISO_EXTENDED_FULL;
+                break;
+            }
+            TimeZone *tz  = tzFormat()->parse(style, text, pos, &tzTimeType);
+            if (tz != NULL) {
+                ((SimpleDateFormat*)this)->tztype = tzTimeType;
+                cal.adoptTimeZone(tz);
+                return pos.getIndex();
+            }
+            return -start;
+        }
+    case UDAT_TIMEZONE_ISO_LOCAL_FIELD: // 'x'
+        {
+            UTimeZoneFormatTimeType tzTimeType = UTZFMT_TIME_TYPE_UNKNOWN;
+            UTimeZoneFormatStyle style;
+            switch (count) {
+            case 1:
+                style = UTZFMT_STYLE_ISO_BASIC_LOCAL_SHORT;
+                break;
+            case 2:
+                style = UTZFMT_STYLE_ISO_BASIC_LOCAL_FIXED;
+                break;
+            case 3:
+                style = UTZFMT_STYLE_ISO_EXTENDED_LOCAL_FIXED;
+                break;
+            case 4:
+                style = UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL;
+                break;
+            default:
+                style = UTZFMT_STYLE_ISO_EXTENDED_LOCAL_FULL;
+                break;
+            }
             TimeZone *tz  = tzFormat()->parse(style, text, pos, &tzTimeType);
             if (tz != NULL) {
                 ((SimpleDateFormat*)this)->tztype = tzTimeType;
index ca98ef30bd086433e2988eb08aba200535d3d9a7..de324ae8b650132b1aeab941c7b6460e8ec767ef 100644 (file)
@@ -1,6 +1,6 @@
 /*
 *******************************************************************************
-* Copyright (C) 1997-2012, International Business Machines Corporation and    *
+* Copyright (C) 1997-2013, International Business Machines Corporation and    *
 * others. All Rights Reserved.                                                *
 *******************************************************************************
 *
@@ -1252,7 +1252,11 @@ TimeZone::getDisplayName(UBool daylight, EDisplayType style, const Locale& local
         // appropriate for the requested daylight value.
         if ((daylight && timeType == UTZFMT_TIME_TYPE_STANDARD) || (!daylight && timeType == UTZFMT_TIME_TYPE_DAYLIGHT)) {
             offset = daylight ? getRawOffset() + getDSTSavings() : getRawOffset();
-            tzfmt->formatOffsetLocalizedGMT(offset, result, status);
+            if (style == SHORT_GENERIC) {
+                tzfmt->formatOffsetShortLocalizedGMT(offset, result, status);
+            } else {
+                tzfmt->formatOffsetLocalizedGMT(offset, result, status);
+            }
         }
     } else if (style == LONG_GMT || style == SHORT_GMT) {
         LocalPointer<TimeZoneFormat> tzfmt(TimeZoneFormat::createInstance(locale, status));
@@ -1266,7 +1270,7 @@ TimeZone::getDisplayName(UBool daylight, EDisplayType style, const Locale& local
             tzfmt->formatOffsetLocalizedGMT(offset, result, status);
             break;
         case SHORT_GMT:
-            tzfmt->formatOffsetRFC822(offset, result, status);
+            tzfmt->formatOffsetISO8601Basic(offset, FALSE, FALSE, FALSE, result, status);
             break;
         default:
             U_ASSERT(FALSE);
@@ -1297,7 +1301,11 @@ TimeZone::getDisplayName(UBool daylight, EDisplayType style, const Locale& local
             // Fallback to localized GMT
             LocalPointer<TimeZoneFormat> tzfmt(TimeZoneFormat::createInstance(locale, status));
             offset = daylight && useDaylightTime() ? getRawOffset() + getDSTSavings() : getRawOffset();
-            tzfmt->formatOffsetLocalizedGMT(offset, result, status);
+            if (style == LONG) {
+                tzfmt->formatOffsetLocalizedGMT(offset, result, status);
+            } else {
+                tzfmt->formatOffsetShortLocalizedGMT(offset, result, status);
+            }
         }
     }
     if (U_FAILURE(status)) {
index a7c7f9a4e3caf2c25821119ad28249c9acd9dd21..f54193d7aa6d8e7f0f9f16431b46c52ff2778b52 100644 (file)
@@ -1,6 +1,6 @@
 /*
 *******************************************************************************
-* Copyright (C) 2011-2012, International Business Machines Corporation and    *
+* Copyright (C) 2011-2013, International Business Machines Corporation and    *
 * others. All Rights Reserved.                                                *
 *******************************************************************************
 */
 #include "ureslocs.h"
 #include "uvector.h"
 #include "zonemeta.h"
+#include "tznames_impl.h"   // TextTrieMap
 
 U_NAMESPACE_BEGIN
 
+// Bit flags used by the parse method.
+// The order must match UTimeZoneFormatStyle enum.
+#define ISO_Z_STYLE_FLAG 0x0080
+#define ISO_LOCAL_STYLE_FLAG 0x0100
+static const int16_t STYLE_PARSE_FLAGS[] = {
+    0x0001, // UTZFMT_STYLE_GENERIC_LOCATION,
+    0x0002, // UTZFMT_STYLE_GENERIC_LONG,
+    0x0004, // UTZFMT_STYLE_GENERIC_SHORT,
+    0x0008, // UTZFMT_STYLE_SPECIFIC_LONG,
+    0x0010, // UTZFMT_STYLE_SPECIFIC_SHORT,
+    0x0020, // UTZFMT_STYLE_LOCALIZED_GMT,
+    0x0040, // UTZFMT_STYLE_LOCALIZED_GMT_SHORT,
+    ISO_Z_STYLE_FLAG,       // UTZFMT_STYLE_ISO_BASIC_SHORT,
+    ISO_LOCAL_STYLE_FLAG,   // UTZFMT_STYLE_ISO_BASIC_LOCAL_SHORT,
+    ISO_Z_STYLE_FLAG,       // UTZFMT_STYLE_ISO_BASIC_FIXED,
+    ISO_LOCAL_STYLE_FLAG,   // UTZFMT_STYLE_ISO_BASIC_LOCAL_FIXED,
+    ISO_Z_STYLE_FLAG,       // UTZFMT_STYLE_ISO_BASIC_FULL,
+    ISO_LOCAL_STYLE_FLAG,   // UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL,
+    ISO_Z_STYLE_FLAG,       // UTZFMT_STYLE_ISO_EXTENDED_FIXED,
+    ISO_LOCAL_STYLE_FLAG,   // UTZFMT_STYLE_ISO_EXTENDED_LOCAL_FIXED,
+    ISO_Z_STYLE_FLAG,       // UTZFMT_STYLE_ISO_EXTENDED_FULL,
+    ISO_LOCAL_STYLE_FLAG,   // UTZFMT_STYLE_ISO_EXTENDED_LOCAL_FULL,
+    0x0200, // UTZFMT_STYLE_ZONE_ID,
+    0x0400, // UTZFMT_STYLE_ZONE_ID_SHORT,
+    0x0800  // UTZFMT_STYLE_EXEMPLAR_LOCATION
+};
+
 static const char gZoneStringsTag[] = "zoneStrings";
 static const char gGmtFormatTag[]= "gmtFormat";
 static const char gGmtZeroFormatTag[] = "gmtZeroFormat";
 static const char gHourFormatTag[]= "hourFormat";
 
 static const UChar TZID_GMT[] = {0x0045, 0x0074, 0x0063, 0x002F, 0x0047, 0x004D, 0x0054, 0};    // Etc/GMT
+static const UChar UNKNOWN_ZONE_ID[] = {
+    0x0045, 0x0074, 0x0063, 0x002F, 0x0055, 0x006E, 0x006B, 0x006E, 0x006F, 0x0077, 0x006E, 0}; // Etc/Unknown
+static const UChar UNKNOWN_SHORT_ZONE_ID[] = {0x0075, 0x006E, 0x006B, 0};   // unk
+static const UChar UNKNOWN_LOCATION[] = {0x0055, 0x006E, 0x006B, 0x006E, 0x006F, 0x0077, 0x006E, 0};    // Unknown
 
 static const UChar DEFAULT_GMT_PATTERN[] = {0x0047, 0x004D, 0x0054, 0x007B, 0x0030, 0x007D, 0}; // GMT{0}
 //static const UChar DEFAULT_GMT_ZERO[] = {0x0047, 0x004D, 0x0054, 0}; // GMT
-static const UChar DEFAULT_GMT_POSITIVE_HM[] = {0x002B, 0x0048, 0x0048, 0x003A, 0x006D, 0x006D, 0}; // +HH:mm
-static const UChar DEFAULT_GMT_POSITIVE_HMS[] = {0x002B, 0x0048, 0x0048, 0x003A, 0x006D, 0x006D, 0x003A, 0x0073, 0x0073, 0}; // +HH:mm:ss
-static const UChar DEFAULT_GMT_NEGATIVE_HM[] = {0x002D, 0x0048, 0x0048, 0x003A, 0x006D, 0x006D, 0}; // -HH:mm
-static const UChar DEFAULT_GMT_NEGATIVE_HMS[] = {0x002D, 0x0048, 0x0048, 0x003A, 0x006D, 0x006D, 0x003A, 0x0073, 0x0073, 0}; // -HH:mm:ss
+static const UChar DEFAULT_GMT_POSITIVE_HM[] = {0x002B, 0x0048, 0x003A, 0x006D, 0x006D, 0}; // +H:mm
+static const UChar DEFAULT_GMT_POSITIVE_HMS[] = {0x002B, 0x0048, 0x003A, 0x006D, 0x006D, 0x003A, 0x0073, 0x0073, 0}; // +H:mm:ss
+static const UChar DEFAULT_GMT_NEGATIVE_HM[] = {0x002D, 0x0048, 0x003A, 0x006D, 0x006D, 0}; // -H:mm
+static const UChar DEFAULT_GMT_NEGATIVE_HMS[] = {0x002D, 0x0048, 0x003A, 0x006D, 0x006D, 0x003A, 0x0073, 0x0073, 0}; // -H:mm:ss
+static const UChar DEFAULT_GMT_POSITIVE_H[] = {0x002B, 0x0048, 0}; // +H
+static const UChar DEFAULT_GMT_NEGATIVE_H[] = {0x002D, 0x0048, 0}; // -H
 
 static const UChar32 DEFAULT_GMT_DIGITS[] = {
     0x0030, 0x0031, 0x0032, 0x0033, 0x0034,
@@ -50,7 +84,7 @@ static const UChar32 DEFAULT_GMT_DIGITS[] = {
 static const UChar DEFAULT_GMT_OFFSET_SEP = 0x003A; // ':'
 
 static const UChar ARG0[] = {0x007B, 0x0030, 0x007D};   // "{0}"
-static const int ARG0_LEN = 3;
+static const int32_t ARG0_LEN = 3;
 
 static const UChar DEFAULT_GMT_OFFSET_MINUTE_PATTERN[] = {0x006D, 0x006D, 0};   // "mm"
 static const UChar DEFAULT_GMT_OFFSET_SECOND_PATTERN[] = {0x0073, 0x0073, 0};   // "ss"
@@ -69,6 +103,8 @@ static const int32_t PARSE_GMT_OFFSET_TYPES[] = {
     UTZFMT_PAT_NEGATIVE_HMS,
     UTZFMT_PAT_POSITIVE_HM,
     UTZFMT_PAT_NEGATIVE_HM,
+    UTZFMT_PAT_POSITIVE_H,
+    UTZFMT_PAT_NEGATIVE_H,
     -1
 };
 
@@ -92,13 +128,42 @@ static const int32_t MAX_OFFSET_SECOND = 59;
 
 static const int32_t UNKNOWN_OFFSET = 0x7FFFFFFF;
 
-static const int32_t ALL_SPECIFIC_NAME_TYPES = UTZNM_LONG_STANDARD | UTZNM_LONG_DAYLIGHT | UTZNM_SHORT_STANDARD | UTZNM_SHORT_DAYLIGHT;
+static const int32_t ALL_SIMPLE_NAME_TYPES = UTZNM_LONG_STANDARD | UTZNM_LONG_DAYLIGHT | UTZNM_SHORT_STANDARD | UTZNM_SHORT_DAYLIGHT | UTZNM_EXEMPLAR_LOCATION;
 static const int32_t ALL_GENERIC_NAME_TYPES = UTZGNM_LOCATION | UTZGNM_LONG | UTZGNM_SHORT;
 
-#define STYLE_FLAG(c) (1 << (c))
 #define DIGIT_VAL(c) (0x0030 <= (c) && (c) <= 0x0039 ? (c) - 0x0030 : -1)
 #define MAX_OFFSET_DIGITS 6
 
+// Time Zone ID/Short ID trie
+static TextTrieMap *gZoneIdTrie = NULL;
+static UBool gZoneIdTrieInitialized = FALSE;
+
+static TextTrieMap *gShortZoneIdTrie = NULL;
+static UBool gShortZoneIdTrieInitialized = FALSE;
+
+static UMutex gLock = U_MUTEX_INITIALIZER;
+
+U_CDECL_BEGIN
+/**
+ * Cleanup callback func
+ */
+static UBool U_CALLCONV tzfmt_cleanup(void)
+{
+    if (gZoneIdTrie != NULL) {
+        delete gZoneIdTrie;
+    }
+    gZoneIdTrie = NULL;
+    gZoneIdTrieInitialized = FALSE;
+
+    if (gShortZoneIdTrie != NULL) {
+        delete gShortZoneIdTrie;
+    }
+    gShortZoneIdTrie = NULL;
+    gShortZoneIdTrieInitialized = FALSE;
+
+    return TRUE;
+}
+U_CDECL_END
 
 // ------------------------------------------------------------------
 // GMTOffsetField
@@ -245,7 +310,7 @@ UOBJECT_DEFINE_RTTI_IMPLEMENTATION(TimeZoneFormat)
 TimeZoneFormat::TimeZoneFormat(const Locale& locale, UErrorCode& status) 
 : fLocale(locale), fTimeZoneNames(NULL), fTimeZoneGenericNames(NULL), fDefParseOptionFlags(0) {
 
-    for (int32_t i = 0; i <= UTZFMT_PAT_NEGATIVE_HMS; i++) {
+    for (int32_t i = 0; i < UTZFMT_PAT_COUNT; i++) {
         fGMTOffsetPatternItems[i] = NULL;
     }
 
@@ -299,20 +364,27 @@ TimeZoneFormat::TimeZoneFormat(const Locale& locale, UErrorCode& status)
     }
     initGMTPattern(UnicodeString(gmtPattern, -1), status);
 
-    UBool useDefHourFmt = TRUE;
+    UBool useDefaultOffsetPatterns = TRUE;
     if (hourFormats) {
         UChar *sep = u_strchr(hourFormats, (UChar)0x003B /* ';' */);
         if (sep != NULL) {
+            UErrorCode tmpStatus = U_ZERO_ERROR;
             fGMTOffsetPatterns[UTZFMT_PAT_POSITIVE_HM].setTo(FALSE, hourFormats, (int32_t)(sep - hourFormats));
             fGMTOffsetPatterns[UTZFMT_PAT_NEGATIVE_HM].setTo(TRUE, sep + 1, -1);
-            expandOffsetPattern(fGMTOffsetPatterns[UTZFMT_PAT_POSITIVE_HM], fGMTOffsetPatterns[UTZFMT_PAT_POSITIVE_HMS]);
-            expandOffsetPattern(fGMTOffsetPatterns[UTZFMT_PAT_NEGATIVE_HM], fGMTOffsetPatterns[UTZFMT_PAT_NEGATIVE_HMS]);
-            useDefHourFmt = FALSE;
+            expandOffsetPattern(fGMTOffsetPatterns[UTZFMT_PAT_POSITIVE_HM], fGMTOffsetPatterns[UTZFMT_PAT_POSITIVE_HMS], tmpStatus);
+            expandOffsetPattern(fGMTOffsetPatterns[UTZFMT_PAT_NEGATIVE_HM], fGMTOffsetPatterns[UTZFMT_PAT_NEGATIVE_HMS], tmpStatus);
+            truncateOffsetPattern(fGMTOffsetPatterns[UTZFMT_PAT_POSITIVE_HM], fGMTOffsetPatterns[UTZFMT_PAT_POSITIVE_H], tmpStatus);
+            truncateOffsetPattern(fGMTOffsetPatterns[UTZFMT_PAT_NEGATIVE_HM], fGMTOffsetPatterns[UTZFMT_PAT_NEGATIVE_H], tmpStatus);
+            if (U_SUCCESS(tmpStatus)) {
+                useDefaultOffsetPatterns = FALSE;
+            }
         }
     }
-    if (useDefHourFmt) {
+    if (useDefaultOffsetPatterns) {
+        fGMTOffsetPatterns[UTZFMT_PAT_POSITIVE_H].setTo(TRUE, DEFAULT_GMT_POSITIVE_H, -1);
         fGMTOffsetPatterns[UTZFMT_PAT_POSITIVE_HM].setTo(TRUE, DEFAULT_GMT_POSITIVE_HM, -1);
         fGMTOffsetPatterns[UTZFMT_PAT_POSITIVE_HMS].setTo(TRUE, DEFAULT_GMT_POSITIVE_HMS, -1);
+        fGMTOffsetPatterns[UTZFMT_PAT_NEGATIVE_H].setTo(TRUE, DEFAULT_GMT_NEGATIVE_H, -1);
         fGMTOffsetPatterns[UTZFMT_PAT_NEGATIVE_HM].setTo(TRUE, DEFAULT_GMT_NEGATIVE_HM, -1);
         fGMTOffsetPatterns[UTZFMT_PAT_NEGATIVE_HMS].setTo(TRUE, DEFAULT_GMT_NEGATIVE_HMS, -1);
     }
@@ -333,7 +405,7 @@ TimeZoneFormat::TimeZoneFormat(const Locale& locale, UErrorCode& status)
 TimeZoneFormat::TimeZoneFormat(const TimeZoneFormat& other)
 : Format(other), fTimeZoneNames(NULL), fTimeZoneGenericNames(NULL) {
 
-    for (int32_t i = 0; i <= UTZFMT_PAT_NEGATIVE_HMS; i++) {
+    for (int32_t i = 0; i < UTZFMT_PAT_COUNT; i++) {
         fGMTOffsetPatternItems[i] = NULL;
     }
     *this = other;
@@ -343,7 +415,7 @@ TimeZoneFormat::TimeZoneFormat(const TimeZoneFormat& other)
 TimeZoneFormat::~TimeZoneFormat() {
     delete fTimeZoneNames;
     delete fTimeZoneGenericNames;
-    for (int32_t i = 0; i <= UTZFMT_PAT_NEGATIVE_HMS; i++) {
+    for (int32_t i = 0; i < UTZFMT_PAT_COUNT; i++) {
         delete fGMTOffsetPatternItems[i];
     }
 }
@@ -371,7 +443,7 @@ TimeZoneFormat::operator=(const TimeZoneFormat& other) {
     fGMTPatternSuffix = other.fGMTPatternSuffix;
 
     UErrorCode status = U_ZERO_ERROR;
-    for (int32_t i = 0; i <= UTZFMT_PAT_NEGATIVE_HMS; i++) {
+    for (int32_t i = 0; i < UTZFMT_PAT_COUNT; i++) {
         fGMTOffsetPatterns[i] = other.fGMTOffsetPatterns[i];
         delete fGMTOffsetPatternItems[i];
     }
@@ -398,7 +470,7 @@ TimeZoneFormat::operator==(const Format& other) const {
             && fGMTZeroFormat == tzfmt->fGMTZeroFormat
             && *fTimeZoneNames == *tzfmt->fTimeZoneNames;
 
-    for (int32_t i = 0; i <= UTZFMT_PAT_NEGATIVE_HMS && isEqual; i++) {
+    for (int32_t i = 0; i < UTZFMT_PAT_COUNT && isEqual; i++) {
         isEqual = fGMTOffsetPatterns[i] == tzfmt->fGMTOffsetPatterns[i];
     }
     for (int32_t i = 0; i < 10 && isEqual; i++) {
@@ -486,7 +558,24 @@ TimeZoneFormat::setGMTOffsetPattern(UTimeZoneFormatGMTOffsetPatternType type, co
         return;
     }
 
-    OffsetFields required = (type == UTZFMT_PAT_POSITIVE_HMS || type == UTZFMT_PAT_NEGATIVE_HMS) ? FIELDS_HMS : FIELDS_HM;
+    OffsetFields required = FIELDS_HM;
+    switch (type) {
+    case UTZFMT_PAT_POSITIVE_H:
+    case UTZFMT_PAT_NEGATIVE_H:
+        required = FIELDS_H;
+        break;
+    case UTZFMT_PAT_POSITIVE_HM:
+    case UTZFMT_PAT_NEGATIVE_HM:
+        required = FIELDS_HM;
+        break;
+    case UTZFMT_PAT_POSITIVE_HMS:
+    case UTZFMT_PAT_NEGATIVE_HMS:
+        required = FIELDS_HMS;
+        break;
+    default:
+        U_ASSERT(FALSE);
+        break;
+    }
 
     UVector* patternItems = parseOffsetPattern(pattern, required, status);
     if (patternItems == NULL) {
@@ -496,6 +585,7 @@ TimeZoneFormat::setGMTOffsetPattern(UTimeZoneFormatGMTOffsetPatternType type, co
     fGMTOffsetPatterns[type].setTo(pattern);
     delete fGMTOffsetPatternItems[type];
     fGMTOffsetPatternItems[type] = patternItems;
+    checkAbuttingHoursAndMinutes();
 }
 
 UnicodeString&
@@ -561,9 +651,7 @@ TimeZoneFormat::format(UTimeZoneFormatStyle style, const TimeZone& tz, UDate dat
     case UTZFMT_STYLE_SPECIFIC_SHORT:
         formatSpecific(tz, UTZNM_SHORT_STANDARD, UTZNM_SHORT_DAYLIGHT, date, name, timeType);
         break;
-    case UTZFMT_STYLE_RFC822:
-    case UTZFMT_STYLE_ISO8601:
-    case UTZFMT_STYLE_LOCALIZED_GMT:
+    default:
         // will be handled below
         break;
     }
@@ -572,23 +660,84 @@ TimeZoneFormat::format(UTimeZoneFormatStyle style, const TimeZone& tz, UDate dat
         UErrorCode status = U_ZERO_ERROR;
         int32_t rawOffset, dstOffset;
         tz.getOffset(date, FALSE, rawOffset, dstOffset, status);
+        int32_t offset = rawOffset + dstOffset;
         if (U_SUCCESS(status)) {
             switch (style) {
-            case UTZFMT_STYLE_RFC822:
-                formatOffsetRFC822(rawOffset + dstOffset, name, status);
+            case UTZFMT_STYLE_GENERIC_LOCATION:
+            case UTZFMT_STYLE_GENERIC_LONG:
+            case UTZFMT_STYLE_SPECIFIC_LONG:
+            case UTZFMT_STYLE_LOCALIZED_GMT:
+                formatOffsetLocalizedGMT(offset, name, status);
+                break;
+
+            case UTZFMT_STYLE_GENERIC_SHORT:
+            case UTZFMT_STYLE_SPECIFIC_SHORT:
+            case UTZFMT_STYLE_LOCALIZED_GMT_SHORT:
+                formatOffsetShortLocalizedGMT(offset, name, status);
                 break;
-            case UTZFMT_STYLE_ISO8601:
-                formatOffsetISO8601(rawOffset + dstOffset, name, status);
+
+            case UTZFMT_STYLE_ISO_BASIC_SHORT:
+                formatOffsetISO8601Basic(offset, TRUE, TRUE, TRUE, name, status);
                 break;
-            default:
-                formatOffsetLocalizedGMT(rawOffset + dstOffset, name, status);
+
+            case UTZFMT_STYLE_ISO_BASIC_LOCAL_SHORT:
+                formatOffsetISO8601Basic(offset, FALSE, TRUE, TRUE, name, status);
+                break;
+
+            case UTZFMT_STYLE_ISO_BASIC_FIXED:
+                formatOffsetISO8601Basic(offset, TRUE, FALSE, TRUE, name, status);
+                break;
+
+            case UTZFMT_STYLE_ISO_BASIC_LOCAL_FIXED:
+                formatOffsetISO8601Basic(offset, FALSE, FALSE, TRUE, name, status);
+                break;
+
+            case UTZFMT_STYLE_ISO_EXTENDED_FIXED:
+                formatOffsetISO8601Extended(offset, TRUE, FALSE, TRUE, name, status);
+                break;
+
+            case UTZFMT_STYLE_ISO_EXTENDED_LOCAL_FIXED:
+                formatOffsetISO8601Extended(offset, FALSE, FALSE, TRUE, name, status);
+                break;
+
+            case UTZFMT_STYLE_ISO_BASIC_FULL:
+                formatOffsetISO8601Basic(offset, TRUE, FALSE, FALSE, name, status);
+                break;
+
+            case UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL:
+                formatOffsetISO8601Basic(offset, FALSE, FALSE, FALSE, name, status);
+                break;
+
+            case UTZFMT_STYLE_ISO_EXTENDED_FULL:
+                formatOffsetISO8601Extended(offset, TRUE, FALSE, FALSE, name, status);
+                break;
+
+            case UTZFMT_STYLE_ISO_EXTENDED_LOCAL_FULL:
+                formatOffsetISO8601Extended(offset, FALSE, FALSE, FALSE, name, status);
+                break;
+
+            case UTZFMT_STYLE_ZONE_ID:
+                tz.getID(name);
+                break;
+
+            case UTZFMT_STYLE_ZONE_ID_SHORT:
+                {
+                    const UChar* shortID = ZoneMeta::getShortID(tz);
+                    if (shortID == NULL) {
+                        shortID = UNKNOWN_SHORT_ZONE_ID;
+                    }
+                    name.setTo(shortID, -1);
+                }
+                break;
+
+            case UTZFMT_STYLE_EXEMPLAR_LOCATION:
+                formatExemplarLocation(tz, name);
                 break;
             }
             if (timeType) {
                 *timeType = (dstOffset != 0) ? UTZFMT_TIME_TYPE_DAYLIGHT : UTZFMT_TIME_TYPE_STANDARD;
             }
         }
-        U_ASSERT(U_SUCCESS(status));
     }
 
     return name;
@@ -645,23 +794,22 @@ TimeZoneFormat::parse(UTimeZoneFormatStyle style, const UnicodeString& text, Par
     int32_t maxPos = text.length();
     int32_t offset;
 
-    UBool fallbackLocalizedGMT = FALSE;
-    if (style == UTZFMT_STYLE_SPECIFIC_LONG || style == UTZFMT_STYLE_SPECIFIC_SHORT
-        || style == UTZFMT_STYLE_GENERIC_LONG || style == UTZFMT_STYLE_GENERIC_SHORT || style == UTZFMT_STYLE_GENERIC_LOCATION) {
-        // above styles may use localized gmt format as fallback
-        fallbackLocalizedGMT = TRUE;
-    }
+    // Styles using localized GMT format as fallback
+    UBool fallbackLocalizedGMT = 
+        (style == UTZFMT_STYLE_SPECIFIC_LONG || style == UTZFMT_STYLE_GENERIC_LONG || style == UTZFMT_STYLE_GENERIC_LOCATION);
+    UBool fallbackShortLocalizedGMT =
+        (style == UTZFMT_STYLE_SPECIFIC_SHORT || style == UTZFMT_STYLE_GENERIC_SHORT);
 
-    int32_t evaluated = 0;
+    int32_t evaluated = 0;  // bit flags representing already evaluated styles
     ParsePosition tmpPos(startIdx);
 
     int32_t parsedOffset = UNKNOWN_OFFSET;  // stores successfully parsed offset for later use
     int32_t parsedPos = -1;                 // stores successfully parsed offset position for later use
 
     // Try localized GMT format first if necessary
-    if (fallbackLocalizedGMT) {
+    if (fallbackLocalizedGMT || fallbackShortLocalizedGMT) {
         UBool hasDigitOffset = FALSE;
-        offset = parseOffsetLocalizedGMT(text, tmpPos, &hasDigitOffset);
+        offset = parseOffsetLocalizedGMT(text, tmpPos, fallbackShortLocalizedGMT, &hasDigitOffset);
         if (tmpPos.getErrorIndex() == -1) {
             // Even when the input text was successfully parsed as a localized GMT format text,
             // we may still need to evaluate the specified style if -
@@ -674,50 +822,88 @@ TimeZoneFormat::parse(UTimeZoneFormatStyle style, const UnicodeString& text, Par
             parsedOffset = offset;
             parsedPos = tmpPos.getIndex();
         }
-        evaluated |= STYLE_FLAG(UTZFMT_STYLE_LOCALIZED_GMT);
-
-        tmpPos.setIndex(startIdx);
-        tmpPos.setErrorIndex(-1);
+        // Note: For now, no distinction between long/short localized GMT format in the parser.
+        // This might be changed in future.
+        // evaluated |= (fallbackLocalizedGMT ? STYLE_PARSE_FLAGS[UTZFMT_STYLE_LOCALIZED_GMT] : STYLE_PARSE_FLAGS[UTZFMT_STYLE_LOCALIZED_GMT_SHORT]);
+        evaluated |= STYLE_PARSE_FLAGS[UTZFMT_STYLE_LOCALIZED_GMT] | STYLE_PARSE_FLAGS[UTZFMT_STYLE_LOCALIZED_GMT_SHORT];
     }
 
     UErrorCode status = U_ZERO_ERROR;
     UnicodeString tzID;
-    UTimeZoneFormatTimeType parsedTimeType = UTZFMT_TIME_TYPE_UNKNOWN;
 
     // Try the specified style
     switch (style) {
-    case UTZFMT_STYLE_RFC822:
+    case UTZFMT_STYLE_LOCALIZED_GMT:
         {
-            offset = parseOffsetRFC822(text, tmpPos);
+            tmpPos.setIndex(startIdx);
+            tmpPos.setErrorIndex(-1);
+
+            offset = parseOffsetLocalizedGMT(text, tmpPos);
             if (tmpPos.getErrorIndex() == -1) {
                 pos.setIndex(tmpPos.getIndex());
                 return createTimeZoneForOffset(offset);
             }
-        }
-        break;
 
-    case UTZFMT_STYLE_LOCALIZED_GMT:
+            // Note: For now, no distinction between long/short localized GMT format in the parser.
+            // This might be changed in future.
+            evaluated |= STYLE_PARSE_FLAGS[UTZFMT_STYLE_LOCALIZED_GMT_SHORT];
+
+            break;
+        }
+    case UTZFMT_STYLE_LOCALIZED_GMT_SHORT:
         {
-            offset = parseOffsetLocalizedGMT(text, tmpPos);
+            tmpPos.setIndex(startIdx);
+            tmpPos.setErrorIndex(-1);
+
+            offset = parseOffsetShortLocalizedGMT(text, tmpPos);
             if (tmpPos.getErrorIndex() == -1) {
                 pos.setIndex(tmpPos.getIndex());
                 return createTimeZoneForOffset(offset);
             }
-        }
-        break;
 
-    case UTZFMT_STYLE_ISO8601:
+            // Note: For now, no distinction between long/short localized GMT format in the parser.
+            // This might be changed in future.
+            evaluated |= STYLE_PARSE_FLAGS[UTZFMT_STYLE_LOCALIZED_GMT];
+
+            break;
+        }
+    case UTZFMT_STYLE_ISO_BASIC_SHORT:
+    case UTZFMT_STYLE_ISO_BASIC_FIXED:
+    case UTZFMT_STYLE_ISO_BASIC_FULL:
+    case UTZFMT_STYLE_ISO_EXTENDED_FIXED:
+    case UTZFMT_STYLE_ISO_EXTENDED_FULL:
         {
+            tmpPos.setIndex(startIdx);
+            tmpPos.setErrorIndex(-1);
+
             offset = parseOffsetISO8601(text, tmpPos);
             if (tmpPos.getErrorIndex() == -1) {
                 pos.setIndex(tmpPos.getIndex());
                 return createTimeZoneForOffset(offset);
             }
-            // Note: ISO 8601 parser also support basic format (without ':'),
-            // which is same with RFC 822 format.
-            evaluated |= STYLE_FLAG(UTZFMT_STYLE_RFC822);
+
+            break;
+        }
+
+    case UTZFMT_STYLE_ISO_BASIC_LOCAL_SHORT:
+    case UTZFMT_STYLE_ISO_BASIC_LOCAL_FIXED:
+    case UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL:
+    case UTZFMT_STYLE_ISO_EXTENDED_LOCAL_FIXED:
+    case UTZFMT_STYLE_ISO_EXTENDED_LOCAL_FULL:
+        {
+            tmpPos.setIndex(startIdx);
+            tmpPos.setErrorIndex(-1);
+
+            // Exclude the case of UTC Indicator "Z" here
+            UBool hasDigitOffset = FALSE;
+            offset = parseOffsetISO8601(text, tmpPos, FALSE, &hasDigitOffset);
+            if (tmpPos.getErrorIndex() == -1 && hasDigitOffset) {
+                pos.setIndex(tmpPos.getIndex());
+                return createTimeZoneForOffset(offset);
+            }
+
+            break;
         }
-        break;
 
     case UTZFMT_STYLE_SPECIFIC_LONG:
     case UTZFMT_STYLE_SPECIFIC_SHORT:
@@ -755,9 +941,8 @@ TimeZoneFormat::parse(UTimeZoneFormatStyle style, const UnicodeString& text, Par
                     return TimeZone::createTimeZone(tzID);
                 }
             }
+            break;
         }
-        break;
-
     case UTZFMT_STYLE_GENERIC_LONG:
     case UTZFMT_STYLE_GENERIC_SHORT:
     case UTZFMT_STYLE_GENERIC_LOCATION:
@@ -781,9 +966,10 @@ TimeZoneFormat::parse(UTimeZoneFormatStyle style, const UnicodeString& text, Par
             }
 
             int32_t len = 0;
+            UTimeZoneFormatTimeType tt = UTZFMT_TIME_TYPE_UNKNOWN;
             const TimeZoneGenericNames *gnames = getTimeZoneGenericNames(status);
             if (U_SUCCESS(status)) {
-                len = gnames->findBestMatch(text, startIdx, genericNameTypes, tzID, parsedTimeType, status);
+                len = gnames->findBestMatch(text, startIdx, genericNameTypes, tzID, tt, status);
             }
             if (U_FAILURE(status)) {
                 pos.setErrorIndex(startIdx);
@@ -792,16 +978,53 @@ TimeZoneFormat::parse(UTimeZoneFormatStyle style, const UnicodeString& text, Par
             if (len > 0) {
                 // Found a match
                 if (timeType) {
-                    *timeType = parsedTimeType;
+                    *timeType = tt;
                 }
                 pos.setIndex(startIdx + len);
                 U_ASSERT(!tzID.isEmpty());
                 return TimeZone::createTimeZone(tzID);
             }
+
+            break;
+        }
+    case UTZFMT_STYLE_ZONE_ID:
+        {
+            tmpPos.setIndex(startIdx);
+            tmpPos.setErrorIndex(-1);
+
+            parseZoneID(text, tmpPos, tzID);
+            if (tmpPos.getErrorIndex() == -1) {
+                pos.setIndex(tmpPos.getIndex());
+                return TimeZone::createTimeZone(tzID);
+            }
+            break;
+        }
+    case UTZFMT_STYLE_ZONE_ID_SHORT:
+        {
+            tmpPos.setIndex(startIdx);
+            tmpPos.setErrorIndex(-1);
+
+            parseShortZoneID(text, tmpPos, tzID);
+            if (tmpPos.getErrorIndex() == -1) {
+                pos.setIndex(tmpPos.getIndex());
+                return TimeZone::createTimeZone(tzID);
+            }
+            break;
+        }
+    case UTZFMT_STYLE_EXEMPLAR_LOCATION:
+        {
+            tmpPos.setIndex(startIdx);
+            tmpPos.setErrorIndex(-1);
+
+            parseExemplarLocation(text, tmpPos, tzID);
+            if (tmpPos.getErrorIndex() == -1) {
+                pos.setIndex(tmpPos.getIndex());
+                return TimeZone::createTimeZone(tzID);
+            }
+            break;
         }
-        break;
     }
-    evaluated |= STYLE_FLAG(style);
+    evaluated |= STYLE_PARSE_FLAGS[style];
 
 
     if (parsedPos > startIdx) {
@@ -818,13 +1041,18 @@ TimeZoneFormat::parse(UTimeZoneFormatStyle style, const UnicodeString& text, Par
 
     // Failed to parse the input text as the time zone format in the specified style.
     // Check the longest match among other styles below.
+    UnicodeString parsedID;
+    UTimeZoneFormatTimeType parsedTimeType = UTZFMT_TIME_TYPE_UNKNOWN;
+
     U_ASSERT(parsedPos < 0);
     U_ASSERT(parsedOffset == UNKNOWN_OFFSET);
-    tmpPos.setIndex(startIdx);
-    tmpPos.setErrorIndex(-1);
 
     // ISO 8601
-    if ((evaluated & STYLE_FLAG(UTZFMT_STYLE_ISO8601)) == 0) {
+    if (parsedPos < maxPos &&
+        ((evaluated & ISO_Z_STYLE_FLAG) == 0 || (evaluated & ISO_LOCAL_STYLE_FLAG) == 0)) {
+        tmpPos.setIndex(startIdx);
+        tmpPos.setErrorIndex(-1);
+
         UBool hasDigitOffset = FALSE;
         offset = parseOffsetISO8601(text, tmpPos, FALSE, &hasDigitOffset);
         if (tmpPos.getErrorIndex() == -1) {
@@ -833,49 +1061,64 @@ TimeZoneFormat::parse(UTimeZoneFormatStyle style, const UnicodeString& text, Par
                 return createTimeZoneForOffset(offset);
             }
             // Note: When ISO 8601 format contains offset digits, it should not
-            // collide with other formats (except RFC 822, which is compatible with
-            // ISO 8601 basic format). However, ISO 8601 UTC format "Z" (single letter)
-            // may collide with other names. In this case, we need to evaluate other
-            // names.
-            parsedOffset = offset;
-            parsedPos = tmpPos.getIndex();
-            U_ASSERT(parsedPos == startIdx + 1);    // only when "Z" is used
+            // collide with other formats. However, ISO 8601 UTC format "Z" (single letter)
+            // may collide with other names. In this case, we need to evaluate other names.
+            if (parsedPos < tmpPos.getIndex()) {
+                parsedOffset = offset;
+                parsedID.setToBogus();
+                parsedTimeType = UTZFMT_TIME_TYPE_UNKNOWN;
+                parsedPos = tmpPos.getIndex();
+                U_ASSERT(parsedPos == startIdx + 1);    // only when "Z" is used
+            }
         }
+    }
+
+    // Localized GMT format
+    if (parsedPos < maxPos &&
+        (evaluated & STYLE_PARSE_FLAGS[UTZFMT_STYLE_LOCALIZED_GMT]) == 0) {
         tmpPos.setIndex(startIdx);
         tmpPos.setErrorIndex(-1);
-    }
 
-    // RFC 822
-    // Note: ISO 8601 parser supports RFC 822 format. So we do not need to parse
-    // it as RFC 822 here. This might be changed in future when we support
-    // strict format option for ISO 8601 or RFC 822.
+        UBool hasDigitOffset = FALSE;
+        offset = parseOffsetLocalizedGMT(text, tmpPos, FALSE, &hasDigitOffset);
+        if (tmpPos.getErrorIndex() == -1) {
+            if (tmpPos.getIndex() == maxPos || hasDigitOffset) {
+                pos.setIndex(tmpPos.getIndex());
+                return createTimeZoneForOffset(offset);
+            }
+            // Evaluate other names - see the comment earlier in this method.
+            if (parsedPos < tmpPos.getIndex()) {
+                parsedOffset = offset;
+                parsedID.setToBogus();
+                parsedTimeType = UTZFMT_TIME_TYPE_UNKNOWN;
+                parsedPos = tmpPos.getIndex();
+            }
+        }
+    }
 
-    //if ((evaluated & STYLE_FLAG(UTZFMT_STYLE_RFC822)) == 0) {
-    //    offset = parseOffsetRFC822(text, tmpPos);
-    //    if (tmpPos.getErrorIndex() == -1) {
-    //        pos.setIndex(tmpPos.getIndex());
-    //        return createTimeZoneForOffset(offset);
-    //    }
-    //    tmpPos.setIndex(startIdx);
-    //    tmpPos.setErrorIndex(-1);
-    //}
+    if (parsedPos < maxPos &&
+        (evaluated & STYLE_PARSE_FLAGS[UTZFMT_STYLE_LOCALIZED_GMT_SHORT]) == 0) {
+        tmpPos.setIndex(startIdx);
+        tmpPos.setErrorIndex(-1);
 
-    // Localized GMT format
-    if ((evaluated & STYLE_FLAG(UTZFMT_STYLE_LOCALIZED_GMT)) == 0) {
         UBool hasDigitOffset = FALSE;
-        offset = parseOffsetLocalizedGMT(text, tmpPos, &hasDigitOffset);
+        offset = parseOffsetLocalizedGMT(text, tmpPos, TRUE, &hasDigitOffset);
         if (tmpPos.getErrorIndex() == -1) {
             if (tmpPos.getIndex() == maxPos || hasDigitOffset) {
                 pos.setIndex(tmpPos.getIndex());
                 return createTimeZoneForOffset(offset);
             }
             // Evaluate other names - see the comment earlier in this method.
-            parsedOffset = offset;
-            parsedPos = tmpPos.getIndex();
+            if (parsedPos < tmpPos.getIndex()) {
+                parsedOffset = offset;
+                parsedID.setToBogus();
+                parsedTimeType = UTZFMT_TIME_TYPE_UNKNOWN;
+                parsedPos = tmpPos.getIndex();
+            }
         }
     }
 
-    // When ParseOption.ALL_STYLES is available, we also try to look all possible display names.
+    // When ParseOption.ALL_STYLES is available, we also try to look all possible display names and IDs.
     // For example, when style is GENERIC_LONG, "EST" (SPECIFIC_SHORT) is never
     // used for America/New_York. With parseAllStyles true, this code parses "EST"
     // as America/New_York.
@@ -883,62 +1126,97 @@ TimeZoneFormat::parse(UTimeZoneFormatStyle style, const UnicodeString& text, Par
     // Note: Adding all possible names into the trie used by the implementation is quite heavy operation,
     // which we want to avoid normally (note that we cache the trie, so this is applicable to the
     // first time only as long as the cache does not expire).
+
     if (parseOptions & UTZFMT_PARSE_OPTION_ALL_STYLES) {
-        // Try all specific names first
-        LocalPointer<TimeZoneNames::MatchInfoCollection> spAllMatches(fTimeZoneNames->find(text, startIdx, ALL_SPECIFIC_NAME_TYPES, status));
-        if (U_FAILURE(status)) {
-            pos.setErrorIndex(startIdx);
-            return NULL;
-        }
-        int32_t spMatchIdx = -1;
-        if (!spAllMatches.isNull()) {
+        // Try all specific names and exemplar location names
+        if (parsedPos < maxPos) {
+            LocalPointer<TimeZoneNames::MatchInfoCollection> specificMatches(fTimeZoneNames->find(text, startIdx, ALL_SIMPLE_NAME_TYPES, status));
+            if (U_FAILURE(status)) {
+                pos.setErrorIndex(startIdx);
+                return NULL;
+            }
+            int32_t specificMatchIdx = -1;
             int32_t matchPos = -1;
-            for (int32_t i = 0; i < spAllMatches->size(); i++) {
-                matchPos  = startIdx + spAllMatches->getMatchLengthAt(i);
-                if (matchPos > parsedPos) {
-                    spMatchIdx = i;
-                    parsedPos = matchPos;
+            if (!specificMatches.isNull()) {
+                for (int32_t i = 0; i < specificMatches->size(); i++) {
+                    if (startIdx + specificMatches->getMatchLengthAt(i) > matchPos) {
+                        specificMatchIdx = i;
+                        matchPos = startIdx + specificMatches->getMatchLengthAt(i);
+                    }
                 }
             }
+            if (parsedPos < matchPos) {
+                U_ASSERT(specificMatchIdx >= 0);
+                parsedPos = matchPos;
+                getTimeZoneID(specificMatches.getAlias(), specificMatchIdx, parsedID);
+                parsedTimeType = getTimeType(specificMatches->getNameTypeAt(specificMatchIdx));
+                parsedOffset = UNKNOWN_OFFSET;
+            }
         }
-        int32_t genMatchLen = -1;
+        // Try generic names
         if (parsedPos < maxPos) {
+            int32_t genMatchLen = -1;
+            UTimeZoneFormatTimeType tt = UTZFMT_TIME_TYPE_UNKNOWN;
+
             const TimeZoneGenericNames *gnames = getTimeZoneGenericNames(status);
             if (U_SUCCESS(status)) {
-                genMatchLen = gnames->findBestMatch(text, startIdx, ALL_GENERIC_NAME_TYPES, tzID, parsedTimeType, status);
+                genMatchLen = gnames->findBestMatch(text, startIdx, ALL_GENERIC_NAME_TYPES, tzID, tt, status);
             }
             if (U_FAILURE(status)) {
                 pos.setErrorIndex(startIdx);
                 return NULL;
             }
+
+            if (parsedPos < startIdx + genMatchLen) {
+                parsedPos = startIdx + genMatchLen;
+                parsedID.setTo(tzID);
+                parsedTimeType = tt;
+                parsedOffset = UNKNOWN_OFFSET;
+            }
         }
-        // Pick up better match
-        if (startIdx + genMatchLen > parsedPos) {
-            // use generic name match
-            parsedPos = startIdx + genMatchLen;
-            if (timeType) {
-                *timeType = parsedTimeType;
+
+        // Try time zone ID
+        if (parsedPos < maxPos && (evaluated & STYLE_PARSE_FLAGS[UTZFMT_STYLE_ZONE_ID]) == 0) {
+            tmpPos.setIndex(startIdx);
+            tmpPos.setErrorIndex(-1);
+
+            parseZoneID(text, tmpPos, tzID);
+            if (tmpPos.getErrorIndex() == -1 && parsedPos < tmpPos.getIndex()) {
+                parsedPos = tmpPos.getIndex();
+                parsedID.setTo(tzID);
+                parsedTimeType = UTZFMT_TIME_TYPE_UNKNOWN;
+                parsedOffset = UNKNOWN_OFFSET;
             }
-            pos.setIndex(parsedPos);
-            U_ASSERT(!tzID.isEmpty());
-            return TimeZone::createTimeZone(tzID);
-        } else if (spMatchIdx >= 0) {
-            // use specific name match
-            if (timeType) {
-                *timeType = getTimeType(spAllMatches->getNameTypeAt(spMatchIdx));
+        }
+        // Try short time zone ID
+        if (parsedPos < maxPos && (evaluated & STYLE_PARSE_FLAGS[UTZFMT_STYLE_ZONE_ID]) == 0) {
+            tmpPos.setIndex(startIdx);
+            tmpPos.setErrorIndex(-1);
+
+            parseShortZoneID(text, tmpPos, tzID);
+            if (tmpPos.getErrorIndex() == -1 && parsedPos < tmpPos.getIndex()) {
+                parsedPos = tmpPos.getIndex();
+                parsedID.setTo(tzID);
+                parsedTimeType = UTZFMT_TIME_TYPE_UNKNOWN;
+                parsedOffset = UNKNOWN_OFFSET;
             }
-            pos.setIndex(parsedPos);
-            getTimeZoneID(spAllMatches.getAlias(), spMatchIdx, tzID);
-            U_ASSERT(!tzID.isEmpty());
-            return TimeZone::createTimeZone(tzID);
         }
     }
 
     if (parsedPos > startIdx) {
-        // Parsed successfully as one of 'offset' format
-        U_ASSERT(parsedOffset != UNKNOWN_OFFSET);
+        // Parsed successfully
+        TimeZone* parsedTZ;
+        if (parsedID.length() > 0) {
+            parsedTZ = TimeZone::createTimeZone(parsedID);
+        } else {
+            U_ASSERT(parsedOffset != UNKNOWN_OFFSET);
+            parsedTZ = createTimeZoneForOffset(parsedOffset);
+        }
+        if (timeType) {
+            *timeType = parsedTimeType;
+        }
         pos.setIndex(parsedPos);
-        return createTimeZoneForOffset(parsedOffset);
+        return parsedTZ;
     }
 
     pos.setErrorIndex(startIdx);
@@ -1004,8 +1282,6 @@ TimeZoneFormat::formatSpecific(const TimeZone& tz, UTimeZoneNameType stdType, UT
     return name;
 }
 
-static UMutex gLock = U_MUTEX_INITIALIZER;
-
 const TimeZoneGenericNames*
 TimeZoneFormat::getTimeZoneGenericNames(UErrorCode& status) const {
     if (U_FAILURE(status)) {
@@ -1028,28 +1304,143 @@ TimeZoneFormat::getTimeZoneGenericNames(UErrorCode& status) const {
     return fTimeZoneGenericNames;
 }
 
+UnicodeString&
+TimeZoneFormat::formatExemplarLocation(const TimeZone& tz, UnicodeString& name) const {
+    UnicodeString location;
+    const UChar* canonicalID = ZoneMeta::getCanonicalCLDRID(tz);
+
+    if (canonicalID) {
+        fTimeZoneNames->getExemplarLocationName(UnicodeString(canonicalID), location);
+    }
+    if (location.length() > 0) {
+        name.setTo(location);
+    } else {
+        // Use "unknown" location
+        fTimeZoneNames->getExemplarLocationName(UnicodeString(UNKNOWN_ZONE_ID), location);
+        if (location.length() > 0) {
+            name.setTo(location);
+        } else {
+            // last resort
+            name.setTo(UNKNOWN_LOCATION, -1);
+        }
+    }
+    return name;
+}
+
+
 // ------------------------------------------------------------------
 // Zone offset format and parse
 
 UnicodeString&
-TimeZoneFormat::formatOffsetRFC822(int32_t offset, UnicodeString& result, UErrorCode& status) const {
+TimeZoneFormat::formatOffsetISO8601Basic(int32_t offset, UBool useUtcIndicator, UBool isShort, UBool ignoreSeconds,
+        UnicodeString& result, UErrorCode& status) const {
+    return formatOffsetISO8601(offset, TRUE, useUtcIndicator, isShort, ignoreSeconds, result, status);
+}
+
+UnicodeString&
+TimeZoneFormat::formatOffsetISO8601Extended(int32_t offset, UBool useUtcIndicator, UBool isShort, UBool ignoreSeconds,
+        UnicodeString& result, UErrorCode& status) const {
+    return formatOffsetISO8601(offset, FALSE, useUtcIndicator, isShort, ignoreSeconds, result, status);
+}
+
+UnicodeString&
+TimeZoneFormat::formatOffsetLocalizedGMT(int32_t offset, UnicodeString& result, UErrorCode& status) const {
+    return formatOffsetLocalizedGMT(offset, FALSE, result, status);
+}
+
+UnicodeString&
+TimeZoneFormat::formatOffsetShortLocalizedGMT(int32_t offset, UnicodeString& result, UErrorCode& status) const {
+    return formatOffsetLocalizedGMT(offset, TRUE, result, status);
+}
+
+int32_t
+TimeZoneFormat::parseOffsetISO8601(const UnicodeString& text, ParsePosition& pos) const {
+    return parseOffsetISO8601(text, pos, FALSE);
+}
+
+int32_t
+TimeZoneFormat::parseOffsetLocalizedGMT(const UnicodeString& text, ParsePosition& pos) const {
+    return parseOffsetLocalizedGMT(text, pos, FALSE, NULL);
+}
+
+int32_t
+TimeZoneFormat::parseOffsetShortLocalizedGMT(const UnicodeString& text, ParsePosition& pos) const {
+    return parseOffsetLocalizedGMT(text, pos, TRUE, NULL);
+}
+
+// ------------------------------------------------------------------
+// Private zone offset format/parse implementation
+
+UnicodeString&
+TimeZoneFormat::formatOffsetISO8601(int32_t offset, UBool isBasic, UBool useUtcIndicator,
+        UBool isShort, UBool ignoreSeconds, UnicodeString& result, UErrorCode& status) const {
     if (U_FAILURE(status)) {
         result.setToBogus();
         return result;
     }
-    if (offset <= -MAX_OFFSET || offset >= MAX_OFFSET) {
+    int32_t absOffset = offset < 0 ? -offset : offset;
+    if (useUtcIndicator && (absOffset < MILLIS_PER_SECOND || (ignoreSeconds && absOffset < MILLIS_PER_MINUTE))) {
+        result.setTo(ISO8601_UTC);
+        return result;
+    }
+
+    OffsetFields minFields = isShort ? FIELDS_H : FIELDS_HM;
+    OffsetFields maxFields = ignoreSeconds ? FIELDS_HM : FIELDS_HMS;
+    UChar sep = isBasic ? 0 : ISO8601_SEP;
+
+    // Note: FIELDS_HMS as maxFields is a CLDR/ICU extension. ISO 8601 specification does
+    // not support seconds field.
+
+    if (absOffset >= MAX_OFFSET) {
         result.setToBogus();
         status = U_ILLEGAL_ARGUMENT_ERROR;
         return result;
     }
 
-    // Note: FIELDS_HMS as maxFields is an ICU extension. RFC822 specification
-    // defines exactly 4 digits for the offset field in HHss format.
-    return formatOffsetWithAsciiDigits(offset, 0, FIELDS_HM, FIELDS_HMS, result);
+    int fields[3];
+    fields[0] = absOffset / MILLIS_PER_HOUR;
+    absOffset = absOffset % MILLIS_PER_HOUR;
+    fields[1] = absOffset / MILLIS_PER_MINUTE;
+    absOffset = absOffset % MILLIS_PER_MINUTE;
+    fields[2] = absOffset / MILLIS_PER_SECOND;
+
+    U_ASSERT(fields[0] >= 0 && fields[0] <= MAX_OFFSET_HOUR);
+    U_ASSERT(fields[1] >= 0 && fields[1] <= MAX_OFFSET_MINUTE);
+    U_ASSERT(fields[2] >= 0 && fields[2] <= MAX_OFFSET_SECOND);
+
+    int32_t lastIdx = maxFields;
+    while (lastIdx > minFields) {
+        if (fields[lastIdx] != 0) {
+            break;
+        }
+        lastIdx--;
+    }
+
+    UChar sign = PLUS;
+    if (offset < 0) {
+        // if all output fields are 0s, do not use negative sign
+        for (int32_t idx = 0; idx <= lastIdx; idx++) {
+            if (fields[idx] != 0) {
+                sign = MINUS;
+                break;
+            }
+        }
+    }
+    result.setTo(sign);
+
+    for (int32_t idx = 0; idx <= lastIdx; idx++) {
+        if (sep && idx != 0) {
+            result.append(sep);
+        }
+        result.append((UChar)(0x0030 + fields[idx]/10));
+        result.append((UChar)(0x0030 + fields[idx]%10));
+    }
+
+    return result;
 }
 
 UnicodeString&
-TimeZoneFormat::formatOffsetISO8601(int32_t offset, UnicodeString& result, UErrorCode& status) const {
+TimeZoneFormat::formatOffsetLocalizedGMT(int32_t offset, UBool isShort, UnicodeString& result, UErrorCode& status) const {
     if (U_FAILURE(status)) {
         result.setToBogus();
         return result;
@@ -1061,26 +1452,7 @@ TimeZoneFormat::formatOffsetISO8601(int32_t offset, UnicodeString& result, UErro
     }
 
     if (offset == 0) {
-        result.setTo(ISO8601_UTC);
-        return result;
-    }
-    return formatOffsetWithAsciiDigits(offset, ISO8601_SEP, FIELDS_HM, FIELDS_HMS, result);
-}
-
-UnicodeString&
-TimeZoneFormat::formatOffsetLocalizedGMT(int32_t offset, UnicodeString& result, UErrorCode& status) const {
-    if (U_FAILURE(status)) {
-        result.setToBogus();
-        return result;
-    }
-    if (offset <= -MAX_OFFSET || offset >= MAX_OFFSET) {
-        result.setToBogus();
-        status = U_ILLEGAL_ARGUMENT_ERROR;
-        return result;
-    }
-
-    if (offset == 0) {
-        result.setTo(fGMTZeroFormat);
+        result.setTo(fGMTZeroFormat);
         return result;
     }
 
@@ -1100,13 +1472,21 @@ TimeZoneFormat::formatOffsetLocalizedGMT(int32_t offset, UnicodeString& result,
 
     const UVector* offsetPatternItems = NULL;
     if (positive) {
-        offsetPatternItems = (offsetS == 0) ?
-            fGMTOffsetPatternItems[UTZFMT_PAT_POSITIVE_HM] :
-            fGMTOffsetPatternItems[UTZFMT_PAT_POSITIVE_HMS];
+        if (offsetS != 0) {
+            offsetPatternItems = fGMTOffsetPatternItems[UTZFMT_PAT_POSITIVE_HMS];
+        } else if (offsetM != 0 || !isShort) {
+            offsetPatternItems = fGMTOffsetPatternItems[UTZFMT_PAT_POSITIVE_HM];
+        } else {
+            offsetPatternItems = fGMTOffsetPatternItems[UTZFMT_PAT_POSITIVE_H];
+        }
     } else {
-        offsetPatternItems = (offsetS == 0) ?
-            fGMTOffsetPatternItems[UTZFMT_PAT_NEGATIVE_HM] :
-            fGMTOffsetPatternItems[UTZFMT_PAT_NEGATIVE_HMS];
+        if (offsetS != 0) {
+            offsetPatternItems = fGMTOffsetPatternItems[UTZFMT_PAT_NEGATIVE_HMS];
+        } else if (offsetM != 0 || !isShort) {
+            offsetPatternItems = fGMTOffsetPatternItems[UTZFMT_PAT_NEGATIVE_HM];
+        } else {
+            offsetPatternItems = fGMTOffsetPatternItems[UTZFMT_PAT_NEGATIVE_H];
+        }
     }
 
     U_ASSERT(offsetPatternItems != NULL);
@@ -1124,15 +1504,15 @@ TimeZoneFormat::formatOffsetLocalizedGMT(int32_t offset, UnicodeString& result,
             break;
 
         case GMTOffsetField::HOUR:
-            appendOffsetDigits(result, offsetH, item->getWidth());
+            appendOffsetDigits(result, offsetH, (isShort ? 1 : 2));
             break;
 
         case GMTOffsetField::MINUTE:
-            appendOffsetDigits(result, offsetM, item->getWidth());
+            appendOffsetDigits(result, offsetM, 2);
             break;
 
         case GMTOffsetField::SECOND:
-            appendOffsetDigits(result, offsetS, item->getWidth());
+            appendOffsetDigits(result, offsetS, 2);
             break;
         }
     }
@@ -1141,54 +1521,6 @@ TimeZoneFormat::formatOffsetLocalizedGMT(int32_t offset, UnicodeString& result,
     return result;
 }
 
-int32_t
-TimeZoneFormat::parseOffsetRFC822(const UnicodeString& text, ParsePosition& pos) const {
-    int32_t start = pos.getIndex();
-    if (start >= text.length()) {
-        pos.setErrorIndex(start);
-        return 0;
-    }
-
-    int32_t sign = 1;
-    UChar signChar = text.charAt(start);
-    if (signChar == PLUS) {
-        sign = 1;
-    } else if (signChar == MINUS) {
-        sign = -1;
-    } else {
-        // Not an RFC822 offset string
-        pos.setErrorIndex(start);
-        return 0;
-    }
-
-    // Parse digits
-    pos.setIndex(start + 1);
-    int32_t offset = parseAbuttingAsciiOffsetFields(text, pos, FIELDS_H, FIELDS_HMS, false);
-
-    if (pos.getErrorIndex() != -1) {
-        pos.setIndex(start);    // reset
-        pos.setErrorIndex(start);
-        return 0;
-    }
-
-    return sign * offset;
-}
-
-int32_t
-TimeZoneFormat::parseOffsetISO8601(const UnicodeString& text, ParsePosition& pos) const {
-    return parseOffsetISO8601(text, pos, FALSE);
-}
-
-int32_t
-TimeZoneFormat::parseOffsetLocalizedGMT(const UnicodeString& text, ParsePosition& pos) const {
-    return parseOffsetLocalizedGMT(text, pos, NULL);
-}
-
-
-
-// ------------------------------------------------------------------
-// Private zone offset format/parse implementation
-
 int32_t
 TimeZoneFormat::parseOffsetISO8601(const UnicodeString& text, ParsePosition& pos, UBool extendedOnly, UBool* hasDigitOffset /* = NULL */) const {
     if (hasDigitOffset) {
@@ -1218,7 +1550,7 @@ TimeZoneFormat::parseOffsetISO8601(const UnicodeString& text, ParsePosition& pos
         return 0;
     }
     ParsePosition posOffset(start + 1);
-    int32_t offset = parseAsciiOffsetFields(text, posOffset, ISO8601_SEP, FIELDS_H, FIELDS_HMS, FALSE);
+    int32_t offset = parseAsciiOffsetFields(text, posOffset, ISO8601_SEP, FIELDS_H, FIELDS_HMS);
     if (posOffset.getErrorIndex() == -1 && !extendedOnly && (posOffset.getIndex() - start <= 3)) {
         // If the text is successfully parsed as extended format with the options above, it can be also parsed
         // as basic format. For example, "0230" can be parsed as offset 2:00 (only first digits are valid for
@@ -1244,54 +1576,36 @@ TimeZoneFormat::parseOffsetISO8601(const UnicodeString& text, ParsePosition& pos
 }
 
 int32_t
-TimeZoneFormat::parseOffsetLocalizedGMT(const UnicodeString& text, ParsePosition& pos, UBool* hasDigitOffset) const {
+TimeZoneFormat::parseOffsetLocalizedGMT(const UnicodeString& text, ParsePosition& pos, UBool isShort, UBool* hasDigitOffset) const {
     int32_t start = pos.getIndex();
-    int32_t idx = start;
-    UBool parsed = FALSE;
     int32_t offset = 0;
+    int32_t parsedLength = 0;
 
     if (hasDigitOffset) {
         *hasDigitOffset = FALSE;
     }
 
-    do {
-        // Prefix part
-        int32_t len = fGMTPatternPrefix.length();
-        if (len > 0 && text.caseCompare(idx, len, fGMTPatternPrefix, 0) != 0) {
-            // prefix match failed
-            break;
-        }
-        idx += len;
+    offset = parseOffsetLocalizedGMTPattern(text, start, isShort, parsedLength);
 
-        // Offset part
-        offset = parseOffsetFields(text, idx, FALSE, len);
-        if (len == 0) {
-            // offset field match failed
-            break;
-        }
-        idx += len;
-
-        // Suffix part
-        len = fGMTPatternSuffix.length();
-        if (len > 0 && text.caseCompare(idx, len, fGMTPatternSuffix, 0) != 0) {
-            // no suffix match
-            break;
-        }
-        idx += len;
-        parsed = TRUE;
-
-    } while (false);
+    // For now, parseOffsetLocalizedGMTPattern handles both long and short
+    // formats, no matter isShort is true or false. This might be changed in future
+    // when strict parsing is necessary, or different set of patterns are used for
+    // short/long formats.
+#if 0
+    if (parsedLength == 0) {
+        offset = parseOffsetLocalizedGMTPattern(text, start, !isShort, parsedLength);
+    }
+#endif
 
-    if (parsed) {
+    if (parsedLength > 0) {
         if (hasDigitOffset) {
             *hasDigitOffset = TRUE;
         }
-        pos.setIndex(idx);
+        pos.setIndex(start + parsedLength);
         return offset;
     }
 
     // Try the default patterns
-    int32_t parsedLength = 0;
     offset = parseOffsetDefaultLocalizedGMT(text, start, parsedLength);
     if (parsedLength > 0) {
         if (hasDigitOffset) {
@@ -1323,85 +1637,155 @@ TimeZoneFormat::parseOffsetLocalizedGMT(const UnicodeString& text, ParsePosition
 }
 
 int32_t
-TimeZoneFormat::parseOffsetFields(const UnicodeString& text, int32_t start, UBool minimumHourWidth, int32_t& parsedLen) const {
+TimeZoneFormat::parseOffsetLocalizedGMTPattern(const UnicodeString& text, int32_t start, UBool /*isShort*/, int32_t& parsedLen) const {
+    int32_t idx = start;
+    int32_t offset = 0;
+    UBool parsed = FALSE;
+
+    do {
+        // Prefix part
+        int32_t len = fGMTPatternPrefix.length();
+        if (len > 0 && text.caseCompare(idx, len, fGMTPatternPrefix, 0) != 0) {
+            // prefix match failed
+            break;
+        }
+        idx += len;
+
+        // Offset part
+        offset = parseOffsetFields(text, idx, FALSE, len);
+        if (len == 0) {
+            // offset field match failed
+            break;
+        }
+        idx += len;
+
+        len = fGMTPatternSuffix.length();
+        if (len > 0 && text.caseCompare(idx, len, fGMTPatternSuffix, 0) != 0) {
+            // no suffix match
+            break;
+        }
+        idx += len;
+        parsed = TRUE;
+    } while (FALSE);
+
+    parsedLen = parsed ? idx - start : 0;
+    return offset;
+}
+
+int32_t
+TimeZoneFormat::parseOffsetFields(const UnicodeString& text, int32_t start, UBool /*isShort*/, int32_t& parsedLen) const {
+    int32_t outLen = 0;
     int32_t offset = 0;
-    UBool sawVarHourAndAbuttingField = FALSE;
+    int32_t sign = 1;
 
     parsedLen = 0;
 
+    int32_t offsetH, offsetM, offsetS;
+    offsetH = offsetM = offsetS = 0;
+
     for (int32_t patidx = 0; PARSE_GMT_OFFSET_TYPES[patidx] >= 0; patidx++) {
         int32_t gmtPatType = PARSE_GMT_OFFSET_TYPES[patidx];
-        int32_t offsetH = 0, offsetM = 0, offsetS = 0;
-        int32_t idx = start;
         UVector* items = fGMTOffsetPatternItems[gmtPatType];
         U_ASSERT(items != NULL);
-        UBool failed = FALSE;
-        for (int32_t i = 0; i < items->size(); i++) {
-            int32_t tmpParsedLen = 0;
-            const GMTOffsetField* field = (const GMTOffsetField*)items->elementAt(i);
-            GMTOffsetField::FieldType fieldType = field->getType();
-            if (fieldType == GMTOffsetField::TEXT) {
-                const UChar* patStr = field->getPatternText();
-                tmpParsedLen = u_strlen(patStr);
-                if (text.caseCompare(idx, tmpParsedLen, patStr, 0) != 0) {
-                    failed = TRUE;
-                    break;
-                }
-                idx += tmpParsedLen;
-            } else {
-                if (fieldType == GMTOffsetField::HOUR) {
-                    uint8_t minDigits = 1;
-                    uint8_t maxDigits = minimumHourWidth ? 1 : 2;
-                    if (!minimumHourWidth && !sawVarHourAndAbuttingField) {
-                        if (i + 1 < items->size()) {
-                            const GMTOffsetField* nextField = (const GMTOffsetField*)items->elementAt(i + 1);
-                            if (nextField->getType() != GMTOffsetField::TEXT) {
-                                sawVarHourAndAbuttingField = true;
-                            }
-                        }
-                    }
-                    offsetH = parseOffsetFieldWithLocalizedDigits(text, idx, minDigits, maxDigits, 0, MAX_OFFSET_HOUR, tmpParsedLen);
-                } else if (fieldType == GMTOffsetField::MINUTE) {
-                    offsetM = parseOffsetFieldWithLocalizedDigits(text, idx, 2, 2, 0, MAX_OFFSET_MINUTE, tmpParsedLen);
-                } else if (fieldType == GMTOffsetField::SECOND) {
-                    offsetS = parseOffsetFieldWithLocalizedDigits(text, idx, 2, 2, 0, MAX_OFFSET_SECOND, tmpParsedLen);
-                }
 
-                if (tmpParsedLen == 0) {
-                    failed = TRUE;
-                    break;
-                }
-                idx += tmpParsedLen;
-            }
-        }
-        if (!failed) {
-            int32_t sign = (gmtPatType == UTZFMT_PAT_POSITIVE_HM || gmtPatType == UTZFMT_PAT_POSITIVE_HMS) ? 1 : -1;
-            offset = ((((offsetH * 60) + offsetM) * 60) + offsetS) * 1000 * sign;
-            parsedLen = idx - start;
+        outLen = parseOffsetFieldsWithPattern(text, start, items, FALSE, offsetH, offsetM, offsetS);
+        if (outLen > 0) {
+            sign = (gmtPatType == UTZFMT_PAT_POSITIVE_H || gmtPatType == UTZFMT_PAT_POSITIVE_HM || gmtPatType == UTZFMT_PAT_POSITIVE_HMS) ?
+                1 : -1;
             break;
         }
     }
 
-    if (parsedLen == 0 && sawVarHourAndAbuttingField && !minimumHourWidth) {
-        // When hour field is variable width and another non-literal pattern
-        // field follows, the parse loop above might eat up the digit from
-        // the abutting field. For example, with pattern "-Hmm" and input "-100",
-        // the hour is parsed as -10 and fails to parse minute field.
-        //
-        // If this is the case, try parsing the text one more time with the arg
-        // minimumHourWidth = true
-        //
-        // Note: This fallback is not applicable when quitAtHourField is true, because
-        // the option is designed for supporting the case like "GMT+5". In this case,
-        // we should get better result for parsing hour digits as much as possible.
+    if (outLen > 0 && fAbuttingOffsetHoursAndMinutes) {
+        // When hours field is sabutting minutes field,
+        // the parse result above may not be appropriate.
+        // For example, "01020" is parsed as 01:02: above,
+        // but it should be parsed as 00:10:20.
+        int32_t tmpLen = 0;
+        int32_t tmpSign = 1;
+        int32_t tmpH, tmpM, tmpS;
+
+        for (int32_t patidx = 0; PARSE_GMT_OFFSET_TYPES[patidx] >= 0; patidx++) {
+            int32_t gmtPatType = PARSE_GMT_OFFSET_TYPES[patidx];
+            UVector* items = fGMTOffsetPatternItems[gmtPatType];
+            U_ASSERT(items != NULL);
+
+            // forcing parse to use single hour digit
+            tmpLen = parseOffsetFieldsWithPattern(text, start, items, TRUE, tmpH, tmpM, tmpS);
+            if (tmpLen > 0) {
+                tmpSign = (gmtPatType == UTZFMT_PAT_POSITIVE_H || gmtPatType == UTZFMT_PAT_POSITIVE_HM || gmtPatType == UTZFMT_PAT_POSITIVE_HMS) ?
+                    1 : -1;
+                break;
+            }
+        }
+        if (tmpLen > outLen) {
+            // Better parse result with single hour digit
+            outLen = tmpLen;
+            sign = tmpSign;
+            offsetH = tmpH;
+            offsetM = tmpM;
+            offsetS = tmpS;
+        }
+    }
 
-        return parseOffsetFields(text, start, true, parsedLen);
+    if (outLen > 0) {
+        offset = ((((offsetH * 60) + offsetM) * 60) + offsetS) * 1000 * sign;
+        parsedLen = outLen;
     }
 
     return offset;
 }
 
+int32_t
+TimeZoneFormat::parseOffsetFieldsWithPattern(const UnicodeString& text, int32_t start,
+        UVector* patternItems, UBool forceSingleHourDigit, int32_t& hour, int32_t& min, int32_t& sec) const {
+    UBool failed = FALSE;
+    int32_t offsetH, offsetM, offsetS;
+    offsetH = offsetM = offsetS = 0;
+    int32_t idx = start;
+
+    for (int32_t i = 0; i < patternItems->size(); i++) {
+        int32_t len;
+        const GMTOffsetField* field = (const GMTOffsetField*)patternItems->elementAt(i);
+        GMTOffsetField::FieldType fieldType = field->getType();
+        if (fieldType == GMTOffsetField::TEXT) {
+            const UChar* patStr = field->getPatternText();
+            len = u_strlen(patStr);
+            if (text.caseCompare(idx, len, patStr, 0) != 0) {
+                failed = TRUE;
+                break;
+            }
+            idx += len;
+        } else {
+            if (fieldType == GMTOffsetField::HOUR) {
+                uint8_t maxDigits = forceSingleHourDigit ? 1 : 2;
+                offsetH = parseOffsetFieldWithLocalizedDigits(text, idx, 1, maxDigits, 0, MAX_OFFSET_HOUR, len);
+            } else if (fieldType == GMTOffsetField::MINUTE) {
+                offsetM = parseOffsetFieldWithLocalizedDigits(text, idx, 2, 2, 0, MAX_OFFSET_MINUTE, len);
+            } else if (fieldType == GMTOffsetField::SECOND) {
+                offsetS = parseOffsetFieldWithLocalizedDigits(text, idx, 2, 2, 0, MAX_OFFSET_SECOND, len);
+            }
+
+            if (len == 0) {
+                failed = TRUE;
+                break;
+            }
+            idx += len;
+        }
+    }
+
+    if (failed) {
+        hour = min = sec = 0;
+        return 0;
+    }
+
+    hour = offsetH;
+    min = offsetM;
+    sec = offsetS;
+
+    return idx - start;
+}
+
 int32_t
 TimeZoneFormat::parseAbuttingOffsetFields(const UnicodeString& text, int32_t start, int32_t& parsedLen) const {
     int32_t digits[MAX_OFFSET_DIGITS];
@@ -1766,25 +2150,30 @@ TimeZoneFormat::parseAbuttingAsciiOffsetFields(const UnicodeString& text, ParseP
 }
 
 int32_t
-TimeZoneFormat::parseAsciiOffsetFields(const UnicodeString& text, ParsePosition& pos, UChar sep, OffsetFields minFields, OffsetFields maxFields, UBool fixedHourWidth) {
+TimeZoneFormat::parseAsciiOffsetFields(const UnicodeString& text, ParsePosition& pos, UChar sep, OffsetFields minFields, OffsetFields maxFields) {
     int32_t start = pos.getIndex();
     int32_t fieldVal[] = {0, 0, 0};
     int32_t fieldLen[] = {0, -1, -1};
     for (int32_t idx = start, fieldIdx = 0; idx < text.length() && fieldIdx <= maxFields; idx++) {
         UChar c = text.charAt(idx);
         if (c == sep) {
-            if (fieldLen[fieldIdx] < 0) {
-                // next field - expected
-                fieldLen[fieldIdx] = 0;
-            } else if (fieldIdx == 0 && !fixedHourWidth) {
+            if (fieldIdx == 0) {
+                if (fieldLen[0] == 0) {
+                    // no hours field
+                    break;
+                }
                 // 1 digit hour, move to next field
-                fieldIdx++;
-                fieldLen[fieldIdx] = 0;
             } else {
-                // otherwise, premature field
-                break;
+                if (fieldLen[fieldIdx] != -1) {
+                    // premature minute or seconds field
+                    break;
+                }
+                fieldLen[fieldIdx] = 0;
             }
             continue;
+        } else if (fieldLen[fieldIdx] == -1) {
+            // no separator after 2 digit field
+            break;
         }
         int32_t digit = DIGIT_VAL(c);
         if (digit < 0) {
@@ -1804,13 +2193,10 @@ TimeZoneFormat::parseAsciiOffsetFields(const UnicodeString& text, ParsePosition&
     int32_t parsedFields = -1;
     do {
         // hour
-        if (fieldLen[0] == 0 || (fieldLen[0] == 1 && fixedHourWidth)) {
+        if (fieldLen[0] == 0) {
             break;
         }
         if (fieldVal[0] > MAX_OFFSET_HOUR) {
-            if (fixedHourWidth) {
-                break;
-            }
             offset = (fieldVal[0] / 10) * MILLIS_PER_HOUR;
             parsedFields = FIELDS_H;
             parsedLen = 1;
@@ -2044,15 +2430,17 @@ TimeZoneFormat::parseOffsetPattern(const UnicodeString& pattern, OffsetFields re
 }
 
 UnicodeString&
-TimeZoneFormat::expandOffsetPattern(const UnicodeString& offsetHM, UnicodeString& result) {
+TimeZoneFormat::expandOffsetPattern(const UnicodeString& offsetHM, UnicodeString& result, UErrorCode& status) {
+    result.setToBogus();
+    if (U_FAILURE(status)) {
+        return result;
+    }
     U_ASSERT(u_strlen(DEFAULT_GMT_OFFSET_MINUTE_PATTERN) == 2);
 
     int32_t idx_mm = offsetHM.indexOf(DEFAULT_GMT_OFFSET_MINUTE_PATTERN, 2, 0);
     if (idx_mm < 0) {
-        // we cannot do anything with this...
-        result.setTo(offsetHM);
-        result.append(DEFAULT_GMT_OFFSET_SEP);
-        result.append(DEFAULT_GMT_OFFSET_SECOND_PATTERN, -1);
+        // Bad time zone hour pattern data
+        status = U_ILLEGAL_ARGUMENT_ERROR;
         return result;
     }
 
@@ -2068,10 +2456,42 @@ TimeZoneFormat::expandOffsetPattern(const UnicodeString& offsetHM, UnicodeString
     return result;
 }
 
+UnicodeString&
+TimeZoneFormat::truncateOffsetPattern(const UnicodeString& offsetHM, UnicodeString& result, UErrorCode& status) {
+    result.setToBogus();
+    if (U_FAILURE(status)) {
+        return result;
+    }
+    U_ASSERT(u_strlen(DEFAULT_GMT_OFFSET_MINUTE_PATTERN) == 2);
+
+    int32_t idx_mm = offsetHM.indexOf(DEFAULT_GMT_OFFSET_MINUTE_PATTERN, 2, 0);
+    if (idx_mm < 0) {
+        // Bad time zone hour pattern data
+        status = U_ILLEGAL_ARGUMENT_ERROR;
+        return result;
+    }
+    UChar HH[] = {0x0048, 0x0048};
+    int32_t idx_HH = offsetHM.tempSubString(0, idx_mm).lastIndexOf(HH, 2, 0);
+    if (idx_HH >= 0) {
+        return result.setTo(offsetHM.tempSubString(0, idx_HH + 2));
+    }
+    int32_t idx_H = offsetHM.tempSubString(0, idx_mm).lastIndexOf((UChar)0x0048, 0);
+    if (idx_H >= 0) {
+        return result.setTo(offsetHM.tempSubString(0, idx_H + 1));
+    }
+    // Bad time zone hour pattern data
+    status = U_ILLEGAL_ARGUMENT_ERROR;
+    return result;
+}
+
 void
 TimeZoneFormat::initGMTOffsetPatterns(UErrorCode& status) {
-    for (int32_t type = 0; type <= UTZFMT_PAT_NEGATIVE_HMS; type++) {
+    for (int32_t type = 0; type < UTZFMT_PAT_COUNT; type++) {
         switch (type) {
+        case UTZFMT_PAT_POSITIVE_H:
+        case UTZFMT_PAT_NEGATIVE_H:
+            fGMTOffsetPatternItems[type] = parseOffsetPattern(fGMTOffsetPatterns[type], FIELDS_H, status);
+            break;
         case UTZFMT_PAT_POSITIVE_HM:
         case UTZFMT_PAT_NEGATIVE_HM:
             fGMTOffsetPatternItems[type] = parseOffsetPattern(fGMTOffsetPatterns[type], FIELDS_HM, status);
@@ -2082,6 +2502,33 @@ TimeZoneFormat::initGMTOffsetPatterns(UErrorCode& status) {
             break;
         }
     }
+    checkAbuttingHoursAndMinutes();
+}
+
+void
+TimeZoneFormat::checkAbuttingHoursAndMinutes() {
+    fAbuttingOffsetHoursAndMinutes= FALSE;
+    for (int32_t type = 0; type < UTZFMT_PAT_COUNT; type++) {
+        UBool afterH = FALSE;
+        UVector *items = fGMTOffsetPatternItems[type];
+        for (int32_t i = 0; i < items->size(); i++) {
+            const GMTOffsetField* item = (GMTOffsetField*)items->elementAt(i);
+            GMTOffsetField::FieldType type = item->getType();
+            if (type != GMTOffsetField::TEXT) {
+                if (afterH) {
+                    fAbuttingOffsetHoursAndMinutes = TRUE;
+                    break;
+                } else if (type == GMTOffsetField::HOUR) {
+                    afterH = TRUE;
+                }
+            } else if (afterH) {
+                break;
+            }
+        }
+        if (fAbuttingOffsetHoursAndMinutes) {
+            break;
+        }
+    }
 }
 
 UBool
@@ -2136,6 +2583,201 @@ TimeZoneFormat::getTimeZoneID(const TimeZoneNames::MatchInfoCollection* matches,
     return tzID;
 }
 
+
+class ZoneIdMatchHandler : public TextTrieMapSearchResultHandler {
+public:
+    ZoneIdMatchHandler();
+    virtual ~ZoneIdMatchHandler();
+
+    UBool handleMatch(int32_t matchLength, const CharacterNode *node, UErrorCode &status);
+    const UChar* getID();
+    int32_t getMatchLen();
+private:
+    int32_t fLen;
+    const UChar* fID;
+};
+
+ZoneIdMatchHandler::ZoneIdMatchHandler() 
+: fLen(0), fID(NULL) {
+}
+
+ZoneIdMatchHandler::~ZoneIdMatchHandler() {
+}
+
+UBool
+ZoneIdMatchHandler::handleMatch(int32_t matchLength, const CharacterNode *node, UErrorCode &status) {
+    if (U_FAILURE(status)) {
+        return FALSE;
+    }
+    if (node->hasValues()) {
+        const UChar* id = (const UChar*)node->getValue(0);
+        if (id != NULL) {
+            if (fLen < matchLength) {
+                fID = id;
+                fLen = matchLength;
+            }
+        }
+    }
+    return TRUE;
+}
+
+const UChar*
+ZoneIdMatchHandler::getID() {
+    return fID;
+}
+
+int32_t
+ZoneIdMatchHandler::getMatchLen() {
+    return fLen;
+}
+
+UnicodeString&
+TimeZoneFormat::parseZoneID(const UnicodeString& text, ParsePosition& pos, UnicodeString& tzID) const {
+    UErrorCode status = U_ZERO_ERROR;
+    UBool initialized;
+    UMTX_CHECK(&gLock, gZoneIdTrieInitialized, initialized);
+    if (!initialized) {
+        umtx_lock(&gLock);
+        {
+            if (!gZoneIdTrieInitialized) {
+                StringEnumeration *tzenum = TimeZone::createEnumeration();
+                TextTrieMap* trie = new TextTrieMap(TRUE, NULL);    // No deleter, because values are pooled by ZoneMeta
+                if (trie) {
+                    const UnicodeString *id;
+                    while ((id = tzenum->snext(status))) {
+                        const UChar* uid = ZoneMeta::findTimeZoneID(*id);
+                        if (uid) {
+                            trie->put(uid, const_cast<UChar *>(uid), status);
+                        }
+                    }
+                    if (U_SUCCESS(status)) {
+                        gZoneIdTrie = trie;
+                        gZoneIdTrieInitialized = initialized = TRUE;
+                        ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONEFORMAT, tzfmt_cleanup);
+                    } else {
+                        delete trie;
+                    }
+                }
+                delete tzenum;
+            }
+        }
+        umtx_unlock(&gLock);
+    }
+
+    int32_t start = pos.getIndex();
+    int32_t len = 0;
+    tzID.setToBogus();
+
+    if (initialized) {
+        LocalPointer<ZoneIdMatchHandler> handler(new ZoneIdMatchHandler());
+        gZoneIdTrie->search(text, start, handler.getAlias(), status); 
+        len = handler->getMatchLen();
+        if (len > 0) {
+            tzID.setTo(handler->getID(), -1);
+        }
+    }
+
+    if (len > 0) {
+        pos.setIndex(start + len);
+    } else {
+        pos.setErrorIndex(start);
+    }
+
+    return tzID;
+}
+
+UnicodeString&
+TimeZoneFormat::parseShortZoneID(const UnicodeString& text, ParsePosition& pos, UnicodeString& tzID) const {
+    UErrorCode status = U_ZERO_ERROR;
+    UBool initialized;
+    UMTX_CHECK(&gLock, gShortZoneIdTrieInitialized, initialized);
+    if (!initialized) {
+        umtx_lock(&gLock);
+        {
+            if (!gShortZoneIdTrieInitialized) {
+                StringEnumeration *tzenum = TimeZone::createTimeZoneIDEnumeration(UCAL_ZONE_TYPE_CANONICAL, NULL, NULL, status);
+                if (U_SUCCESS(status)) {
+                    TextTrieMap* trie = new TextTrieMap(TRUE, NULL);    // No deleter, because values are pooled by ZoneMeta
+                    if (trie) {
+                        const UnicodeString *id;
+                        while ((id = tzenum->snext(status))) {
+                            const UChar* uID = ZoneMeta::findTimeZoneID(*id);
+                            const UChar* shortID = ZoneMeta::getShortID(*id);
+                            if (shortID && uID) {
+                                trie->put(shortID, const_cast<UChar *>(uID), status);
+                            }
+                        }
+                        if (U_SUCCESS(status)) {
+                            gShortZoneIdTrie = trie;
+                            gShortZoneIdTrieInitialized = initialized = TRUE;
+                            ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONEFORMAT, tzfmt_cleanup);
+                        } else {
+                            delete trie;
+                        }
+                    }
+                }
+                delete tzenum;
+            }
+        }
+        umtx_unlock(&gLock);
+    }
+
+    int32_t start = pos.getIndex();
+    int32_t len = 0;
+    tzID.setToBogus();
+
+    if (initialized) {
+        LocalPointer<ZoneIdMatchHandler> handler(new ZoneIdMatchHandler());
+        gShortZoneIdTrie->search(text, start, handler.getAlias(), status); 
+        len = handler->getMatchLen();
+        if (len > 0) {
+            tzID.setTo(handler->getID(), -1);
+        }
+    }
+
+    if (len > 0) {
+        pos.setIndex(start + len);
+    } else {
+        pos.setErrorIndex(start);
+    }
+
+    return tzID;
+}
+
+
+UnicodeString&
+TimeZoneFormat::parseExemplarLocation(const UnicodeString& text, ParsePosition& pos, UnicodeString& tzID) const {
+    int32_t startIdx = pos.getIndex();
+    int32_t parsedPos = -1;
+    tzID.setToBogus();
+
+    UErrorCode status = U_ZERO_ERROR;
+    LocalPointer<TimeZoneNames::MatchInfoCollection> exemplarMatches(fTimeZoneNames->find(text, startIdx, UTZNM_EXEMPLAR_LOCATION, status));
+    if (U_FAILURE(status)) {
+        pos.setErrorIndex(startIdx);
+        return tzID;
+    }
+    int32_t matchIdx = -1;
+    if (!exemplarMatches.isNull()) {
+        for (int32_t i = 0; i < exemplarMatches->size(); i++) {
+            if (startIdx + exemplarMatches->getMatchLengthAt(i) > parsedPos) {
+                matchIdx = i;
+                parsedPos = startIdx + exemplarMatches->getMatchLengthAt(i);
+            }
+        }
+        if (parsedPos > 0) {
+            pos.setIndex(parsedPos);
+            getTimeZoneID(exemplarMatches.getAlias(), matchIdx, tzID);
+        }
+    }
+
+    if (tzID.length() == 0) {
+        pos.setErrorIndex(startIdx);
+    }
+
+    return tzID;
+}
+
 U_NAMESPACE_END
 
 #endif
index 923eb7ae9e32301230c3263f1d1ae25ff6960223..c887997e82d4f5f395c57f2e7b26fcc6332efde6 100644 (file)
@@ -1,6 +1,6 @@
 /*
 *******************************************************************************
-* Copyright (C) 2011-2012, International Business Machines Corporation and    *
+* Copyright (C) 2011-2013, International Business Machines Corporation and    *
 * others. All Rights Reserved.                                                *
 *******************************************************************************
 */
 
 U_NAMESPACE_BEGIN
 
-static const UChar gEtcPrefix[]         = { 0x45, 0x74, 0x63, 0x2F }; // "Etc/"
-static const int32_t gEtcPrefixLen      = 4;
-static const UChar gSystemVPrefix[]     = { 0x53, 0x79, 0x73, 0x74, 0x65, 0x6D, 0x56, 0x2F }; // "SystemV/
-static const int32_t gSystemVPrefixLen  = 8;
-static const UChar gRiyadh8[]           = { 0x52, 0x69, 0x79, 0x61, 0x64, 0x68, 0x38 }; // "Riyadh8"
-static const int32_t gRiyadh8Len       = 7;
-
 // TimeZoneNames object cache handling
 static UMutex gTimeZoneNamesLock = U_MUTEX_INITIALIZER;
 static UHashtable *gTimeZoneNamesCache = NULL;
@@ -313,21 +306,7 @@ TimeZoneNames::createInstance(const Locale& locale, UErrorCode& status) {
 
 UnicodeString&
 TimeZoneNames::getExemplarLocationName(const UnicodeString& tzID, UnicodeString& name) const {
-    if (tzID.isEmpty() || tzID.startsWith(gEtcPrefix, gEtcPrefixLen)
-        || tzID.startsWith(gSystemVPrefix, gSystemVPrefixLen) || tzID.indexOf(gRiyadh8, gRiyadh8Len, 0) > 0) {
-        name.setToBogus();
-        return name;
-    }
-
-    int32_t sep = tzID.lastIndexOf((UChar)0x2F /* '/' */);
-    if (sep > 0 && sep + 1 < tzID.length()) {
-        name.setTo(tzID, sep + 1);
-        name.findAndReplace(UnicodeString((UChar)0x5f /* _ */),
-                            UnicodeString((UChar)0x20 /* space */));
-    } else {
-        name.setToBogus();
-    }
-    return name;
+    return TimeZoneNamesImpl::getDefaultExemplarLocationName(tzID, name);
 }
 
 UnicodeString&
index 876411bc599fb8a7ef68efa704460e12c908c63f..e3b0c3c043192cf25a2e0e13f7fc2f2d95639684 100644 (file)
@@ -1,6 +1,6 @@
 /*
 *******************************************************************************
-* Copyright (C) 2011-2012, International Business Machines Corporation and
+* Copyright (C) 2011-2013, International Business Machines Corporation and
 * others. All Rights Reserved.
 *******************************************************************************
 *
@@ -46,6 +46,7 @@ static const char EMPTY[]               = "<empty>";   // place holder for empty
 static const UTimeZoneNameType ALL_NAME_TYPES[] = {
     UTZNM_LONG_GENERIC, UTZNM_LONG_STANDARD, UTZNM_LONG_DAYLIGHT,
     UTZNM_SHORT_GENERIC, UTZNM_SHORT_STANDARD, UTZNM_SHORT_DAYLIGHT,
+    UTZNM_EXEMPLAR_LOCATION,
     UTZNM_UNKNOWN // unknown as the last one
 };
 
@@ -489,7 +490,7 @@ public:
     virtual ~ZNames();
 
     static ZNames* createInstance(UResourceBundle* rb, const char* key);
-    const UChar* getName(UTimeZoneNameType type);
+    virtual const UChar* getName(UTimeZoneNameType type);
 
 protected:
     ZNames(const UChar** names);
@@ -544,6 +545,7 @@ ZNames::getName(UTimeZoneNameType type) {
     case UTZNM_SHORT_DAYLIGHT:
         name = fNames[5];
         break;
+    case UTZNM_EXEMPLAR_LOCATION:   // implemeted by subclass
     default:
         name = NULL;
     }
@@ -594,48 +596,80 @@ class TZNames : public ZNames {
 public:
     virtual ~TZNames();
 
-    static TZNames* createInstance(UResourceBundle* rb, const char* key);
-    const UChar* getLocationName(void);
+    static TZNames* createInstance(UResourceBundle* rb, const char* key, const UnicodeString& tzID);
+    virtual const UChar* getName(UTimeZoneNameType type);
 
 private:
-    TZNames(const UChar** names, const UChar* locationName);
+    TZNames(const UChar** names);
     const UChar* fLocationName;
+    UChar* fLocationNameOwned;
 };
 
-TZNames::TZNames(const UChar** names, const UChar* locationName)
-: ZNames(names), fLocationName(locationName) {
+TZNames::TZNames(const UChar** names)
+: ZNames(names), fLocationName(NULL), fLocationNameOwned(NULL) {
 }
 
 TZNames::~TZNames() {
+    if (fLocationNameOwned) {
+        uprv_free(fLocationNameOwned);
+    }
 }
 
 const UChar*
-TZNames::getLocationName() {
-    return fLocationName;
+TZNames::getName(UTimeZoneNameType type) {
+    if (type == UTZNM_EXEMPLAR_LOCATION) {
+        return fLocationName;
+    }
+    return ZNames::getName(type);
 }
 
 TZNames*
-TZNames::createInstance(UResourceBundle* rb, const char* key) {
+TZNames::createInstance(UResourceBundle* rb, const char* key, const UnicodeString& tzID) {
     if (rb == NULL || key == NULL || *key == 0) {
         return NULL;
     }
-    TZNames* tznames = NULL;
+
+    const UChar** names = loadData(rb, key);
+    const UChar* locationName = NULL;
+    UChar* locationNameOwned = NULL;
+
     UErrorCode status = U_ZERO_ERROR;
-    UResourceBundle* rbTable = ures_getByKeyWithFallback(rb, key, NULL, &status);
-    if (U_SUCCESS(status)) {
-        int32_t len = 0;
-        const UChar* locationName = ures_getStringByKeyWithFallback(rbTable, gEcTag, &len, &status);
-        if (U_FAILURE(status) || len == 0) {
-            locationName = NULL;
+    int32_t len = 0;
+
+    UResourceBundle* table = ures_getByKeyWithFallback(rb, key, NULL, &status);
+    locationName = ures_getStringByKeyWithFallback(table, gEcTag, &len, &status);
+    // ignore missing resource here
+    status = U_ZERO_ERROR;
+
+    ures_close(table);
+
+    if (locationName == NULL) {
+        UnicodeString tmpName;
+        int32_t tmpNameLen = 0;
+        TimeZoneNamesImpl::getDefaultExemplarLocationName(tzID, tmpName);
+        tmpNameLen = tmpName.length();
+
+        if (tmpNameLen > 0) {
+            locationNameOwned = (UChar*) uprv_malloc(sizeof(UChar) * (tmpNameLen + 1));
+            if (locationNameOwned) {
+                tmpName.extract(locationNameOwned, tmpNameLen + 1, status);
+                locationName = locationNameOwned;
+            }
         }
+    }
 
-        const UChar** names = loadData(rb, key);
-
-        if (locationName != NULL || names != NULL) {
-            tznames = new TZNames(names, locationName);
+    TZNames* tznames = NULL;
+    if (locationName != NULL || names != NULL) {
+        tznames = new TZNames(names);
+        if (tznames == NULL) {
+            if (locationNameOwned) {
+                uprv_free(locationNameOwned);
+            }
         }
+        tznames->fLocationName = locationName;
+        tznames->fLocationNameOwned = locationNameOwned;
     }
-    ures_close(rbTable);
+
     return tznames;
 }
 
@@ -1057,6 +1091,7 @@ TimeZoneNamesImpl::getTimeZoneDisplayName(const UnicodeString& tzID, UTimeZoneNa
 
 UnicodeString&
 TimeZoneNamesImpl::getExemplarLocationName(const UnicodeString& tzID, UnicodeString& name) const {
+    name.setToBogus();  // cleanup result.
     const UChar* locName = NULL;
     TZNames *tznames = NULL;
     TimeZoneNamesImpl *nonConstThis = const_cast<TimeZoneNamesImpl *>(this);
@@ -1068,14 +1103,13 @@ TimeZoneNamesImpl::getExemplarLocationName(const UnicodeString& tzID, UnicodeStr
     umtx_unlock(&gLock);
 
     if (tznames != NULL) {
-        locName = tznames->getLocationName();
+        locName = tznames->getName(UTZNM_EXEMPLAR_LOCATION);
     }
     if (locName != NULL) {
         name.setTo(TRUE, locName, -1);
-        return name;
     }
 
-    return TimeZoneNames::getExemplarLocationName(tzID, name);
+    return name;
 }
 
 
@@ -1193,7 +1227,7 @@ TimeZoneNamesImpl::loadTimeZoneNames(const UnicodeString& tzID) {
             }
         }
         uKey.extract(0, uKey.length(), key, sizeof(key), US_INV);
-        tznames = TZNames::createInstance(fZoneStrings, key);
+        tznames = TZNames::createInstance(fZoneStrings, key, tzID);
 
         if (tznames == NULL) {
             cacheVal = (void *)EMPTY;
@@ -1306,6 +1340,32 @@ TimeZoneNamesImpl::find(const UnicodeString& text, int32_t start, uint32_t types
     return handler.getMatches(maxLen);
 }
 
+static const UChar gEtcPrefix[]         = { 0x45, 0x74, 0x63, 0x2F }; // "Etc/"
+static const int32_t gEtcPrefixLen      = 4;
+static const UChar gSystemVPrefix[]     = { 0x53, 0x79, 0x73, 0x74, 0x65, 0x6D, 0x56, 0x2F }; // "SystemV/
+static const int32_t gSystemVPrefixLen  = 8;
+static const UChar gRiyadh8[]           = { 0x52, 0x69, 0x79, 0x61, 0x64, 0x68, 0x38 }; // "Riyadh8"
+static const int32_t gRiyadh8Len       = 7;
+
+UnicodeString& U_EXPORT2
+TimeZoneNamesImpl::getDefaultExemplarLocationName(const UnicodeString& tzID, UnicodeString& name) {
+    if (tzID.isEmpty() || tzID.startsWith(gEtcPrefix, gEtcPrefixLen)
+        || tzID.startsWith(gSystemVPrefix, gSystemVPrefixLen) || tzID.indexOf(gRiyadh8, gRiyadh8Len, 0) > 0) {
+        name.setToBogus();
+        return name;
+    }
+
+    int32_t sep = tzID.lastIndexOf((UChar)0x2F /* '/' */);
+    if (sep > 0 && sep + 1 < tzID.length()) {
+        name.setTo(tzID, sep + 1);
+        name.findAndReplace(UnicodeString((UChar)0x5f /* _ */),
+                            UnicodeString((UChar)0x20 /* space */));
+    } else {
+        name.setToBogus();
+    }
+    return name;
+}
+
 U_NAMESPACE_END
 
 
index c03eb8e6ed4ecc640f9bf3d3d029c5f7b47298b5..c677a8b9537a536560818745a70179f4a69584d8 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *******************************************************************************
- * Copyright (C) 2011-2012, International Business Machines Corporation and    *
+ * Copyright (C) 2011-2013, International Business Machines Corporation and    *
  * others. All Rights Reserved.                                                *
  *******************************************************************************
  */
@@ -184,6 +184,8 @@ public:
 
     TimeZoneNames::MatchInfoCollection* find(const UnicodeString& text, int32_t start, uint32_t types, UErrorCode& status) const;
 
+    static UnicodeString& getDefaultExemplarLocationName(const UnicodeString& tzID, UnicodeString& name);
+
 private:
 
     Locale fLocale;
index fc3565208e201b4de38b048339f12e76171440d7..494f73e2aacba682f998aeeaa82d5661afbca2b7 100644 (file)
@@ -33,6 +33,7 @@ typedef enum ECleanupI18NType {
     UCLN_I18N_HEBREW_CALENDAR,
     UCLN_I18N_ASTRO_CALENDAR,
     UCLN_I18N_CALENDAR,
+    UCLN_I18N_TIMEZONEFORMAT,
     UCLN_I18N_TIMEZONEGENERICNAMES,
     UCLN_I18N_TIMEZONENAMES,
     UCLN_I18N_ZONEMETA,
index 299449d2f9d5689b96061dc59e1697917496b96a..02966617feca814566c162ef45122232af67b844 100644 (file)
@@ -1,5 +1,5 @@
 /*
-* Copyright (C) 1997-2012, International Business Machines Corporation and
+* Copyright (C) 1997-2013, International Business Machines Corporation and
 * others. All Rights Reserved.
 *******************************************************************************
 *
@@ -99,8 +99,13 @@ class TimeZoneFormat;
  * ZZZZZ    time zone (ISO 8601)    (Text & Number)     -08:00 & Z
  * v        time zone (generic)     (Text)              PT
  * vvvv     time zone (generic)     (Text)              Pacific Time
- * V        time zone (abreviation) (Text)              PST
- * VVVV     time zone (location)    (Text)              United States Time (Los Angeles)
+ * V        time zone (short ID)    (Text)              uslax
+ * VV       time zone (ID)          (Text)              America/Los_Angeles
+ * VVV      time zone (exemplar)    (Text)              Los Angeles
+ * VVVV     time zone (location)    (Text)              Los Angeles Time
+ * O        time zone (GMT offset)  (Text & Number)     GMT-8 & GMT-08:00
+ * X        time zone (ISO 8601)    (text & Number)     -08, -0800, -08:00 & Z (UTC)
+ * X        time zone (ISO 8601)    (Number)            -08, -0800 & -08:00
  * g        Julian day              (Number)            2451334
  * A        milliseconds in day     (Number)            69540000
  * q        stand alone quarter     (Text & Number)     Q2 & 02
index 90b43b01a7f9ba115a889ce01fa7c884f2c66702..2b20f353fe397b8dda8746854e4097d1c58eef1d 100644 (file)
@@ -1,6 +1,6 @@
 /*
 *******************************************************************************
-* Copyright (C) 2011-2012, International Business Machines Corporation and    *
+* Copyright (C) 2011-2013, International Business Machines Corporation and    *
 * others. All Rights Reserved.                                                *
 *******************************************************************************
 */
@@ -53,21 +53,102 @@ typedef enum UTimeZoneFormatStyle {
      * @draft ICU 50
      */
     UTZFMT_STYLE_SPECIFIC_SHORT,
-    /**
-     * RFC822 format, such as "-0500"
-     * @draft ICU 50
-     */
-    UTZFMT_STYLE_RFC822,
     /**
      * Localized GMT offset format, such as "GMT-05:00", "UTC+0100"
      * @draft ICU 50
      */
     UTZFMT_STYLE_LOCALIZED_GMT,
     /**
-     * ISO 8601 format (extended), such as "-05:00", "Z"(UTC)
-     * @draft ICU 50
+     * Short localized GMT offset format, such as "GMT-5", "UTC+1:30"
+     * This style is equivalent to the LDML date format pattern "O".
+     * @draft ICU 51
+     */
+    UTZFMT_STYLE_LOCALIZED_GMT_SHORT,
+    /**
+     * Short ISO 8601 local time difference (basic format) or the UTC indicator.
+     * For example, "-05", "+0530", and "Z"(UTC).
+     * This style is equivalent to the LDML date format pattern "X".
+     * @draft ICU 51
+     */
+    UTZFMT_STYLE_ISO_BASIC_SHORT,
+    /**
+     * Short ISO 8601 locale time difference (basic format).
+     * For example, "-05" and "+0530".
+     * This style is equivalent to the LDML date format pattern "x".
+     * @draft ICU 51
+     */
+    UTZFMT_STYLE_ISO_BASIC_LOCAL_SHORT,
+    /**
+     * Fixed width ISO 8601 local time difference (basic format) or the UTC indicator.
+     * For example, "-0500", "+0530", and "Z"(UTC).
+     * This style is equivalent to the LDML date format pattern "XX".
+     * @draft ICU 51
+     */
+    UTZFMT_STYLE_ISO_BASIC_FIXED,
+    /**
+     * Fixed width ISO 8601 local time difference (basic format).
+     * For example, "-0500" and "+0530".
+     * This style is equivalent to the LDML date format pattern "xx".
+     * @draft ICU 51
+     */
+    UTZFMT_STYLE_ISO_BASIC_LOCAL_FIXED,
+    /**
+     * ISO 8601 local time difference (basic format) with optional seconds field, or the UTC indicator.
+     * For example, "-0500", "+052538", and "Z"(UTC).
+     * This style is equivalent to the LDML date format pattern "XXXX".
+     * @draft ICU 51
+     */
+    UTZFMT_STYLE_ISO_BASIC_FULL,
+    /**
+     * ISO 8601 local time difference (basic format) with optional seconds field.
+     * For example, "-0500" and "+052538".
+     * This style is equivalent to the LDML date format pattern "xxxx".
+     * @draft ICU 51
      */
-    UTZFMT_STYLE_ISO8601
+    UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL,
+    /**
+     * Fixed width ISO 8601 local time difference (extended format) or the UTC indicator.
+     * For example, "-05:00", "+05:30", and "Z"(UTC).
+     * This style is equivalent to the LDML date format pattern "XXX".
+     * @draft ICU 51
+     */
+    UTZFMT_STYLE_ISO_EXTENDED_FIXED,
+    /**
+     * Fixed width ISO 8601 local time difference (extended format).
+     * For example, "-05:00" and "+05:30".
+     * This style is equivalent to the LDML date format pattern "xxx" and "ZZZZZ".
+     * @draft ICU 51
+     */
+    UTZFMT_STYLE_ISO_EXTENDED_LOCAL_FIXED,
+    /**
+     * ISO 8601 local time difference (extended format) with optional seconds field, or the UTC indicator.
+     * For example, "-05:00", "+05:25:38", and "Z"(UTC).
+     * This style is equivalent to the LDML date format pattern "XXXXX".
+     * @draft ICU 51
+     */
+    UTZFMT_STYLE_ISO_EXTENDED_FULL,
+    /**
+     * ISO 8601 local time difference (extended format) with optional seconds field.
+     * For example, "-05:00" and "+05:25:38".
+     * This style is equivalent to the LDML date format pattern "xxxxx".
+     * @draft ICU 51
+     */
+    UTZFMT_STYLE_ISO_EXTENDED_LOCAL_FULL,
+    /**
+     * Time Zone ID, such as "America/Los_Angeles".
+     * @draft ICU 51
+     */
+    UTZFMT_STYLE_ZONE_ID,
+    /**
+     * Short Time Zone ID (BCP 47 Unicode location extension, time zone type value), such as "uslax".
+     * @draft ICU 51
+     */
+    UTZFMT_STYLE_ZONE_ID_SHORT,
+    /**
+     * Exemplar location, such as "Los Angeles" and "Paris".
+     * @draft ICU 51
+     */
+    UTZFMT_STYLE_EXEMPLAR_LOCATION
 } UTimeZoneFormatStyle;
 
 /**
@@ -76,25 +157,41 @@ typedef enum UTimeZoneFormatStyle {
  */
 typedef enum UTimeZoneFormatGMTOffsetPatternType {
     /**
-     * Positive offset with hour and minute fields
+     * Positive offset with hours and minutes fields
      * @draft ICU 50
      */
     UTZFMT_PAT_POSITIVE_HM,
     /**
-     * Positive offset with hour, minute and second fields
+     * Positive offset with hours, minutes and seconds fields
      * @draft ICU 50
      */
     UTZFMT_PAT_POSITIVE_HMS,
     /**
-     * Negative offset with hour and minute fields
+     * Negative offset with hours and minutes fields
      * @draft ICU 50
      */
     UTZFMT_PAT_NEGATIVE_HM,
     /**
-     * Negative offset with hour, minute and second fields
+     * Negative offset with hours, minutes and seconds fields
      * @draft ICU 50
      */
-    UTZFMT_PAT_NEGATIVE_HMS
+    UTZFMT_PAT_NEGATIVE_HMS,
+    /**
+     * Positive offset with hours field
+     * @draft ICU 51
+     */
+    UTZFMT_PAT_POSITIVE_H,
+    /**
+     * Negative offset with hours field
+     * @draft ICU 51
+     */
+    UTZFMT_PAT_NEGATIVE_H,
+
+    /**
+     * Number of UTimeZoneFormatGMTOffsetPatternType types.
+     * @internal
+     */
+    UTZFMT_PAT_COUNT
 } UTimeZoneFormatGMTOffsetPatternType;
 
 /**
@@ -334,28 +431,40 @@ public:
     void setDefaultParseOptions(uint32_t flags);
 
     /**
-     * Returns the RFC822 style time zone string for the given offset.
-     * For example, "-0800".
-     * @param offset The offset from GMT(UTC) in milliseconds.
-     * @param result Recevies the RFC822 style GMT(UTC) offset format.
-     * @return A reference to the result.
+     * Returns the ISO 8601 basic time zone string for the given offset.
+     * For example, "-08", "-0830" and "Z"
+     * 
+     * @param offset the offset from GMT(UTC) in milliseconds.
+     * @param useUtcIndicator true if ISO 8601 UTC indicator "Z" is used when the offset is 0.
+     * @param isShort true if shortest form is used.
+     * @param ignoreSeconds true if non-zero offset seconds is appended.
+     * @param result Receives the ISO format string.
      * @param status Receives the status
-     * @see #parseOffsetRFC822
-     * @draft ICU 50
+     * @return the ISO 8601 basic format.
+     * @see #formatOffsetISO8601Extended
+     * @see #parseOffsetISO8601
+     * @draft ICU 51
      */
-    UnicodeString& formatOffsetRFC822(int32_t offset, UnicodeString& result, UErrorCode& status) const;
+    UnicodeString& formatOffsetISO8601Basic(int32_t offset, UBool useUtcIndicator, UBool isShort, UBool ignoreSeconds,
+        UnicodeString& result, UErrorCode& status) const;
 
     /**
-     * Returns the ISO 8601 style time zone string for the given offset.
-     * For example, "-08:00" and "Z".
-     * @param offset The offset from GMT(UTC) in milliseconds.
-     * @param result Receives the ISO 8601 style GMT(UTC) offset format.
+     * Returns the ISO 8601 extended time zone string for the given offset.
+     * For example, "-08:00", "-08:30" and "Z"
+     * 
+     * @param offset the offset from GMT(UTC) in milliseconds.
+     * @param useUtcIndicator true if ISO 8601 UTC indicator "Z" is used when the offset is 0.
+     * @param isShort true if shortest form is used.
+     * @param ignoreSeconds true if non-zero offset seconds is appended.
+     * @param result Receives the ISO format string.
      * @param status Receives the status
-     * @return A reference to the result.
+     * @return the ISO 8601 basic format.
+     * @see #formatOffsetISO8601Extended
      * @see #parseOffsetISO8601
-     * @draft ICU 50
+     * @draft ICU 51
      */
-    UnicodeString& formatOffsetISO8601(int32_t offset, UnicodeString& result, UErrorCode& status) const;
+    UnicodeString& formatOffsetISO8601Extended(int32_t offset, UBool useUtcIndicator, UBool isShort, UBool ignoreSeconds,
+        UnicodeString& result, UErrorCode& status) const;
 
     /**
      * Returns the localized GMT(UTC) offset format for the given offset.
@@ -366,6 +475,9 @@ public:
      * <li>Offset digits (e.g. "0123456789" - see {@link #getGMTOffsetDigits})
      * <li>GMT zero format (e.g. "GMT" - see {@link #getGMTZeroFormat})
      * </ul>
+     * This format always uses 2 digit hours and minutes. When the given offset has non-zero
+     * seconds, 2 digit seconds field will be appended. For example,
+     * GMT+05:00 and GMT+05:28:06.
      * @param offset the offset from GMT(UTC) in milliseconds.
      * @param status Receives the status
      * @param result Receives the localized GMT format string.
@@ -375,6 +487,27 @@ public:
      */
     UnicodeString& formatOffsetLocalizedGMT(int32_t offset, UnicodeString& result, UErrorCode& status) const;
 
+    /**
+     * Returns the short localized GMT(UTC) offset format for the given offset.
+     * The short localized GMT offset is defined by;
+     * <ul>
+     * <li>GMT format pattern (e.g. "GMT {0}" - see {@link #getGMTPattern})
+     * <li>Offset time pattern (e.g. "+HH:mm" - see {@link #getGMTOffsetPattern})
+     * <li>Offset digits (e.g. "0123456789" - see {@link #getGMTOffsetDigits})
+     * <li>GMT zero format (e.g. "GMT" - see {@link #getGMTZeroFormat})
+     * </ul>
+     * This format uses the shortest representation of offset. The hours field does not
+     * have leading zero and lower fields with zero will be truncated. For example,
+     * GMT+5 and GMT+530.
+     * @param offset the offset from GMT(UTC) in milliseconds.
+     * @param status Receives the status
+     * @param result Receives the short localized GMT format string.
+     * @return A reference to the result.
+     * @see #parseOffsetShortLocalizedGMT
+     * @draft ICU 51
+     */
+    UnicodeString& formatOffsetShortLocalizedGMT(int32_t offset, UnicodeString& result, UErrorCode& status) const;
+
     using Format::format;
 
     /**
@@ -393,21 +526,6 @@ public:
     virtual UnicodeString& format(UTimeZoneFormatStyle style, const TimeZone& tz, UDate date,
         UnicodeString& name, UTimeZoneFormatTimeType* timeType = NULL) const;
 
-    /**
-     * Returns offset from GMT(UTC) in milliseconds for the given RFC822
-     * style time zone string. When the given string is not an RFC822 time zone
-     * string, this method sets the current position as the error index
-     * to <code>ParsePosition pos</code> and returns 0.
-     * @param text The text contains RFC822 style time zone string (e.g. "-0800")
-     *              at the position.
-     * @param pos The ParsePosition object.
-     * @return The offset from GMT(UTC) in milliseconds for the given RFC822 style
-     *              time zone string.
-     * @see #formatOffsetRFC822
-     * @draft ICU 50
-     */
-    int32_t parseOffsetRFC822(const UnicodeString& text, ParsePosition& pos) const;
-
     /**
      * Returns offset from GMT(UTC) in milliseconds for the given ISO 8601
      * style time zone string. When the given string is not an ISO 8601 time zone
@@ -418,7 +536,8 @@ public:
      * @param pos The ParsePosition object.
      * @return The offset from GMT(UTC) in milliseconds for the given ISO 8601 style
      *              time zone string.
-     * @see #formatOffsetISO8601
+     * @see #formatOffsetISO8601Basic
+     * @see #formatOffsetISO8601Extended
      * @draft ICU 50
      */
     int32_t parseOffsetISO8601(const UnicodeString& text, ParsePosition& pos) const;
@@ -437,6 +556,20 @@ public:
      */
     int32_t parseOffsetLocalizedGMT(const UnicodeString& text, ParsePosition& pos) const;
 
+    /**
+     * Returns offset from GMT(UTC) in milliseconds for the given short localized GMT
+     * offset format string. When the given string cannot be parsed, this method
+     * sets the current position as the error index to <code>ParsePosition pos</code>
+     * and returns 0.
+     * @param text The text contains a short localized GMT offset string at the position.
+     * @param pos The ParsePosition object.
+     * @return The offset from GMT(UTC) in milliseconds for the given short localized GMT
+     *          offset format string.
+     * @see #formatOffsetShortLocalizedGMT
+     * @draft ICU 51
+     */
+    int32_t parseOffsetShortLocalizedGMT(const UnicodeString& text, ParsePosition& pos) const;
+
     /**
      * Returns a <code>TimeZone</code> by parsing the time zone string according to
      * the given parse position, the specified format style and parse options.
@@ -544,7 +677,7 @@ private:
     UnicodeString fGMTPattern;
 
     /* Array of offset patterns used by Localized GMT format - e.g. "+HH:mm" */
-    UnicodeString fGMTOffsetPatterns[UTZFMT_PAT_NEGATIVE_HMS + 1];
+    UnicodeString fGMTOffsetPatterns[UTZFMT_PAT_COUNT];
 
     /* Localized decimal digits used by Localized GMT format */
     UChar32 fGMTOffsetDigits[10];
@@ -560,7 +693,9 @@ private:
     UnicodeString fGMTPatternSuffix;    /* Substring after {0} */
 
     /* Compiled offset patterns generated from fGMTOffsetPatterns[] */
-    UVector* fGMTOffsetPatternItems[UTZFMT_PAT_NEGATIVE_HMS + 1];
+    UVector* fGMTOffsetPatternItems[UTZFMT_PAT_COUNT];
+
+    UBool fAbuttingOffsetHoursAndMinutes;
 
     /**
      * Returns the time zone's specific format string.
@@ -592,6 +727,15 @@ private:
      */
     const TimeZoneGenericNames* getTimeZoneGenericNames(UErrorCode& status) const;
 
+    /**
+     * Private method returning the time zone's exemplar location string.
+     * This method will never return empty.
+     * @param tz the time zone
+     * @param name receives the time zone's exemplar location name
+     * @return a reference to name.
+     */
+    UnicodeString& formatExemplarLocation(const TimeZone& tz, UnicodeString& name) const;
+
     /**
      * Private enum specifying a combination of offset fields
      */
@@ -621,13 +765,24 @@ private:
     static UVector* parseOffsetPattern(const UnicodeString& pattern, OffsetFields required, UErrorCode& status);
 
     /**
-     * Appends second field to the offset pattern with hour/minute
+     * Appends seconds field to the offset pattern with hour/minute
      * Note: This code will be obsoleted once we add hour-minute-second pattern data in CLDR.
-     * @param offsetHM the offset pattern including hour and minute fields
-     * @param result the output offset pattern including hour, minute and second fields
+     * @param offsetHM the offset pattern including hours and minutes fields
+     * @param result the output offset pattern including hour, minute and seconds fields
+     * @param status receives the status
      * @return a reference to result
      */
-    static UnicodeString& expandOffsetPattern(const UnicodeString& offsetHM, UnicodeString& result);
+    static UnicodeString& expandOffsetPattern(const UnicodeString& offsetHM, UnicodeString& result, UErrorCode& status);
+
+    /**
+     * Truncates minutes field to the offset pattern with hour/minute
+     * Note: This code will be obsoleted once we add hour pattern data in CLDR.
+     * @param offsetHM the offset pattern including hours and minutes fields
+     * @param result the output offset pattern including only hours field
+     * @param status receives the status
+     * @return a reference to result
+     */
+    static UnicodeString& truncateOffsetPattern(const UnicodeString& offsetHM, UnicodeString& result, UErrorCode& status);
 
     /**
      * Break input string into UChar32[]. Each array element represents
@@ -641,6 +796,28 @@ private:
      */
     static UBool toCodePoints(const UnicodeString& str, UChar32* codeArray, int32_t capacity);
 
+    /**
+     * Private method supprting all of ISO8601 formats
+     * @param offset the offset from GMT(UTC) in milliseconds.
+     * @param useUtcIndicator true if ISO 8601 UTC indicator "Z" is used when the offset is 0.
+     * @param isShort true if shortest form is used.
+     * @param ignoreSeconds true if non-zero offset seconds is appended.
+     * @param result Receives the result
+     * @param status Receives the status
+     * @return the ISO 8601 basic format.
+     */
+    UnicodeString& formatOffsetISO8601(int32_t offset, UBool isBasic, UBool useUtcIndicator,
+        UBool isShort, UBool ignoreSeconds, UnicodeString& result, UErrorCode& status) const;
+
+    /**
+     * Private method used for localized GMT formatting.
+     * @param offset the zone's UTC offset
+     * @param isShort true if the short localized GMT format is desired.
+     * @param result receives the localized GMT format string
+     * @param status receives the status
+     */
+    UnicodeString& formatOffsetLocalizedGMT(int32_t offset, UBool isShort, UnicodeString& result, UErrorCode& status) const;
+
     /**
      * Returns offset from GMT(UTC) in milliseconds for the given ISO 8601 style
      * (extended format) time zone string. When the given string is not an ISO 8601 time
@@ -674,23 +851,49 @@ private:
      * and returns 0.
      * @param text the text contains a localized GMT offset string at the position.
      * @param pos the position, non-negative error index will be set on failure.
+     * @param isShort true if this parser to try the short format first
      * @param hasDigitOffset receiving if the parsed zone string contains offset digits.
      * @return the offset from GMT(UTC) in milliseconds for the given localized GMT
      *      offset format string.
      */
     int32_t parseOffsetLocalizedGMT(const UnicodeString& text, ParsePosition& pos,
-        UBool* hasDigitOffset) const;
+        UBool isShort, UBool* hasDigitOffset) const;
+
+    /**
+     * Parse localized GMT format generated by the patter used by this formatter, except
+     * GMT Zero format.
+     * @param text the input text
+     * @param start the start index
+     * @param isShort true if the short localized format is parsed.
+     * @param parsedLen receives the parsed length
+     * @return the parsed offset in milliseconds
+     */
+    int32_t parseOffsetLocalizedGMTPattern(const UnicodeString& text, int32_t start,
+        UBool isShort, int32_t& parsedLen) const;
 
     /**
      * Parses localized GMT offset fields into offset.
      * @param text the input text
      * @param start the start index
-     * @param minimumHourWidth true if the parser allows hour field width to be 1
+     * @param isShort true if this is a short format - currently not used
      * @param parsedLen the parsed length, or 0 on failure.
      * @return the parsed offset in milliseconds.
      */
-    int32_t parseOffsetFields(const UnicodeString& text, int32_t start, UBool minimumHourWidth,
-        int32_t& parsedLen) const;
+    int32_t parseOffsetFields(const UnicodeString& text, int32_t start, UBool isShort, int32_t& parsedLen) const;
+
+    /**
+     * Parse localized GMT offset fields with the given pattern.
+     * @param text the input text
+     * @param start the start index
+     * @param pattenItems the pattern (already itemized)
+     * @param forceSingleHourDigit true if hours field is parsed as a single digit
+     * @param hour receives the hour offset field
+     * @param min receives the minute offset field
+     * @param sec receives the second offset field
+     * @return the parsed length
+     */
+    int32_t parseOffsetFieldsWithPattern(const UnicodeString& text, int32_t start,
+        UVector* patternItems, UBool forceSingleHourDigit, int32_t& hour, int32_t& min, int32_t& sec) const;
 
     /**
      * Parses abutting localized GMT offset fields (such as 0800) into offset.
@@ -770,7 +973,7 @@ private:
      * @param pos The parse position
      * @param minFields The minimum Fields to be parsed
      * @param maxFields The maximum Fields to be parsed
-     * @param fixedHourWidth true if hour field must be width of 2
+     * @param fixedHourWidth true if hours field must be width of 2
      * @return Parsed offset, 0 or positive number.
      */
     static int32_t parseAbuttingAsciiOffsetFields(const UnicodeString& text, ParsePosition& pos,
@@ -786,11 +989,10 @@ private:
      * @param sep The separator character
      * @param minFields The minimum Fields to be parsed
      * @param maxFields The maximum Fields to be parsed
-     * @param fixedHourWidth true if hour field must be width of 2
      * @return Parsed offset, 0 or positive number.
      */
     static int32_t parseAsciiOffsetFields(const UnicodeString& text, ParsePosition& pos, UChar sep,
-        OffsetFields minFields, OffsetFields maxFields, UBool fixedHourWidth);
+        OffsetFields minFields, OffsetFields maxFields);
 
     /**
      * Unquotes the message format style pattern.
@@ -807,6 +1009,14 @@ private:
      */
     void initGMTOffsetPatterns(UErrorCode& status);
 
+    /**
+     * Check if there are any GMT format offset patterns without
+     * any separators between hours field and minutes field and update
+     * fAbuttingOffsetHoursAndMinutes field. This method must be called
+     * after all patterns are parsed into pattern items.
+     */
+    void checkAbuttingHoursAndMinutes();
+
     /**
      * Creates an instance of TimeZone for the given offset
      * @param offset the offset
@@ -821,7 +1031,7 @@ private:
      */
     static UTimeZoneFormatTimeType getTimeType(UTimeZoneNameType nameType);
 
-    /*
+    /**
      * Returns the time zone ID of a match at the specified index within
      * the MatchInfoCollection.
      * @param matches the collection of matches
@@ -830,6 +1040,34 @@ private:
      * @return a reference to tzID.
      */
     UnicodeString& getTimeZoneID(const TimeZoneNames::MatchInfoCollection* matches, int32_t idx, UnicodeString& tzID) const;
+
+
+    /**
+     * Parse a zone ID.
+     * @param text the text contains a time zone ID string at the position.
+     * @param pos the position
+     * @param tzID receives the zone ID
+     * @return a reference to tzID
+     */
+    UnicodeString& parseZoneID(const UnicodeString& text, ParsePosition& pos, UnicodeString& tzID) const;
+
+    /**
+     * Parse a short zone ID.
+     * @param text the text contains a short time zone ID string at the position.
+     * @param pos the position
+     * @param tzID receives the short zone ID
+     * @return a reference to tzID
+     */
+    UnicodeString& parseShortZoneID(const UnicodeString& text, ParsePosition& pos, UnicodeString& tzID) const;
+
+    /**
+     * Parse an exemplar location string.
+     * @param text the text contains an exemplar location string at the position.
+     * @param pos the position.
+     * @param tzID receives the time zone ID
+     * @return a reference to tzID
+     */
+    UnicodeString& parseExemplarLocation(const UnicodeString& text, ParsePosition& pos, UnicodeString& tzID) const;
 };
 
 U_NAMESPACE_END
index 8211b3b1ab9509bc8dc865d847093e4cd9b4abb5..99b71d42af9128fba2ee9b6fa2ff9ac1529f0d4f 100644 (file)
@@ -1,6 +1,6 @@
 /*
 *******************************************************************************
-* Copyright (C) 2011-2012, International Business Machines Corporation and    *
+* Copyright (C) 2011-2013, International Business Machines Corporation and    *
 * others. All Rights Reserved.                                                *
 *******************************************************************************
 */
@@ -60,7 +60,12 @@ typedef enum UTimeZoneNameType {
      * Short display name for daylight saving time, such as "EDT".
      * @draft ICU 50
      */
-    UTZNM_SHORT_DAYLIGHT    = 0x20
+    UTZNM_SHORT_DAYLIGHT    = 0x20,
+    /**
+     * Exemplar location name, such as "Los Angeles".
+     * @draft ICU 51
+     */
+    UTZNM_EXEMPLAR_LOCATION = 0x40
 } UTimeZoneNameType;
 
 U_CDECL_END
index 1d21c74eaff41ad7e1843d317b6f40b5e1ac6d3b..6f542d379f32a7a3024694c19ceb5169a4f9bd10 100644 (file)
@@ -713,7 +713,31 @@ typedef enum UDateFormatField {
      */
     UDAT_YEAR_NAME_FIELD = 30,
 
-   /**
+    /**
+     * FieldPosition selector for 'O' field alignment,
+     * corresponding to the UCAL_ZONE_OFFSET and UCAL_DST_OFFSETfields.
+     * This displays the localized GMT format.
+     * @draft ICU 51
+     */
+    UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD = 31,
+
+    /**
+     * FieldPosition selector for 'X' field alignment,
+     * corresponding to the UCAL_ZONE_OFFSET and UCAL_DST_OFFSETfields.
+     * This displays the ISO 8601 local time offset format or UTC indicator ("Z").
+     * @draft ICU 51
+     */
+    UDAT_TIMEZONE_ISO_FIELD = 32,
+
+    /**
+     * FieldPosition selector for 'x' field alignment,
+     * corresponding to the UCAL_ZONE_OFFSET and UCAL_DST_OFFSETfields.
+     * This displays the ISO 8601 local time offset format.
+     * @draft ICU 51
+     */
+    UDAT_TIMEZONE_ISO_LOCAL_FIELD = 33,
+
+    /**
      * Number of FieldPosition and UFieldPosition selectors for
      * DateFormat and UDateFormat.
      * Valid selectors range from 0 to UDAT_FIELD_COUNT-1.
@@ -721,7 +745,7 @@ typedef enum UDateFormatField {
      * in the future.
      * @stable ICU 3.0
      */
-    UDAT_FIELD_COUNT = 31
+    UDAT_FIELD_COUNT = 34
 
 } UDateFormatField;
 
index 53a3ef3465bc33ad105f44b8e52577481abf0af3..522c3f04990e3a07371f48de77bea442988db839 100644 (file)
@@ -117,7 +117,7 @@ static const char gMetaZones[]          = "metaZones";
 static const char gMetazoneInfo[]       = "metazoneInfo";
 static const char gMapTimezonesTag[]    = "mapTimezones";
 
-static const char gTimeZoneTypes[]      = "timezoneTypes";
+static const char gKeyTypeData[]        = "keyTypeData";
 static const char gTypeAliasTag[]       = "typeAlias";
 static const char gTypeMapTag[]         = "typeMap";
 static const char gTimezoneTag[]        = "timezone";
@@ -282,7 +282,7 @@ ZoneMeta::getCanonicalCLDRID(const UnicodeString &tzid, UErrorCode& status) {
         }
     }
 
-    UResourceBundle *top = ures_openDirect(NULL, gTimeZoneTypes, &tmpStatus);
+    UResourceBundle *top = ures_openDirect(NULL, gKeyTypeData, &tmpStatus);
     UResourceBundle *rb = ures_getByKey(top, gTypeMapTag, NULL, &tmpStatus);
     ures_getByKey(rb, gTimezoneTag, rb, &tmpStatus);
     ures_getByKey(rb, id, rb, &tmpStatus);
@@ -431,6 +431,7 @@ ZoneMeta::getCanonicalCountry(const UnicodeString &tzid, UnicodeString &country,
 
                     if (U_SUCCESS(status)) {
                         gCountryInfoVectorsInitialized = TRUE;
+                        ucln_i18n_registerCleanup(UCLN_I18N_ZONEMETA, zoneMeta_cleanup);
                     } else {
                         delete gSingleZoneCountries;
                         delete gMultiZonesCountries;
@@ -828,6 +829,7 @@ ZoneMeta::initAvailableMetaZoneIDs () {
                         gMetaZoneIDs = metaZoneIDs;
                         gMetaZoneIDTable = metaZoneIDTable;
                         gMetaZoneIDsInitialized = TRUE;
+                        ucln_i18n_registerCleanup(UCLN_I18N_ZONEMETA, zoneMeta_cleanup);
                     } else {
                         uhash_close(metaZoneIDTable);
                         delete metaZoneIDs;
@@ -906,6 +908,56 @@ ZoneMeta::formatCustomID(uint8_t hour, uint8_t min, uint8_t sec, UBool negative,
     return id;
 }
 
+const UChar*
+ZoneMeta::getShortID(const TimeZone& tz) {
+    const UChar* canonicalID = NULL;
+    if (dynamic_cast<const OlsonTimeZone *>(&tz) != NULL) {
+        // short cut for OlsonTimeZone
+        const OlsonTimeZone *otz = (const OlsonTimeZone*)&tz;
+        canonicalID = otz->getCanonicalID();
+    }
+    if (canonicalID == NULL) {
+        return NULL;
+    }
+    return getShortIDFromCanonical(canonicalID);
+}
+
+const UChar*
+ZoneMeta::getShortID(const UnicodeString& id) {
+    UErrorCode status = U_ZERO_ERROR;
+    const UChar* canonicalID = ZoneMeta::getCanonicalCLDRID(id, status);
+    if (U_FAILURE(status) || canonicalID == NULL) {
+        return NULL;
+    }
+    return ZoneMeta::getShortIDFromCanonical(canonicalID);
+}
+
+const UChar*
+ZoneMeta::getShortIDFromCanonical(const UChar* canonicalID) {
+    const UChar* shortID = NULL;
+    int32_t len = u_strlen(canonicalID);
+    char tzidKey[ZID_KEY_MAX + 1];
+
+    u_UCharsToChars(canonicalID, tzidKey, len);
+    tzidKey[len] = (char) 0; // Make sure it is null terminated.
+
+    // replace '/' with ':'
+    char *p = tzidKey;
+    while (*p++) {
+        if (*p == '/') {
+            *p = ':';
+        }
+    }
+
+    UErrorCode status = U_ZERO_ERROR;
+    UResourceBundle *rb = ures_openDirect(NULL, gKeyTypeData, &status);
+    ures_getByKey(rb, gTypeMapTag, rb, &status);
+    ures_getByKey(rb, gTimezoneTag, rb, &status);
+    shortID = ures_getStringByKey(rb, tzidKey, NULL, &status);
+    ures_close(rb);
+
+    return shortID;
+}
 
 U_NAMESPACE_END
 
index 26c2b04fa35b83f61d6ada3b1c06636243fb9bf1..3c4218276ac18d043b3d5428e89a9d35df1abe5f 100644 (file)
@@ -90,11 +90,28 @@ public:
      */
     static TimeZone* createCustomTimeZone(int32_t offset);
 
+    /**
+     * Returns the time zone's short ID (null terminated) for the zone.
+     * For example, "uslax" for zone "America/Los_Angeles".
+     * @param tz the time zone
+     * @return the short ID of the time zone, or null if the short ID is not available.
+     */
+    static const UChar* U_EXPORT2 getShortID(const TimeZone& tz);
+
+    /**
+     * Returns the time zone's short ID (null terminated) for the zone ID.
+     * For example, "uslax" for zone ID "America/Los_Angeles".
+     * @param tz the time zone ID
+     * @return the short ID of the time zone ID, or null if the short ID is not available.
+     */
+    static const UChar* U_EXPORT2 getShortID(const UnicodeString& id);
+
 private:
     ZoneMeta(); // Prevent construction.
     static UVector* createMetazoneMappings(const UnicodeString &tzid);
     static void initAvailableMetaZoneIDs();
     static UnicodeString& formatCustomID(uint8_t hour, uint8_t min, uint8_t sec, UBool negative, UnicodeString& id);
+    static const UChar* getShortIDFromCanonical(const UChar* canonicalID);
 };
 
 U_NAMESPACE_END
index 90d27c9e45e6e56568de19488302e2c9c6347cd6..bd4fd8482e67280a9af47a6d8ab1aa69ffb4e767 100644 (file)
@@ -647,7 +647,7 @@ static void TestSymbols()
     VerifygetSymbols(def, UDAT_QUARTERS, 3, "4th quarter");
     VerifygetSymbols(fr, UDAT_SHORT_QUARTERS, 1, "T2");
     VerifygetSymbols(def, UDAT_SHORT_QUARTERS, 2, "Q3");
-    VerifygetSymbols(def,UDAT_LOCALIZED_CHARS, 0, "GyMdkHmsSEDFwWahKzYeugAZvcLQqVU");
+    VerifygetSymbols(def,UDAT_LOCALIZED_CHARS, 0, "GyMdkHmsSEDFwWahKzYeugAZvcLQqVUOXx");
 
 
     if(result != NULL) {
index c879ba866a31a6f3a3eb05e312370d8661af3841..3ebec5cc854c73c48a0116ca70304e0179134b64 100644 (file)
@@ -420,7 +420,7 @@ DateFormatTest::escape(UnicodeString& s)
 /**
  * This MUST be kept in sync with DateFormatSymbols.gPatternChars.
  */
-static const char* PATTERN_CHARS = "GyMdkHmsSEDFwWahKzYeugAZvcLQqVU";
+static const char* PATTERN_CHARS = "GyMdkHmsSEDFwWahKzYeugAZvcLQqVUOXx";
 
 /**
  * A list of the names of all the fields in DateFormat.
@@ -457,7 +457,10 @@ static const char* DATEFORMAT_FIELD_NAMES[] = {
     "QUARTER_FIELD",
     "STAND_ALONE_QUARTER_FIELD",
     "TIMEZONE_SPECIAL_FIELD",
-    "YEAR_NAME_FIELD"
+    "YEAR_NAME_FIELD",
+    "TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD",
+    "TIMEZONE_ISO_FIELD",
+    "TIMEZONE_ISO_LOCAL_FIELD",
 };
 
 static const int32_t DATEFORMAT_FIELD_NAMES_LENGTH =
@@ -510,18 +513,25 @@ void DateFormatTest::TestFieldPosition() {
     // Expected output field values for above DateFormats on aug13
     // Fields are given in order of DateFormat field number
     const char* EXPECTED[] = {
-        "", "1997", "August", "13", "", "", "34", "12", "",
-        "Wednesday", "", "", "", "", "PM", "2", "", "Pacific Daylight Time", "", "", "", "", "", "", "", "", "", "", "","","",
-
-        "", "1997", "ao\\u00FBt", "13", "", "14", "34", "12", "",
-        "mercredi", "", "", "", "", "", "", "", "heure avanc\\u00e9e du Pacifique", "", "", "", "", "", "", "",  "", "", "", "", "","",
-
-        "AD", "1997", "8", "13", "14", "14", "34", "12", "5",
-        "Wed", "225", "2", "33", "3", "PM", "2", "2", "PDT", "1997", "4", "1997", "2450674", "52452513", "-0700", "PT",  "4", "8", "3", "3","PDT","1997",
-
-        "Anno Domini", "1997", "August", "0013", "0014", "0014", "0034", "0012", "5130",
-        "Wednesday", "0225", "0002", "0033", "0003", "PM", "0002", "0002", "Pacific Daylight Time", "1997", "Wednesday", "1997", "2450674", "52452513", "GMT-07:00",
-        "Pacific Time",  "Wednesday", "August", "3rd quarter", "3rd quarter", "Los Angeles Time","1997"
+        "", "1997", "August", "13", "", "", "34", "12", "", "Wednesday",
+        "", "", "", "", "PM", "2", "", "Pacific Daylight Time", "", "",
+        "", "", "", "", "", "", "", "", "", "",
+        "", "", "", "",
+
+        "", "1997", "ao\\u00FBt", "13", "", "14", "34", "12", "", "mercredi",
+        "", "", "", "", "", "", "", "heure avanc\\u00e9e du Pacifique", "", "",
+        "", "", "", "", "",  "", "", "", "", "",
+        "", "", "", "",
+
+        "AD", "1997", "8", "13", "14", "14", "34", "12", "5", "Wed",
+        "225", "2", "33", "3", "PM", "2", "2", "PDT", "1997", "4",
+        "1997", "2450674", "52452513", "-0700", "PT",  "4", "8", "3", "3", "uslax",
+        "1997", "GMT-7", "-07", "-07",
+
+        "Anno Domini", "1997", "August", "0013", "0014", "0014", "0034", "0012", "5130", "Wednesday",
+        "0225", "0002", "0033", "0003", "PM", "0002", "0002", "Pacific Daylight Time", "1997", "Wednesday",
+        "1997", "2450674", "52452513", "GMT-07:00", "Pacific Time",  "Wednesday", "August", "3rd quarter", "3rd quarter", "Los Angeles Time",
+        "1997", "GMT-07:00", "-0700", "-0700",
     };
 
     const int32_t EXPECTED_LENGTH = sizeof(EXPECTED)/sizeof(EXPECTED[0]);
@@ -2434,26 +2444,22 @@ void DateFormatTest::TestTimeZoneDisplayName()
         { "en", "America/Los_Angeles", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-08:00", "-8:00" },
         { "en", "America/Los_Angeles", "2004-01-15T00:00:00Z", "ZZZZZ", "-08:00", "-8:00" },
         { "en", "America/Los_Angeles", "2004-01-15T00:00:00Z", "z", "PST", "America/Los_Angeles" },
-        { "en", "America/Los_Angeles", "2004-01-15T00:00:00Z", "V", "PST", "America/Los_Angeles" },
         { "en", "America/Los_Angeles", "2004-01-15T00:00:00Z", "zzzz", "Pacific Standard Time", "America/Los_Angeles" },
         { "en", "America/Los_Angeles", "2004-07-15T00:00:00Z", "Z", "-0700", "-7:00" },
         { "en", "America/Los_Angeles", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-07:00", "-7:00" },
         { "en", "America/Los_Angeles", "2004-07-15T00:00:00Z", "z", "PDT", "America/Los_Angeles" },
-        { "en", "America/Los_Angeles", "2004-07-15T00:00:00Z", "V", "PDT", "America/Los_Angeles" },
         { "en", "America/Los_Angeles", "2004-07-15T00:00:00Z", "zzzz", "Pacific Daylight Time", "America/Los_Angeles" },
         { "en", "America/Los_Angeles", "2004-07-15T00:00:00Z", "v", "PT", "America/Los_Angeles" },
         { "en", "America/Los_Angeles", "2004-07-15T00:00:00Z", "vvvv", "Pacific Time", "America/Los_Angeles" },
         { "en", "America/Los_Angeles", "2004-07-15T00:00:00Z", "VVVV", "Los Angeles Time", "America/Los_Angeles" },
-        { "en_GB", "America/Los_Angeles", "2004-01-15T12:00:00Z", "z", "GMT-08:00", "America/Los_Angeles" },
+        { "en_GB", "America/Los_Angeles", "2004-01-15T12:00:00Z", "z", "GMT-8", "America/Los_Angeles" },
         { "en", "America/Phoenix", "2004-01-15T00:00:00Z", "Z", "-0700", "-7:00" },
         { "en", "America/Phoenix", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-07:00", "-7:00" },
         { "en", "America/Phoenix", "2004-01-15T00:00:00Z", "z", "MST", "America/Phoenix" },
-        { "en", "America/Phoenix", "2004-01-15T00:00:00Z", "V", "MST", "America/Phoenix" },
         { "en", "America/Phoenix", "2004-01-15T00:00:00Z", "zzzz", "Mountain Standard Time", "America/Phoenix" },
         { "en", "America/Phoenix", "2004-07-15T00:00:00Z", "Z", "-0700", "-7:00" },
         { "en", "America/Phoenix", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-07:00", "-7:00" },
         { "en", "America/Phoenix", "2004-07-15T00:00:00Z", "z", "MST", "America/Phoenix" },
-        { "en", "America/Phoenix", "2004-07-15T00:00:00Z", "V", "MST", "America/Phoenix" },
         { "en", "America/Phoenix", "2004-07-15T00:00:00Z", "zzzz", "Mountain Standard Time", "America/Phoenix" },
         { "en", "America/Phoenix", "2004-07-15T00:00:00Z", "v", "MST", "America/Phoenix" },
         { "en", "America/Phoenix", "2004-07-15T00:00:00Z", "vvvv", "Mountain Standard Time", "America/Phoenix" },
@@ -2461,13 +2467,11 @@ void DateFormatTest::TestTimeZoneDisplayName()
 
         { "en", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
         { "en", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
-        { "en", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-03:00", "-3:00" },
-        { "en", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "V", "GMT-03:00", "-3:00" },
+        { "en", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
         { "en", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "Argentina Standard Time", "-3:00" },
         { "en", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
         { "en", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
-        { "en", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-03:00", "-3:00" },
-        { "en", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "V", "GMT-03:00", "-3:00" },
+        { "en", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
         { "en", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "Argentina Standard Time", "-3:00" },
         { "en", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "Buenos Aires Time", "America/Buenos_Aires" },
         { "en", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "Argentina Standard Time", "America/Buenos_Aires" },
@@ -2475,13 +2479,11 @@ void DateFormatTest::TestTimeZoneDisplayName()
 
         { "en", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
         { "en", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
-        { "en", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-03:00", "-3:00" },
-        { "en", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "V", "GMT-03:00", "-3:00" },
+        { "en", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
         { "en", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "Argentina Standard Time", "-3:00" },
         { "en", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
         { "en", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
-        { "en", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-03:00", "-3:00" },
-        { "en", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "V", "GMT-03:00", "-3:00" },
+        { "en", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
         { "en", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "Argentina Standard Time", "-3:00" },
         { "en", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "Buenos Aires Time", "America/Buenos_Aires" },
         { "en", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "Argentina Standard Time", "America/Buenos_Aires" },
@@ -2489,13 +2491,11 @@ void DateFormatTest::TestTimeZoneDisplayName()
 
         { "en", "America/Havana", "2004-01-15T00:00:00Z", "Z", "-0500", "-5:00" },
         { "en", "America/Havana", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-05:00", "-5:00" },
-        { "en", "America/Havana", "2004-01-15T00:00:00Z", "z", "GMT-05:00", "-5:00" },
-        { "en", "America/Havana", "2004-01-15T00:00:00Z", "V", "GMT-05:00", "-5:00" },
+        { "en", "America/Havana", "2004-01-15T00:00:00Z", "z", "GMT-5", "-5:00" },
         { "en", "America/Havana", "2004-01-15T00:00:00Z", "zzzz", "Cuba Standard Time", "-5:00" },
         { "en", "America/Havana", "2004-07-15T00:00:00Z", "Z", "-0400", "-4:00" },
         { "en", "America/Havana", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-04:00", "-4:00" },
-        { "en", "America/Havana", "2004-07-15T00:00:00Z", "z", "GMT-04:00", "-4:00" },
-        { "en", "America/Havana", "2004-07-15T00:00:00Z", "V", "GMT-04:00", "-4:00" },
+        { "en", "America/Havana", "2004-07-15T00:00:00Z", "z", "GMT-4", "-4:00" },
         { "en", "America/Havana", "2004-07-15T00:00:00Z", "zzzz", "Cuba Daylight Time", "-4:00" },
         { "en", "America/Havana", "2004-07-15T00:00:00Z", "v", "Cuba Time", "America/Havana" },
         { "en", "America/Havana", "2004-07-15T00:00:00Z", "vvvv", "Cuba Time", "America/Havana" },
@@ -2503,13 +2503,11 @@ void DateFormatTest::TestTimeZoneDisplayName()
 
         { "en", "Australia/ACT", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
         { "en", "Australia/ACT", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
-        { "en", "Australia/ACT", "2004-01-15T00:00:00Z", "z", "GMT+11:00", "+11:00" },
-        { "en", "Australia/ACT", "2004-01-15T00:00:00Z", "V", "GMT+11:00", "+11:00" },
+        { "en", "Australia/ACT", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
         { "en", "Australia/ACT", "2004-01-15T00:00:00Z", "zzzz", "Australian Eastern Daylight Time", "+11:00" },
         { "en", "Australia/ACT", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
         { "en", "Australia/ACT", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
-        { "en", "Australia/ACT", "2004-07-15T00:00:00Z", "z", "GMT+10:00", "+10:00" },
-        { "en", "Australia/ACT", "2004-07-15T00:00:00Z", "V", "GMT+10:00", "+10:00" },
+        { "en", "Australia/ACT", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
         { "en", "Australia/ACT", "2004-07-15T00:00:00Z", "zzzz", "Australian Eastern Standard Time", "+10:00" },
         { "en", "Australia/ACT", "2004-07-15T00:00:00Z", "v", "Sydney Time", "Australia/Sydney" },
         { "en", "Australia/ACT", "2004-07-15T00:00:00Z", "vvvv", "Eastern Australia Time", "Australia/Sydney" },
@@ -2517,13 +2515,11 @@ void DateFormatTest::TestTimeZoneDisplayName()
 
         { "en", "Australia/Sydney", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
         { "en", "Australia/Sydney", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
-        { "en", "Australia/Sydney", "2004-01-15T00:00:00Z", "z", "GMT+11:00", "+11:00" },
-        { "en", "Australia/Sydney", "2004-01-15T00:00:00Z", "V", "GMT+11:00", "+11:00" },
+        { "en", "Australia/Sydney", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
         { "en", "Australia/Sydney", "2004-01-15T00:00:00Z", "zzzz", "Australian Eastern Daylight Time", "+11:00" },
         { "en", "Australia/Sydney", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
         { "en", "Australia/Sydney", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
-        { "en", "Australia/Sydney", "2004-07-15T00:00:00Z", "z", "GMT+10:00", "+10:00" },
-        { "en", "Australia/Sydney", "2004-07-15T00:00:00Z", "V", "GMT+10:00", "+10:00" },
+        { "en", "Australia/Sydney", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
         { "en", "Australia/Sydney", "2004-07-15T00:00:00Z", "zzzz", "Australian Eastern Standard Time", "+10:00" },
         { "en", "Australia/Sydney", "2004-07-15T00:00:00Z", "v", "Sydney Time", "Australia/Sydney" },
         { "en", "Australia/Sydney", "2004-07-15T00:00:00Z", "vvvv", "Eastern Australia Time", "Australia/Sydney" },
@@ -2532,12 +2528,10 @@ void DateFormatTest::TestTimeZoneDisplayName()
         { "en", "Europe/London", "2004-01-15T00:00:00Z", "Z", "+0000", "+0:00" },
         { "en", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", "GMT", "+0:00" },
         { "en", "Europe/London", "2004-01-15T00:00:00Z", "z", "GMT", "+0:00" },
-        { "en", "Europe/London", "2004-01-15T00:00:00Z", "V", "GMT", "+0:00" },
         { "en", "Europe/London", "2004-01-15T00:00:00Z", "zzzz", "Greenwich Mean Time", "+0:00" },
         { "en", "Europe/London", "2004-07-15T00:00:00Z", "Z", "+0100", "+1:00" },
         { "en", "Europe/London", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+01:00", "+1:00" },
-        { "en", "Europe/London", "2004-07-15T00:00:00Z", "z", "GMT+01:00", "Europe/London" },
-        { "en", "Europe/London", "2004-07-15T00:00:00Z", "V", "GMT+01:00", "Europe/London" },
+        { "en", "Europe/London", "2004-07-15T00:00:00Z", "z", "GMT+1", "Europe/London" },
         { "en", "Europe/London", "2004-07-15T00:00:00Z", "zzzz", "British Summer Time", "Europe/London" },
     // icu en.txt has exemplar city for this time zone
         { "en", "Europe/London", "2004-07-15T00:00:00Z", "v", "United Kingdom Time", "Europe/London" },
@@ -2546,25 +2540,23 @@ void DateFormatTest::TestTimeZoneDisplayName()
 
         { "en", "Etc/GMT+3", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
         { "en", "Etc/GMT+3", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
-        { "en", "Etc/GMT+3", "2004-01-15T00:00:00Z", "z", "GMT-03:00", "-3:00" },
+        { "en", "Etc/GMT+3", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
         { "en", "Etc/GMT+3", "2004-01-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
         { "en", "Etc/GMT+3", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
         { "en", "Etc/GMT+3", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
-        { "en", "Etc/GMT+3", "2004-07-15T00:00:00Z", "z", "GMT-03:00", "-3:00" },
+        { "en", "Etc/GMT+3", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
         { "en", "Etc/GMT+3", "2004-07-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
-        { "en", "Etc/GMT+3", "2004-07-15T00:00:00Z", "v", "GMT-03:00", "-3:00" },
+        { "en", "Etc/GMT+3", "2004-07-15T00:00:00Z", "v", "GMT-3", "-3:00" },
         { "en", "Etc/GMT+3", "2004-07-15T00:00:00Z", "vvvv", "GMT-03:00", "-3:00" },
 
         // JB#5150
         { "en", "Asia/Calcutta", "2004-01-15T00:00:00Z", "Z", "+0530", "+5:30" },
         { "en", "Asia/Calcutta", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
-        { "en", "Asia/Calcutta", "2004-01-15T00:00:00Z", "z", "GMT+05:30", "+5:30" },
-        { "en", "Asia/Calcutta", "2004-01-15T00:00:00Z", "V", "GMT+05:30", "+5:30" },
+        { "en", "Asia/Calcutta", "2004-01-15T00:00:00Z", "z", "GMT+5:30", "+5:30" },
         { "en", "Asia/Calcutta", "2004-01-15T00:00:00Z", "zzzz", "India Standard Time", "+5:30" },
         { "en", "Asia/Calcutta", "2004-07-15T00:00:00Z", "Z", "+0530", "+5:30" },
         { "en", "Asia/Calcutta", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
-        { "en", "Asia/Calcutta", "2004-07-15T00:00:00Z", "z", "GMT+05:30", "+05:30" },
-        { "en", "Asia/Calcutta", "2004-07-15T00:00:00Z", "V", "GMT+05:30", "+05:30" },
+        { "en", "Asia/Calcutta", "2004-07-15T00:00:00Z", "z", "GMT+5:30", "+05:30" },
         { "en", "Asia/Calcutta", "2004-07-15T00:00:00Z", "zzzz", "India Standard Time", "+5:30" },
         { "en", "Asia/Calcutta", "2004-07-15T00:00:00Z", "v", "India Time", "Asia/Calcutta" },
         { "en", "Asia/Calcutta", "2004-07-15T00:00:00Z", "vvvv", "India Standard Time", "Asia/Calcutta" },
@@ -2577,44 +2569,44 @@ void DateFormatTest::TestTimeZoneDisplayName()
 
         { "de", "America/Los_Angeles", "2004-01-15T00:00:00Z", "Z", "-0800", "-8:00" },
         { "de", "America/Los_Angeles", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-08:00", "-8:00" },
-        { "de", "America/Los_Angeles", "2004-01-15T00:00:00Z", "z", "GMT-08:00", "-8:00" },
+        { "de", "America/Los_Angeles", "2004-01-15T00:00:00Z", "z", "GMT-8", "-8:00" },
         { "de", "America/Los_Angeles", "2004-01-15T00:00:00Z", "zzzz", "Nordamerikanische Westk\\u00fcsten-Normalzeit", "-8:00" },
         { "de", "America/Los_Angeles", "2004-07-15T00:00:00Z", "Z", "-0700", "-7:00" },
         { "de", "America/Los_Angeles", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-07:00", "-7:00" },
-        { "de", "America/Los_Angeles", "2004-07-15T00:00:00Z", "z", "GMT-07:00", "-7:00" },
+        { "de", "America/Los_Angeles", "2004-07-15T00:00:00Z", "z", "GMT-7", "-7:00" },
         { "de", "America/Los_Angeles", "2004-07-15T00:00:00Z", "zzzz", "Nordamerikanische Westk\\u00fcsten-Sommerzeit", "-7:00" },
         { "de", "America/Los_Angeles", "2004-07-15T00:00:00Z", "v", "Los Angeles Zeit", "America/Los_Angeles" },
         { "de", "America/Los_Angeles", "2004-07-15T00:00:00Z", "vvvv", "Nordamerikanische Westk\\u00fcstenzeit", "America/Los_Angeles" },
 
         { "de", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
         { "de", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
-        { "de", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-03:00", "-3:00" },
+        { "de", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
         { "de", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "Argentinische Normalzeit", "-3:00" },
         { "de", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
         { "de", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
-        { "de", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-03:00", "-3:00" },
+        { "de", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
         { "de", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "Argentinische Normalzeit", "-3:00" },
         { "de", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "Buenos Aires Zeit", "America/Buenos_Aires" },
         { "de", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "Argentinische Normalzeit", "America/Buenos_Aires" },
 
         { "de", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
         { "de", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
-        { "de", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-03:00", "-3:00" },
+        { "de", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
         { "de", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "Argentinische Normalzeit", "-3:00" },
         { "de", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
         { "de", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
-        { "de", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-03:00", "-3:00" },
+        { "de", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
         { "de", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "Argentinische Normalzeit", "-3:00" },
         { "de", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "Buenos Aires Zeit", "America/Buenos_Aires" },
         { "de", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "Argentinische Normalzeit", "America/Buenos_Aires" },
 
         { "de", "America/Havana", "2004-01-15T00:00:00Z", "Z", "-0500", "-5:00" },
         { "de", "America/Havana", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-05:00", "-5:00" },
-        { "de", "America/Havana", "2004-01-15T00:00:00Z", "z", "GMT-05:00", "-5:00" },
+        { "de", "America/Havana", "2004-01-15T00:00:00Z", "z", "GMT-5", "-5:00" },
         { "de", "America/Havana", "2004-01-15T00:00:00Z", "zzzz", "Kubanische Normalzeit", "-5:00" },
         { "de", "America/Havana", "2004-07-15T00:00:00Z", "Z", "-0400", "-4:00" },
         { "de", "America/Havana", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-04:00", "-4:00" },
-        { "de", "America/Havana", "2004-07-15T00:00:00Z", "z", "GMT-04:00", "-4:00" },
+        { "de", "America/Havana", "2004-07-15T00:00:00Z", "z", "GMT-4", "-4:00" },
         { "de", "America/Havana", "2004-07-15T00:00:00Z", "zzzz", "Kubanische Sommerzeit", "-4:00" },
         { "de", "America/Havana", "2004-07-15T00:00:00Z", "v", "Kuba Zeit", "America/Havana" },
         { "de", "America/Havana", "2004-07-15T00:00:00Z", "vvvv", "Kubanische Zeit", "America/Havana" },
@@ -2624,22 +2616,22 @@ void DateFormatTest::TestTimeZoneDisplayName()
 
         { "de", "Australia/ACT", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
         { "de", "Australia/ACT", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
-        { "de", "Australia/ACT", "2004-01-15T00:00:00Z", "z", "GMT+11:00", "+11:00" },
+        { "de", "Australia/ACT", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
         { "de", "Australia/ACT", "2004-01-15T00:00:00Z", "zzzz", "Ostaustralische Sommerzeit", "+11:00" },
         { "de", "Australia/ACT", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
         { "de", "Australia/ACT", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
-        { "de", "Australia/ACT", "2004-07-15T00:00:00Z", "z", "GMT+10:00", "+10:00" },
+        { "de", "Australia/ACT", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
         { "de", "Australia/ACT", "2004-07-15T00:00:00Z", "zzzz", "Ostaustralische Normalzeit", "+10:00" },
         { "de", "Australia/ACT", "2004-07-15T00:00:00Z", "v", "Sydney Zeit", "Australia/Sydney" },
         { "de", "Australia/ACT", "2004-07-15T00:00:00Z", "vvvv", "Ostaustralische Zeit", "Australia/Sydney" },
 
         { "de", "Australia/Sydney", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
         { "de", "Australia/Sydney", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
-        { "de", "Australia/Sydney", "2004-01-15T00:00:00Z", "z", "GMT+11:00", "+11:00" },
+        { "de", "Australia/Sydney", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
         { "de", "Australia/Sydney", "2004-01-15T00:00:00Z", "zzzz", "Ostaustralische Sommerzeit", "+11:00" },
         { "de", "Australia/Sydney", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
         { "de", "Australia/Sydney", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
-        { "de", "Australia/Sydney", "2004-07-15T00:00:00Z", "z", "GMT+10:00", "+10:00" },
+        { "de", "Australia/Sydney", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
         { "de", "Australia/Sydney", "2004-07-15T00:00:00Z", "zzzz", "Ostaustralische Normalzeit", "+10:00" },
         { "de", "Australia/Sydney", "2004-07-15T00:00:00Z", "v", "Sydney Zeit", "Australia/Sydney" },
         { "de", "Australia/Sydney", "2004-07-15T00:00:00Z", "vvvv", "Ostaustralische Zeit", "Australia/Sydney" },
@@ -2650,30 +2642,30 @@ void DateFormatTest::TestTimeZoneDisplayName()
         { "de", "Europe/London", "2004-01-15T00:00:00Z", "zzzz", "Mittlere Greenwich-Zeit", "+0:00" },
         { "de", "Europe/London", "2004-07-15T00:00:00Z", "Z", "+0100", "+1:00" },
         { "de", "Europe/London", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+01:00", "+1:00" },
-        { "de", "Europe/London", "2004-07-15T00:00:00Z", "z", "GMT+01:00", "+1:00" },
+        { "de", "Europe/London", "2004-07-15T00:00:00Z", "z", "GMT+1", "+1:00" },
         { "de", "Europe/London", "2004-07-15T00:00:00Z", "zzzz", "Britische Sommerzeit", "+1:00" },
         { "de", "Europe/London", "2004-07-15T00:00:00Z", "v", "Vereinigtes K\\u00f6nigreich Zeit", "Europe/London" },
         { "de", "Europe/London", "2004-07-15T00:00:00Z", "vvvv", "Vereinigtes K\\u00f6nigreich Zeit", "Europe/London" },
 
         { "de", "Etc/GMT+3", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
         { "de", "Etc/GMT+3", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
-        { "de", "Etc/GMT+3", "2004-01-15T00:00:00Z", "z", "GMT-03:00", "-3:00" },
+        { "de", "Etc/GMT+3", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
         { "de", "Etc/GMT+3", "2004-01-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
         { "de", "Etc/GMT+3", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
         { "de", "Etc/GMT+3", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
-        { "de", "Etc/GMT+3", "2004-07-15T00:00:00Z", "z", "GMT-03:00", "-3:00" },
+        { "de", "Etc/GMT+3", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
         { "de", "Etc/GMT+3", "2004-07-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
-        { "de", "Etc/GMT+3", "2004-07-15T00:00:00Z", "v", "GMT-03:00", "-3:00" },
+        { "de", "Etc/GMT+3", "2004-07-15T00:00:00Z", "v", "GMT-3", "-3:00" },
         { "de", "Etc/GMT+3", "2004-07-15T00:00:00Z", "vvvv", "GMT-03:00", "-3:00" },
 
         // JB#5150
         { "de", "Asia/Calcutta", "2004-01-15T00:00:00Z", "Z", "+0530", "+5:30" },
         { "de", "Asia/Calcutta", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
-        { "de", "Asia/Calcutta", "2004-01-15T00:00:00Z", "z", "GMT+05:30", "+5:30" },
+        { "de", "Asia/Calcutta", "2004-01-15T00:00:00Z", "z", "GMT+5:30", "+5:30" },
         { "de", "Asia/Calcutta", "2004-01-15T00:00:00Z", "zzzz", "Indische Zeit", "+5:30" },
         { "de", "Asia/Calcutta", "2004-07-15T00:00:00Z", "Z", "+0530", "+5:30" },
         { "de", "Asia/Calcutta", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
-        { "de", "Asia/Calcutta", "2004-07-15T00:00:00Z", "z", "GMT+05:30", "+05:30" },
+        { "de", "Asia/Calcutta", "2004-07-15T00:00:00Z", "z", "GMT+5:30", "+05:30" },
         { "de", "Asia/Calcutta", "2004-07-15T00:00:00Z", "zzzz", "Indische Zeit", "+5:30" },
         { "de", "Asia/Calcutta", "2004-07-15T00:00:00Z", "v", "Indien Zeit", "Asia/Calcutta" },
         { "de", "Asia/Calcutta", "2004-07-15T00:00:00Z", "vvvv", "Indische Zeit", "Asia/Calcutta" },
@@ -2682,11 +2674,11 @@ void DateFormatTest::TestTimeZoneDisplayName()
 
         { "zh", "America/Los_Angeles", "2004-01-15T00:00:00Z", "Z", "-0800", "-8:00" },
         { "zh", "America/Los_Angeles", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-0800", "-8:00" },
-        { "zh", "America/Los_Angeles", "2004-01-15T00:00:00Z", "z", "GMT-0800", "America/Los_Angeles" },
+        { "zh", "America/Los_Angeles", "2004-01-15T00:00:00Z", "z", "GMT-8", "America/Los_Angeles" },
         { "zh", "America/Los_Angeles", "2004-01-15T00:00:00Z", "zzzz", "\\u5317\\u7f8e\\u592a\\u5e73\\u6d0b\\u6807\\u51c6\\u65f6\\u95f4", "America/Los_Angeles" },
         { "zh", "America/Los_Angeles", "2004-07-15T00:00:00Z", "Z", "-0700", "-7:00" },
         { "zh", "America/Los_Angeles", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-0700", "-7:00" },
-        { "zh", "America/Los_Angeles", "2004-07-15T00:00:00Z", "z", "GMT-0700", "America/Los_Angeles" },
+        { "zh", "America/Los_Angeles", "2004-07-15T00:00:00Z", "z", "GMT-7", "America/Los_Angeles" },
         { "zh", "America/Los_Angeles", "2004-07-15T00:00:00Z", "zzzz", "\\u5317\\u7f8e\\u592a\\u5e73\\u6d0b\\u590f\\u4ee4\\u65f6\\u95f4", "America/Los_Angeles" },
     // icu zh.txt has exemplar city for this time zone
         { "zh", "America/Los_Angeles", "2004-07-15T00:00:00Z", "v", "\\u6D1B\\u6749\\u77F6\\u65F6\\u95F4", "America/Los_Angeles" },
@@ -2694,44 +2686,44 @@ void DateFormatTest::TestTimeZoneDisplayName()
 
         { "zh", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
         { "zh", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-0300", "-3:00" },
-        { "zh", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-0300", "-3:00" },
+        { "zh", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
         { "zh", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "\\u963f\\u6839\\u5ef7\\u6807\\u51c6\\u65f6\\u95f4", "-3:00" },
         { "zh", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
         { "zh", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-0300", "-3:00" },
-        { "zh", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-0300", "-3:00" },
+        { "zh", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
         { "zh", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "\\u963f\\u6839\\u5ef7\\u6807\\u51c6\\u65f6\\u95f4", "-3:00" },
         { "zh", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "\\u5E03\\u5B9C\\u8BFA\\u65AF\\u827E\\u5229\\u65AF\\u65F6\\u95F4", "America/Buenos_Aires" },
         { "zh", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "\\u963f\\u6839\\u5ef7\\u6807\\u51c6\\u65f6\\u95f4", "America/Buenos_Aires" },
 
         { "zh", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
         { "zh", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-0300", "-3:00" },
-        { "zh", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-0300", "-3:00" },
+        { "zh", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
         { "zh", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "\\u963f\\u6839\\u5ef7\\u6807\\u51c6\\u65f6\\u95f4", "-3:00" },
         { "zh", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
         { "zh", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-0300", "-3:00" },
-        { "zh", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-0300", "-3:00" },
+        { "zh", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
         { "zh", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "\\u963f\\u6839\\u5ef7\\u6807\\u51c6\\u65f6\\u95f4", "-3:00" },
         { "zh", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "\\u5E03\\u5B9C\\u8BFA\\u65AF\\u827E\\u5229\\u65AF\\u65F6\\u95F4", "America/Buenos_Aires" },
         { "zh", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "\\u963f\\u6839\\u5ef7\\u6807\\u51c6\\u65f6\\u95f4", "America/Buenos_Aires" },
 
         { "zh", "America/Havana", "2004-01-15T00:00:00Z", "Z", "-0500", "-5:00" },
         { "zh", "America/Havana", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-0500", "-5:00" },
-        { "zh", "America/Havana", "2004-01-15T00:00:00Z", "z", "GMT-0500", "-5:00" },
+        { "zh", "America/Havana", "2004-01-15T00:00:00Z", "z", "GMT-5", "-5:00" },
         { "zh", "America/Havana", "2004-01-15T00:00:00Z", "zzzz", "\\u53e4\\u5df4\\u6807\\u51c6\\u65f6\\u95f4", "-5:00" },
         { "zh", "America/Havana", "2004-07-15T00:00:00Z", "Z", "-0400", "-4:00" },
         { "zh", "America/Havana", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-0400", "-4:00" },
-        { "zh", "America/Havana", "2004-07-15T00:00:00Z", "z", "GMT-0400", "-4:00" },
+        { "zh", "America/Havana", "2004-07-15T00:00:00Z", "z", "GMT-4", "-4:00" },
         { "zh", "America/Havana", "2004-07-15T00:00:00Z", "zzzz", "\\u53e4\\u5df4\\u590f\\u4ee4\\u65f6\\u95f4", "-4:00" },
         { "zh", "America/Havana", "2004-07-15T00:00:00Z", "v", "\\u53e4\\u5df4\\u65f6\\u95f4", "America/Havana" },
         { "zh", "America/Havana", "2004-07-15T00:00:00Z", "vvvv", "\\u53e4\\u5df4\\u65f6\\u95f4", "America/Havana" },
 
         { "zh", "Australia/ACT", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
         { "zh", "Australia/ACT", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+1100", "+11:00" },
-        { "zh", "Australia/ACT", "2004-01-15T00:00:00Z", "z", "GMT+1100", "+11:00" },
+        { "zh", "Australia/ACT", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
         { "zh", "Australia/ACT", "2004-01-15T00:00:00Z", "zzzz", "\\u6fb3\\u5927\\u5229\\u4e9a\\u4e1c\\u90e8\\u590f\\u4ee4\\u65f6\\u95f4", "+11:00" },
         { "zh", "Australia/ACT", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
         { "zh", "Australia/ACT", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+1000", "+10:00" },
-        { "zh", "Australia/ACT", "2004-07-15T00:00:00Z", "z", "GMT+1000", "+10:00" },
+        { "zh", "Australia/ACT", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
         { "zh", "Australia/ACT", "2004-07-15T00:00:00Z", "zzzz", "\\u6fb3\\u5927\\u5229\\u4e9a\\u4e1c\\u90e8\\u6807\\u51c6\\u65f6\\u95f4", "+10:00" },
     // icu zh.txt does not have info for this time zone
         { "zh", "Australia/ACT", "2004-07-15T00:00:00Z", "v", "\\u6089\\u5C3C\\u65F6\\u95F4", "Australia/Sydney" },
@@ -2739,11 +2731,11 @@ void DateFormatTest::TestTimeZoneDisplayName()
 
         { "zh", "Australia/Sydney", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
         { "zh", "Australia/Sydney", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+1100", "+11:00" },
-        { "zh", "Australia/Sydney", "2004-01-15T00:00:00Z", "z", "GMT+1100", "+11:00" },
+        { "zh", "Australia/Sydney", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
         { "zh", "Australia/Sydney", "2004-01-15T00:00:00Z", "zzzz", "\\u6fb3\\u5927\\u5229\\u4e9a\\u4e1c\\u90e8\\u590f\\u4ee4\\u65f6\\u95f4", "+11:00" },
         { "zh", "Australia/Sydney", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
         { "zh", "Australia/Sydney", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+1000", "+10:00" },
-        { "zh", "Australia/Sydney", "2004-07-15T00:00:00Z", "z", "GMT+1000", "+10:00" },
+        { "zh", "Australia/Sydney", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
         { "zh", "Australia/Sydney", "2004-07-15T00:00:00Z", "zzzz", "\\u6fb3\\u5927\\u5229\\u4e9a\\u4e1c\\u90e8\\u6807\\u51c6\\u65f6\\u95f4", "+10:00" },
         { "zh", "Australia/Sydney", "2004-07-15T00:00:00Z", "v", "\\u6089\\u5C3C\\u65F6\\u95F4", "Australia/Sydney" },
         { "zh", "Australia/Sydney", "2004-07-15T00:00:00Z", "vvvv", "\\u6fb3\\u5927\\u5229\\u4e9a\\u4e1c\\u90e8\\u65f6\\u95f4", "Australia/Sydney" },
@@ -2751,15 +2743,12 @@ void DateFormatTest::TestTimeZoneDisplayName()
         { "zh", "Europe/London", "2004-01-15T00:00:00Z", "Z", "+0000", "+0:00" },
         { "zh", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", "GMT", "+0:00" },
         { "zh", "Europe/London", "2004-01-15T00:00:00Z", "z", "GMT", "+0:00" },
-        { "zh", "Europe/London", "2004-01-15T00:00:00Z", "V", "GMT", "+0:00" },
         { "zh", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", "GMT", "+0:00" },
         { "zh", "Europe/London", "2004-01-15T00:00:00Z", "z", "GMT", "+0:00" },
-        { "zh", "Europe/London", "2004-01-15T00:00:00Z", "V", "GMT", "+0:00" },
         { "zh", "Europe/London", "2004-01-15T00:00:00Z", "zzzz", "\\u683C\\u6797\\u5C3C\\u6CBB\\u6807\\u51C6\\u65F6\\u95F4", "+0:00" },
         { "zh", "Europe/London", "2004-07-15T00:00:00Z", "Z", "+0100", "+1:00" },
         { "zh", "Europe/London", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+0100", "+1:00" },
-        { "zh", "Europe/London", "2004-07-15T00:00:00Z", "z", "GMT+0100", "+1:00" },
-        { "zh", "Europe/London", "2004-07-15T00:00:00Z", "V", "GMT+0100", "+1:00" },
+        { "zh", "Europe/London", "2004-07-15T00:00:00Z", "z", "GMT+1", "+1:00" },
         { "zh", "Europe/London", "2004-07-15T00:00:00Z", "zzzz", "\\u82f1\\u56fd\\u590f\\u4ee4\\u65f6\\u95f4", "+1:00" },
         { "zh", "Europe/London", "2004-07-15T00:00:00Z", "v", "\\u82f1\\u56fd\\u65f6\\u95f4", "Europe/London" },
         { "zh", "Europe/London", "2004-07-15T00:00:00Z", "vvvv", "\\u82f1\\u56fd\\u65f6\\u95f4", "Europe/London" },
@@ -2767,23 +2756,23 @@ void DateFormatTest::TestTimeZoneDisplayName()
 
         { "zh", "Etc/GMT+3", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
         { "zh", "Etc/GMT+3", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-0300", "-3:00" },
-        { "zh", "Etc/GMT+3", "2004-01-15T00:00:00Z", "z", "GMT-0300", "-3:00" },
+        { "zh", "Etc/GMT+3", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
         { "zh", "Etc/GMT+3", "2004-01-15T00:00:00Z", "zzzz", "GMT-0300", "-3:00" },
         { "zh", "Etc/GMT+3", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
         { "zh", "Etc/GMT+3", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-0300", "-3:00" },
-        { "zh", "Etc/GMT+3", "2004-07-15T00:00:00Z", "z", "GMT-0300", "-3:00" },
+        { "zh", "Etc/GMT+3", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
         { "zh", "Etc/GMT+3", "2004-07-15T00:00:00Z", "zzzz", "GMT-0300", "-3:00" },
-        { "zh", "Etc/GMT+3", "2004-07-15T00:00:00Z", "v", "GMT-0300", "-3:00" },
+        { "zh", "Etc/GMT+3", "2004-07-15T00:00:00Z", "v", "GMT-3", "-3:00" },
         { "zh", "Etc/GMT+3", "2004-07-15T00:00:00Z", "vvvv", "GMT-0300", "-3:00" },
 
         // JB#5150
         { "zh", "Asia/Calcutta", "2004-01-15T00:00:00Z", "Z", "+0530", "+5:30" },
         { "zh", "Asia/Calcutta", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+0530", "+5:30" },
-        { "zh", "Asia/Calcutta", "2004-01-15T00:00:00Z", "z", "GMT+0530", "+5:30" },
+        { "zh", "Asia/Calcutta", "2004-01-15T00:00:00Z", "z", "GMT+530", "+5:30" },
         { "zh", "Asia/Calcutta", "2004-01-15T00:00:00Z", "zzzz", "\\u5370\\u5ea6\\u65f6\\u95f4", "+5:30" },
         { "zh", "Asia/Calcutta", "2004-07-15T00:00:00Z", "Z", "+0530", "+5:30" },
         { "zh", "Asia/Calcutta", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+0530", "+5:30" },
-        { "zh", "Asia/Calcutta", "2004-07-15T00:00:00Z", "z", "GMT+0530", "+05:30" },
+        { "zh", "Asia/Calcutta", "2004-07-15T00:00:00Z", "z", "GMT+530", "+05:30" },
         { "zh", "Asia/Calcutta", "2004-07-15T00:00:00Z", "zzzz", "\\u5370\\u5ea6\\u65f6\\u95f4", "+5:30" },
         { "zh", "Asia/Calcutta", "2004-07-15T00:00:00Z", "v", "\\u5370\\u5ea6\\u65f6\\u95f4", "Asia/Calcutta" },
         { "zh", "Asia/Calcutta", "2004-07-15T00:00:00Z", "vvvv", "\\u5370\\u5ea6\\u65f6\\u95f4", "Asia/Calcutta" },
@@ -2796,66 +2785,66 @@ void DateFormatTest::TestTimeZoneDisplayName()
 
         { "hi", "America/Los_Angeles", "2004-01-15T00:00:00Z", "Z", "-0800", "-8:00" },
         { "hi", "America/Los_Angeles", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-08:00", "-8:00" },
-        { "hi", "America/Los_Angeles", "2004-01-15T00:00:00Z", "z", "GMT-08:00", "-8:00" },
+        { "hi", "America/Los_Angeles", "2004-01-15T00:00:00Z", "z", "GMT-8", "-8:00" },
         { "hi", "America/Los_Angeles", "2004-01-15T00:00:00Z", "zzzz", "\\u092a\\u094d\\u0930\\u0936\\u093e\\u0902\\u0924\\u0020\\u092e\\u093e\\u0928\\u0915\\u0020\\u0938\\u092e\\u092f", "-8:00" },
         { "hi", "America/Los_Angeles", "2004-07-15T00:00:00Z", "Z", "-0700", "-7:00" },
         { "hi", "America/Los_Angeles", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-07:00", "-7:00" },
-        { "hi", "America/Los_Angeles", "2004-07-15T00:00:00Z", "z", "GMT-07:00", "-7:00" },
+        { "hi", "America/Los_Angeles", "2004-07-15T00:00:00Z", "z", "GMT-7", "-7:00" },
         { "hi", "America/Los_Angeles", "2004-07-15T00:00:00Z", "zzzz", "\\u092A\\u094D\\u0930\\u0936\\u093E\\u0902\\u0924 \\u0926\\u093F\\u0935\\u093E\\u0935\\u0932\\u094B\\u0915 \\u0938\\u092E\\u092F", "-7:00" },
         { "hi", "America/Los_Angeles", "2004-07-15T00:00:00Z", "v", "\\u0932\\u094B\\u0938 \\u090F\\u0902\\u091C\\u093F\\u0932\\u0947\\u0938 \\u0938\\u092E\\u092F", "America/Los_Angeles" },
         { "hi", "America/Los_Angeles", "2004-07-15T00:00:00Z", "vvvv", "\\u092A\\u094D\\u0930\\u0936\\u093E\\u0902\\u0924 \\u0938\\u092E\\u092F", "America/Los_Angeles" },
 
         { "hi", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
         { "hi", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
-        { "hi", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-03:00", "-3:00" },
+        { "hi", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
         { "hi", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "\\u0905\\u0930\\u094D\\u091C\\u0947\\u0902\\u091F\\u0940\\u0928\\u093E \\u092E\\u093E\\u0928\\u0915 \\u0938\\u092E\\u092F", "-3:00" },
         { "hi", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
         { "hi", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
-        { "hi", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-03:00", "-3:00" },
+        { "hi", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
         { "hi", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "\\u0905\\u0930\\u094D\\u091C\\u0947\\u0902\\u091F\\u0940\\u0928\\u093E \\u092E\\u093E\\u0928\\u0915 \\u0938\\u092E\\u092F", "-3:00" },
         { "hi", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "\\u092C\\u094D\\u092F\\u0942\\u0928\\u0938 \\u0906\\u092F\\u0930\\u0938 \\u0938\\u092E\\u092F", "America/Buenos_Aires" },
         { "hi", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "\\u0905\\u0930\\u094D\\u091C\\u0947\\u0902\\u091F\\u0940\\u0928\\u093E \\u092E\\u093E\\u0928\\u0915 \\u0938\\u092E\\u092F", "America/Buenos_Aires" },
 
         { "hi", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
         { "hi", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
-        { "hi", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-03:00", "-3:00" },
+        { "hi", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
         { "hi", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "\\u0905\\u0930\\u094D\\u091C\\u0947\\u0902\\u091F\\u0940\\u0928\\u093E \\u092E\\u093E\\u0928\\u0915 \\u0938\\u092E\\u092F", "-3:00" },
         { "hi", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
         { "hi", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
-        { "hi", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-03:00", "-3:00" },
+        { "hi", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
         { "hi", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "\\u0905\\u0930\\u094D\\u091C\\u0947\\u0902\\u091F\\u0940\\u0928\\u093E \\u092E\\u093E\\u0928\\u0915 \\u0938\\u092E\\u092F", "-3:00" },
         { "hi", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "\\u092C\\u094D\\u092F\\u0942\\u0928\\u0938 \\u0906\\u092F\\u0930\\u0938 \\u0938\\u092E\\u092F", "America/Buenos_Aires" },
         { "hi", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "\\u0905\\u0930\\u094D\\u091C\\u0947\\u0902\\u091F\\u0940\\u0928\\u093E \\u092E\\u093E\\u0928\\u0915 \\u0938\\u092E\\u092F", "America/Buenos_Aires" },
 
         { "hi", "America/Havana", "2004-01-15T00:00:00Z", "Z", "-0500", "-5:00" },
         { "hi", "America/Havana", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-05:00", "-5:00" },
-        { "hi", "America/Havana", "2004-01-15T00:00:00Z", "z", "GMT-05:00", "-5:00" },
+        { "hi", "America/Havana", "2004-01-15T00:00:00Z", "z", "GMT-5", "-5:00" },
         { "hi", "America/Havana", "2004-01-15T00:00:00Z", "zzzz", "\\u0915\\u094d\\u092f\\u0942\\u092c\\u093e \\u0915\\u093e \\u092e\\u093e\\u0928\\u0915 \\u0938\\u092e\\u092f", "-5:00" },
         { "hi", "America/Havana", "2004-07-15T00:00:00Z", "Z", "-0400", "-4:00" },
         { "hi", "America/Havana", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-04:00", "-4:00" },
-        { "hi", "America/Havana", "2004-07-15T00:00:00Z", "z", "GMT-04:00", "-4:00" },
+        { "hi", "America/Havana", "2004-07-15T00:00:00Z", "z", "GMT-4", "-4:00" },
         { "hi", "America/Havana", "2004-07-15T00:00:00Z", "zzzz", "\\u0915\\u094d\\u092f\\u0942\\u092c\\u093e \\u0915\\u093e \\u0921\\u0947\\u0932\\u093e\\u0907\\u091f \\u091f\\u093e\\u0907\\u092e", "-4:00" },
         { "hi", "America/Havana", "2004-07-15T00:00:00Z", "v", "\\u0915\\u094d\\u092f\\u0942\\u092c\\u093e \\u0938\\u092E\\u092F", "America/Havana" },
         { "hi", "America/Havana", "2004-07-15T00:00:00Z", "vvvv", "\\u0915\\u094d\\u092f\\u0942\\u092c\\u093e \\u0915\\u093e \\u0938\\u092E\\u092F", "America/Havana" },
 
         { "hi", "Australia/ACT", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
         { "hi", "Australia/ACT", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
-        { "hi", "Australia/ACT", "2004-01-15T00:00:00Z", "z", "GMT+11:00", "+11:00" },
+        { "hi", "Australia/ACT", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
         { "hi", "Australia/ACT", "2004-01-15T00:00:00Z", "zzzz", "\\u0911\\u0938\\u094D\\u200D\\u091F\\u094D\\u0930\\u0947\\u0932\\u093F\\u092F\\u093E\\u0908 \\u092A\\u0942\\u0930\\u094D\\u0935\\u0940 \\u0926\\u093F\\u0935\\u093E\\u0935\\u0932\\u094B\\u0915 \\u0938\\u092E\\u092F", "+11:00" },
         { "hi", "Australia/ACT", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
         { "hi", "Australia/ACT", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
-        { "hi", "Australia/ACT", "2004-07-15T00:00:00Z", "z", "GMT+10:00", "+10:00" },
+        { "hi", "Australia/ACT", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
         { "hi", "Australia/ACT", "2004-07-15T00:00:00Z", "zzzz", "\\u0911\\u0938\\u094D\\u200D\\u091F\\u094D\\u0930\\u0947\\u0932\\u093F\\u092F\\u093E\\u0908 \\u092A\\u0942\\u0930\\u094D\\u0935\\u0940 \\u092E\\u093E\\u0928\\u0915 \\u0938\\u092E\\u092F", "+10:00" },
         { "hi", "Australia/ACT", "2004-07-15T00:00:00Z", "v", "\\u0938\\u093F\\u0921\\u0928\\u0940 \\u0938\\u092E\\u092F", "Australia/Sydney" },
         { "hi", "Australia/ACT", "2004-07-15T00:00:00Z", "vvvv", "\\u092A\\u0942\\u0930\\u094D\\u0935\\u0940 \\u0911\\u0938\\u094D\\u091F\\u094D\\u0930\\u0947\\u0932\\u093F\\u092F\\u093E\\u0908 \\u0938\\u092E\\u092F", "Australia/Sydney" },
 
         { "hi", "Australia/Sydney", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
         { "hi", "Australia/Sydney", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
-        { "hi", "Australia/Sydney", "2004-01-15T00:00:00Z", "z", "GMT+11:00", "+11:00" },
+        { "hi", "Australia/Sydney", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
         { "hi", "Australia/Sydney", "2004-01-15T00:00:00Z", "zzzz", "\\u0911\\u0938\\u094D\\u200D\\u091F\\u094D\\u0930\\u0947\\u0932\\u093F\\u092F\\u093E\\u0908 \\u092A\\u0942\\u0930\\u094D\\u0935\\u0940 \\u0926\\u093F\\u0935\\u093E\\u0935\\u0932\\u094B\\u0915 \\u0938\\u092E\\u092F", "+11:00" },
         { "hi", "Australia/Sydney", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
         { "hi", "Australia/Sydney", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
-        { "hi", "Australia/Sydney", "2004-07-15T00:00:00Z", "z", "GMT+10:00", "+10:00" },
+        { "hi", "Australia/Sydney", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
         { "hi", "Australia/Sydney", "2004-07-15T00:00:00Z", "zzzz", "\\u0911\\u0938\\u094D\\u200D\\u091F\\u094D\\u0930\\u0947\\u0932\\u093F\\u092F\\u093E\\u0908 \\u092A\\u0942\\u0930\\u094D\\u0935\\u0940 \\u092E\\u093E\\u0928\\u0915 \\u0938\\u092E\\u092F", "+10:00" },
         { "hi", "Australia/Sydney", "2004-07-15T00:00:00Z", "v", "\\u0938\\u093F\\u0921\\u0928\\u0940 \\u0938\\u092E\\u092F", "Australia/Sydney" },
         { "hi", "Australia/Sydney", "2004-07-15T00:00:00Z", "vvvv", "\\u092A\\u0942\\u0930\\u094D\\u0935\\u0940 \\u0911\\u0938\\u094D\\u091F\\u094D\\u0930\\u0947\\u0932\\u093F\\u092F\\u093E\\u0908 \\u0938\\u092E\\u092F", "Australia/Sydney" },
@@ -2866,20 +2855,20 @@ void DateFormatTest::TestTimeZoneDisplayName()
         { "hi", "Europe/London", "2004-01-15T00:00:00Z", "zzzz", "\\u0917\\u094d\\u0930\\u0940\\u0928\\u0935\\u093f\\u091a \\u092e\\u0940\\u0928 \\u091f\\u093e\\u0907\\u092e", "+0:00" },
         { "hi", "Europe/London", "2004-07-15T00:00:00Z", "Z", "+0100", "+1:00" },
         { "hi", "Europe/London", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+01:00", "+1:00" },
-        { "hi", "Europe/London", "2004-07-15T00:00:00Z", "z", "GMT+01:00", "+1:00" },
+        { "hi", "Europe/London", "2004-07-15T00:00:00Z", "z", "GMT+1", "+1:00" },
         { "hi", "Europe/London", "2004-07-15T00:00:00Z", "zzzz", "GMT+01:00", "+1:00" },
         { "hi", "Europe/London", "2004-07-15T00:00:00Z", "v", "\\u092C\\u094D\\u0930\\u093F\\u091F\\u0947\\u0928 \\u0938\\u092E\\u092F", "Europe/London" },
         { "hi", "Europe/London", "2004-07-15T00:00:00Z", "vvvv", "\\u092C\\u094D\\u0930\\u093F\\u091F\\u0947\\u0928 \\u0938\\u092E\\u092F", "Europe/London" },
 
         { "hi", "Etc/GMT+3", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
         { "hi", "Etc/GMT+3", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
-        { "hi", "Etc/GMT+3", "2004-01-15T00:00:00Z", "z", "GMT-03:00", "-3:00" },
+        { "hi", "Etc/GMT+3", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
         { "hi", "Etc/GMT+3", "2004-01-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
         { "hi", "Etc/GMT+3", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
         { "hi", "Etc/GMT+3", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
-        { "hi", "Etc/GMT+3", "2004-07-15T00:00:00Z", "z", "GMT-03:00", "-3:00" },
+        { "hi", "Etc/GMT+3", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
         { "hi", "Etc/GMT+3", "2004-07-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
-        { "hi", "Etc/GMT+3", "2004-07-15T00:00:00Z", "v", "GMT-03:00", "-3:00" },
+        { "hi", "Etc/GMT+3", "2004-07-15T00:00:00Z", "v", "GMT-3", "-3:00" },
         { "hi", "Etc/GMT+3", "2004-07-15T00:00:00Z", "vvvv", "GMT-03:00", "-3:00" },
 
         { "hi", "Asia/Calcutta", "2004-01-15T00:00:00Z", "Z", "+0530", "+5:30" },
@@ -2897,13 +2886,11 @@ void DateFormatTest::TestTimeZoneDisplayName()
 
         { "bg", "America/Los_Angeles", "2004-01-15T00:00:00Z", "Z", "-0800", "-8:00" },
         { "bg", "America/Los_Angeles", "2004-01-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447-0800", "-8:00" },
-        { "bg", "America/Los_Angeles", "2004-01-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447-0800", "America/Los_Angeles" },
-        { "bg", "America/Los_Angeles", "2004-01-15T00:00:00Z", "V", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447-0800", "America/Los_Angeles" },
+        { "bg", "America/Los_Angeles", "2004-01-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447-8", "America/Los_Angeles" },
         { "bg", "America/Los_Angeles", "2004-01-15T00:00:00Z", "zzzz", "\\u0422\\u0438\\u0445\\u043E\\u043E\\u043A\\u0435\\u0430\\u043D\\u0441\\u043A\\u0430 \\u0447\\u0430\\u0441\\u043E\\u0432\\u0430 \\u0437\\u043E\\u043D\\u0430", "America/Los_Angeles" },
         { "bg", "America/Los_Angeles", "2004-07-15T00:00:00Z", "Z", "-0700", "-7:00" },
         { "bg", "America/Los_Angeles", "2004-07-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447-0700", "-7:00" },
-        { "bg", "America/Los_Angeles", "2004-07-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447-0700", "America/Los_Angeles" },
-        { "bg", "America/Los_Angeles", "2004-07-15T00:00:00Z", "V", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447-0700", "America/Los_Angeles" },
+        { "bg", "America/Los_Angeles", "2004-07-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447-7", "America/Los_Angeles" },
         { "bg", "America/Los_Angeles", "2004-07-15T00:00:00Z", "zzzz", "\\u0422\\u0438\\u0445\\u043E\\u043E\\u043A\\u0435\\u0430\\u043D\\u0441\\u043A\\u0430 \\u043B\\u044F\\u0442\\u043D\\u0430 \\u0447\\u0430\\u0441\\u043E\\u0432\\u0430 \\u0437\\u043E\\u043D\\u0430", "America/Los_Angeles" },
     // icu bg.txt has exemplar city for this time zone
         { "bg", "America/Los_Angeles", "2004-07-15T00:00:00Z", "v", "\\u041B\\u043E\\u0441 \\u0410\\u043D\\u0436\\u0435\\u043B\\u0438\\u0441 \\u0432\\u0440\\u0435\\u043C\\u0435", "America/Los_Angeles" },
@@ -2912,22 +2899,22 @@ void DateFormatTest::TestTimeZoneDisplayName()
 
         { "bg", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
         { "bg", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447-0300", "-3:00" },
-        { "bg", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447-0300", "-3:00" },
+        { "bg", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447-3", "-3:00" },
         { "bg", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "\\u0410\\u0440\\u0436\\u0435\\u043D\\u0442\\u0438\\u043D\\u0430 \\u2013 \\u0441\\u0442\\u0430\\u043d\\u0434\\u0430\\u0440\\u0442\\u043d\\u043e \\u0432\\u0440\\u0435\\u043c\\u0435", "-3:00" },
         { "bg", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
         { "bg", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447-0300", "-3:00" },
-        { "bg", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447-0300", "-3:00" },
+        { "bg", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447-3", "-3:00" },
         { "bg", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "\\u0410\\u0440\\u0436\\u0435\\u043D\\u0442\\u0438\\u043D\\u0430 \\u2013 \\u0441\\u0442\\u0430\\u043d\\u0434\\u0430\\u0440\\u0442\\u043d\\u043e \\u0432\\u0440\\u0435\\u043c\\u0435", "-3:00" },
         { "bg", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "\\u0411\\u0443\\u0435\\u043D\\u043E\\u0441 \\u0410\\u0439\\u0440\\u0435\\u0441 \\u0432\\u0440\\u0435\\u043C\\u0435", "America/Buenos_Aires" },
         { "bg", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "\\u0410\\u0440\\u0436\\u0435\\u043D\\u0442\\u0438\\u043D\\u0430 \\u2013 \\u0441\\u0442\\u0430\\u043d\\u0434\\u0430\\u0440\\u0442\\u043d\\u043e \\u0432\\u0440\\u0435\\u043c\\u0435", "America/Buenos_Aires" },
 
         { "bg", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
         { "bg", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447-0300", "-3:00" },
-        { "bg", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447-0300", "-3:00" },
+        { "bg", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447-3", "-3:00" },
         { "bg", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "\\u0410\\u0440\\u0436\\u0435\\u043D\\u0442\\u0438\\u043D\\u0430 \\u2013 \\u0441\\u0442\\u0430\\u043d\\u0434\\u0430\\u0440\\u0442\\u043d\\u043e \\u0432\\u0440\\u0435\\u043c\\u0435", "-3:00" },
         { "bg", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
         { "bg", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447-0300", "-3:00" },
-        { "bg", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447-0300", "-3:00" },
+        { "bg", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447-3", "-3:00" },
         { "bg", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "\\u0410\\u0440\\u0436\\u0435\\u043D\\u0442\\u0438\\u043D\\u0430 \\u2013 \\u0441\\u0442\\u0430\\u043d\\u0434\\u0430\\u0440\\u0442\\u043d\\u043e \\u0432\\u0440\\u0435\\u043c\\u0435", "-3:00" },
     // icu bg.txt does not have info for this time zone
         { "bg", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "\\u0411\\u0443\\u0435\\u043D\\u043E\\u0441 \\u0410\\u0439\\u0440\\u0435\\u0441 \\u0432\\u0440\\u0435\\u043C\\u0435", "America/Buenos_Aires" },
@@ -2935,33 +2922,33 @@ void DateFormatTest::TestTimeZoneDisplayName()
 
         { "bg", "America/Havana", "2004-01-15T00:00:00Z", "Z", "-0500", "-5:00" },
         { "bg", "America/Havana", "2004-01-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447-0500", "-5:00" },
-        { "bg", "America/Havana", "2004-01-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447-0500", "-5:00" },
+        { "bg", "America/Havana", "2004-01-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447-5", "-5:00" },
         { "bg", "America/Havana", "2004-01-15T00:00:00Z", "zzzz", "\\u041a\\u0443\\u0431\\u0438\\u043d\\u0441\\u043a\\u043e \\u0441\\u0442\\u0430\\u043d\\u0434\\u0430\\u0440\\u0442\\u043d\\u043e \\u0432\\u0440\\u0435\\u043c\\u0435", "-5:00" },
         { "bg", "America/Havana", "2004-07-15T00:00:00Z", "Z", "-0400", "-4:00" },
         { "bg", "America/Havana", "2004-07-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447-0400", "-4:00" },
-        { "bg", "America/Havana", "2004-07-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447-0400", "-4:00" },
+        { "bg", "America/Havana", "2004-07-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447-4", "-4:00" },
         { "bg", "America/Havana", "2004-07-15T00:00:00Z", "zzzz", "\\u041a\\u0443\\u0431\\u0438\\u043d\\u0441\\u043a\\u043e \\u043b\\u044f\\u0442\\u043d\\u043e \\u0447\\u0430\\u0441\\u043e\\u0432\\u043e \\u0432\\u0440\\u0435\\u043c\\u0435", "-4:00" },
         { "bg", "America/Havana", "2004-07-15T00:00:00Z", "v", "\\u041a\\u0443\\u0431\\u0430 \\u0432\\u0440\\u0435\\u043C\\u0435", "America/Havana" },
         { "bg", "America/Havana", "2004-07-15T00:00:00Z", "vvvv", "\\u041a\\u0443\\u0431\\u0438\\u043d\\u0441\\u043a\\u043e \\u0432\\u0440\\u0435\\u043C\\u0435", "America/Havana" },
 
         { "bg", "Australia/ACT", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
         { "bg", "Australia/ACT", "2004-01-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447+1100", "+11:00" },
-        { "bg", "Australia/ACT", "2004-01-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447+1100", "+11:00" },
+        { "bg", "Australia/ACT", "2004-01-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447+11", "+11:00" },
         { "bg", "Australia/ACT", "2004-01-15T00:00:00Z", "zzzz", "\\u0410\\u0432\\u0441\\u0442\\u0440\\u0430\\u043B\\u0438\\u044F \\u2013 \\u0438\\u0437\\u0442\\u043E\\u0447\\u043D\\u043E \\u043B\\u044F\\u0442\\u043D\\u043E \\u0447\\u0430\\u0441\\u043E\\u0432\\u043E \\u0432\\u0440\\u0435\\u043C\\u0435", "+11:00" },
         { "bg", "Australia/ACT", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
         { "bg", "Australia/ACT", "2004-07-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447+1000", "+10:00" },
-        { "bg", "Australia/ACT", "2004-07-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447+1000", "+10:00" },
+        { "bg", "Australia/ACT", "2004-07-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447+10", "+10:00" },
         { "bg", "Australia/ACT", "2004-07-15T00:00:00Z", "zzzz", "\\u0410\\u0432\\u0441\\u0442\\u0440\\u0430\\u043B\\u0438\\u044F \\u2013 \\u0438\\u0437\\u0442\\u043E\\u0447\\u043D\\u043E \\u0441\\u0442\\u0430\\u043D\\u0434\\u0430\\u0440\\u0442\\u043D\\u043E \\u0432\\u0440\\u0435\\u043C\\u0435", "+10:00" },
         { "bg", "Australia/ACT", "2004-07-15T00:00:00Z", "v", "\\u0421\\u0438\\u0434\\u043D\\u0438 \\u0432\\u0440\\u0435\\u043C\\u0435", "Australia/Sydney" },
         { "bg", "Australia/ACT", "2004-07-15T00:00:00Z", "vvvv", "\\u0410\\u0432\\u0441\\u0442\\u0440\\u0430\\u043B\\u0438\\u044F \\u2013 \\u0438\\u0437\\u0442\\u043E\\u0447\\u043D\\u043E \\u0432\\u0440\\u0435\\u043C\\u0435", "Australia/Sydney" },
 
         { "bg", "Australia/Sydney", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
         { "bg", "Australia/Sydney", "2004-01-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447+1100", "+11:00" },
-        { "bg", "Australia/Sydney", "2004-01-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447+1100", "+11:00" },
+        { "bg", "Australia/Sydney", "2004-01-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447+11", "+11:00" },
         { "bg", "Australia/Sydney", "2004-01-15T00:00:00Z", "zzzz", "\\u0410\\u0432\\u0441\\u0442\\u0440\\u0430\\u043B\\u0438\\u044F \\u2013 \\u0438\\u0437\\u0442\\u043E\\u0447\\u043D\\u043E \\u043B\\u044F\\u0442\\u043D\\u043E \\u0447\\u0430\\u0441\\u043E\\u0432\\u043E \\u0432\\u0440\\u0435\\u043C\\u0435", "+11:00" },
         { "bg", "Australia/Sydney", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
         { "bg", "Australia/Sydney", "2004-07-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447+1000", "+10:00" },
-        { "bg", "Australia/Sydney", "2004-07-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447+1000", "+10:00" },
+        { "bg", "Australia/Sydney", "2004-07-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447+10", "+10:00" },
         { "bg", "Australia/Sydney", "2004-07-15T00:00:00Z", "zzzz", "\\u0410\\u0432\\u0441\\u0442\\u0440\\u0430\\u043B\\u0438\\u044F \\u2013 \\u0438\\u0437\\u0442\\u043E\\u0447\\u043D\\u043E \\u0441\\u0442\\u0430\\u043D\\u0434\\u0430\\u0440\\u0442\\u043D\\u043E \\u0432\\u0440\\u0435\\u043C\\u0435", "+10:00" },
         { "bg", "Australia/Sydney", "2004-07-15T00:00:00Z", "v", "\\u0421\\u0438\\u0434\\u043D\\u0438 \\u0432\\u0440\\u0435\\u043C\\u0435", "Australia/Sydney" },
         { "bg", "Australia/Sydney", "2004-07-15T00:00:00Z", "vvvv", "\\u0410\\u0432\\u0441\\u0442\\u0440\\u0430\\u043B\\u0438\\u044F \\u2013 \\u0438\\u0437\\u0442\\u043E\\u0447\\u043D\\u043E \\u0432\\u0440\\u0435\\u043C\\u0435", "Australia/Sydney" },
@@ -2972,30 +2959,30 @@ void DateFormatTest::TestTimeZoneDisplayName()
         { "bg", "Europe/London", "2004-01-15T00:00:00Z", "zzzz", "\\u0427\\u0430\\u0441\\u043E\\u0432\\u0430 \\u0437\\u043E\\u043D\\u0430 \\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447", "+0:00" },
         { "bg", "Europe/London", "2004-07-15T00:00:00Z", "Z", "+0100", "+1:00" },
         { "bg", "Europe/London", "2004-07-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447+0100", "+1:00" },
-        { "bg", "Europe/London", "2004-07-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447+0100", "+1:00" },
+        { "bg", "Europe/London", "2004-07-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447+1", "+1:00" },
         { "bg", "Europe/London", "2004-07-15T00:00:00Z", "zzzz", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447+0100", "+1:00" },
         { "bg", "Europe/London", "2004-07-15T00:00:00Z", "v", "\\u041e\\u0431\\u0435\\u0434\\u0438\\u043d\\u0435\\u043d\\u043e \\u043a\\u0440\\u0430\\u043b\\u0441\\u0442\\u0432\\u043e \\u0432\\u0440\\u0435\\u043C\\u0435", "Europe/London" },
         { "bg", "Europe/London", "2004-07-15T00:00:00Z", "vvvv", "\\u041e\\u0431\\u0435\\u0434\\u0438\\u043d\\u0435\\u043d\\u043e \\u043a\\u0440\\u0430\\u043b\\u0441\\u0442\\u0432\\u043e \\u0432\\u0440\\u0435\\u043C\\u0435", "Europe/London" },
 
         { "bg", "Etc/GMT+3", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
         { "bg", "Etc/GMT+3", "2004-01-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447-0300", "-3:00" },
-        { "bg", "Etc/GMT+3", "2004-01-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447-0300", "-3:00" },
+        { "bg", "Etc/GMT+3", "2004-01-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447-3", "-3:00" },
         { "bg", "Etc/GMT+3", "2004-01-15T00:00:00Z", "zzzz", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447-0300", "-3:00" },
         { "bg", "Etc/GMT+3", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
         { "bg", "Etc/GMT+3", "2004-07-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447-0300", "-3:00" },
-        { "bg", "Etc/GMT+3", "2004-07-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447-0300", "-3:00" },
+        { "bg", "Etc/GMT+3", "2004-07-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447-3", "-3:00" },
         { "bg", "Etc/GMT+3", "2004-07-15T00:00:00Z", "zzzz", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447-0300", "-3:00" },
-        { "bg", "Etc/GMT+3", "2004-07-15T00:00:00Z", "v", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447-0300", "-3:00" },
+        { "bg", "Etc/GMT+3", "2004-07-15T00:00:00Z", "v", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447-3", "-3:00" },
         { "bg", "Etc/GMT+3", "2004-07-15T00:00:00Z", "vvvv", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447-0300", "-3:00" },
 
         // JB#5150
         { "bg", "Asia/Calcutta", "2004-01-15T00:00:00Z", "Z", "+0530", "+5:30" },
         { "bg", "Asia/Calcutta", "2004-01-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447+0530", "+5:30" },
-        { "bg", "Asia/Calcutta", "2004-01-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447+0530", "+5:30" },
+        { "bg", "Asia/Calcutta", "2004-01-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447+530", "+5:30" },
         { "bg", "Asia/Calcutta", "2004-01-15T00:00:00Z", "zzzz", "\\u0418\\u043d\\u0434\\u0438\\u0439\\u0441\\u043a\\u043e \\u0441\\u0442\\u0430\\u043d\\u0434\\u0430\\u0440\\u0442\\u043d\\u043e \\u0432\\u0440\\u0435\\u043c\\u0435", "+5:30" },
         { "bg", "Asia/Calcutta", "2004-07-15T00:00:00Z", "Z", "+0530", "+5:30" },
         { "bg", "Asia/Calcutta", "2004-07-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447+0530", "+5:30" },
-        { "bg", "Asia/Calcutta", "2004-07-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447+0530", "+05:30" },
+        { "bg", "Asia/Calcutta", "2004-07-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447+530", "+05:30" },
         { "bg", "Asia/Calcutta", "2004-07-15T00:00:00Z", "zzzz", "\\u0418\\u043d\\u0434\\u0438\\u0439\\u0441\\u043a\\u043e \\u0441\\u0442\\u0430\\u043d\\u0434\\u0430\\u0440\\u0442\\u043d\\u043e \\u0432\\u0440\\u0435\\u043c\\u0435", "+5:30" },
         { "bg", "Asia/Calcutta", "2004-07-15T00:00:00Z", "v", "\\u0418\\u043D\\u0434\\u0438\\u044F \\u0432\\u0440\\u0435\\u043C\\u0435", "Asia/Calcutta" },
         { "bg", "Asia/Calcutta", "2004-07-15T00:00:00Z", "vvvv", "\\u0418\\u043d\\u0434\\u0438\\u0439\\u0441\\u043a\\u043e \\u0441\\u0442\\u0430\\u043d\\u0434\\u0430\\u0440\\u0442\\u043d\\u043e \\u0432\\u0440\\u0435\\u043c\\u0435", "Asia/Calcutta" },
@@ -3003,13 +2990,11 @@ void DateFormatTest::TestTimeZoneDisplayName()
 
         { "ja", "America/Los_Angeles", "2004-01-15T00:00:00Z", "Z", "-0800", "-8:00" },
         { "ja", "America/Los_Angeles", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-08:00", "-8:00" },
-        { "ja", "America/Los_Angeles", "2004-01-15T00:00:00Z", "z", "GMT-08:00", "America/Los_Angeles" },
-        { "ja", "America/Los_Angeles", "2004-01-15T00:00:00Z", "V", "GMT-08:00", "America/Los_Angeles" },
+        { "ja", "America/Los_Angeles", "2004-01-15T00:00:00Z", "z", "GMT-8", "America/Los_Angeles" },
         { "ja", "America/Los_Angeles", "2004-01-15T00:00:00Z", "zzzz", "\\u30a2\\u30e1\\u30ea\\u30ab\\u592a\\u5e73\\u6d0b\\u6a19\\u6e96\\u6642", "America/Los_Angeles" },
         { "ja", "America/Los_Angeles", "2004-07-15T00:00:00Z", "Z", "-0700", "-700" },
         { "ja", "America/Los_Angeles", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-07:00", "-7:00" },
-        { "ja", "America/Los_Angeles", "2004-07-15T00:00:00Z", "z", "GMT-07:00", "America/Los_Angeles" },
-        { "ja", "America/Los_Angeles", "2004-07-15T00:00:00Z", "V", "GMT-07:00", "America/Los_Angeles" },
+        { "ja", "America/Los_Angeles", "2004-07-15T00:00:00Z", "z", "GMT-7", "America/Los_Angeles" },
         { "ja", "America/Los_Angeles", "2004-07-15T00:00:00Z", "zzzz", "\\u30a2\\u30e1\\u30ea\\u30ab\\u592a\\u5e73\\u6d0b\\u590f\\u6642\\u9593", "America/Los_Angeles" },
     // icu ja.txt has exemplar city for this time zone
         { "ja", "America/Los_Angeles", "2004-07-15T00:00:00Z", "v", "\\u30ED\\u30B5\\u30F3\\u30BC\\u30EB\\u30B9\\u6642\\u9593", "America/Los_Angeles" },
@@ -3018,11 +3003,11 @@ void DateFormatTest::TestTimeZoneDisplayName()
 
         { "ja", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
         { "ja", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
-        { "ja", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-03:00", "-3:00" },
+        { "ja", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
         { "ja", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "\\u30A2\\u30EB\\u30BC\\u30F3\\u30C1\\u30F3\\u6A19\\u6E96\\u6642", "-3:00" },
         { "ja", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
         { "ja", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
-        { "ja", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-03:00", "-3:00" },
+        { "ja", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
         { "ja", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "\\u30A2\\u30EB\\u30BC\\u30F3\\u30C1\\u30F3\\u6A19\\u6E96\\u6642", "-3:00" },
     // icu ja.txt does not have info for this time zone
         { "ja", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "\\u30D6\\u30A8\\u30CE\\u30B9\\u30A2\\u30A4\\u30EC\\u30B9\\u6642\\u9593", "America/Buenos_Aires" },
@@ -3030,33 +3015,33 @@ void DateFormatTest::TestTimeZoneDisplayName()
 
         { "ja", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
         { "ja", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
-        { "ja", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-03:00", "-3:00" },
+        { "ja", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
         { "ja", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "\\u30A2\\u30EB\\u30BC\\u30F3\\u30C1\\u30F3\\u6A19\\u6E96\\u6642", "-3:00" },
         { "ja", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
         { "ja", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
-        { "ja", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-03:00", "-3:00" },
+        { "ja", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
         { "ja", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "\\u30A2\\u30EB\\u30BC\\u30F3\\u30C1\\u30F3\\u6A19\\u6E96\\u6642", "-3:00" },
         { "ja", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "\\u30D6\\u30A8\\u30CE\\u30B9\\u30A2\\u30A4\\u30EC\\u30B9\\u6642\\u9593", "America/Buenos_Aires" },
         { "ja", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "\\u30A2\\u30EB\\u30BC\\u30F3\\u30C1\\u30F3\\u6A19\\u6E96\\u6642", "America/Buenos_Aires" },
 
         { "ja", "America/Havana", "2004-01-15T00:00:00Z", "Z", "-0500", "-5:00" },
         { "ja", "America/Havana", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-05:00", "-5:00" },
-        { "ja", "America/Havana", "2004-01-15T00:00:00Z", "z", "GMT-05:00", "-5:00" },
+        { "ja", "America/Havana", "2004-01-15T00:00:00Z", "z", "GMT-5", "-5:00" },
         { "ja", "America/Havana", "2004-01-15T00:00:00Z", "zzzz", "\\u30AD\\u30E5\\u30FC\\u30D0\\u6A19\\u6E96\\u6642", "-5:00" },
         { "ja", "America/Havana", "2004-07-15T00:00:00Z", "Z", "-0400", "-4:00" },
         { "ja", "America/Havana", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-04:00", "-4:00" },
-        { "ja", "America/Havana", "2004-07-15T00:00:00Z", "z", "GMT-04:00", "-4:00" },
+        { "ja", "America/Havana", "2004-07-15T00:00:00Z", "z", "GMT-4", "-4:00" },
         { "ja", "America/Havana", "2004-07-15T00:00:00Z", "zzzz", "\\u30AD\\u30E5\\u30FC\\u30D0\\u590F\\u6642\\u9593", "-4:00" },
         { "ja", "America/Havana", "2004-07-15T00:00:00Z", "v", "\\u30ad\\u30e5\\u30fc\\u30d0\\u6642\\u9593", "America/Havana" },
         { "ja", "America/Havana", "2004-07-15T00:00:00Z", "vvvv", "\\u30ad\\u30e5\\u30fc\\u30d0\\u6642\\u9593", "America/Havana" },
 
         { "ja", "Australia/ACT", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
         { "ja", "Australia/ACT", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
-        { "ja", "Australia/ACT", "2004-01-15T00:00:00Z", "z", "GMT+11:00", "+11:00" },
+        { "ja", "Australia/ACT", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
         { "ja", "Australia/ACT", "2004-01-15T00:00:00Z", "zzzz", "\\u30AA\\u30FC\\u30B9\\u30C8\\u30E9\\u30EA\\u30A2\\u6771\\u90E8\\u590F\\u6642\\u9593", "+11:00" },
         { "ja", "Australia/ACT", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
         { "ja", "Australia/ACT", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
-        { "ja", "Australia/ACT", "2004-07-15T00:00:00Z", "z", "GMT+10:00", "+10:00" },
+        { "ja", "Australia/ACT", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
         { "ja", "Australia/ACT", "2004-07-15T00:00:00Z", "zzzz", "\\u30AA\\u30FC\\u30B9\\u30C8\\u30E9\\u30EA\\u30A2\\u6771\\u90E8\\u6A19\\u6E96\\u6642", "+10:00" },
     // icu ja.txt does not have info for this time zone
         { "ja", "Australia/ACT", "2004-07-15T00:00:00Z", "v", "\\u30B7\\u30C9\\u30CB\\u30FC\\u6642\\u9593", "Australia/Sydney" },
@@ -3064,11 +3049,11 @@ void DateFormatTest::TestTimeZoneDisplayName()
 
         { "ja", "Australia/Sydney", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
         { "ja", "Australia/Sydney", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
-        { "ja", "Australia/Sydney", "2004-01-15T00:00:00Z", "z", "GMT+11:00", "+11:00" },
+        { "ja", "Australia/Sydney", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
         { "ja", "Australia/Sydney", "2004-01-15T00:00:00Z", "zzzz", "\\u30AA\\u30FC\\u30B9\\u30C8\\u30E9\\u30EA\\u30A2\\u6771\\u90E8\\u590F\\u6642\\u9593", "+11:00" },
         { "ja", "Australia/Sydney", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
         { "ja", "Australia/Sydney", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
-        { "ja", "Australia/Sydney", "2004-07-15T00:00:00Z", "z", "GMT+10:00", "+10:00" },
+        { "ja", "Australia/Sydney", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
         { "ja", "Australia/Sydney", "2004-07-15T00:00:00Z", "zzzz", "\\u30AA\\u30FC\\u30B9\\u30C8\\u30E9\\u30EA\\u30A2\\u6771\\u90E8\\u6A19\\u6E96\\u6642", "+10:00" },
         { "ja", "Australia/Sydney", "2004-07-15T00:00:00Z", "v", "\\u30B7\\u30C9\\u30CB\\u30FC\\u6642\\u9593", "Australia/Sydney" },
         { "ja", "Australia/Sydney", "2004-07-15T00:00:00Z", "vvvv", "\\u30AA\\u30FC\\u30B9\\u30C8\\u30E9\\u30EA\\u30A2\\u6771\\u90E8\\u6642\\u9593", "Australia/Sydney" },
@@ -3076,12 +3061,10 @@ void DateFormatTest::TestTimeZoneDisplayName()
         { "ja", "Europe/London", "2004-01-15T00:00:00Z", "Z", "+0000", "+0:00" },
         { "ja", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", "GMT", "+0:00" },
         { "ja", "Europe/London", "2004-01-15T00:00:00Z", "z", "GMT", "+0:00" },
-        { "ja", "Europe/London", "2004-01-15T00:00:00Z", "V", "GMT", "+0:00" },
         { "ja", "Europe/London", "2004-01-15T00:00:00Z", "zzzz", "\\u30B0\\u30EA\\u30CB\\u30C3\\u30B8\\u6A19\\u6E96\\u6642", "+0:00" },
         { "ja", "Europe/London", "2004-07-15T00:00:00Z", "Z", "+0100", "+1:00" },
         { "ja", "Europe/London", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+01:00", "+1:00" },
-        { "ja", "Europe/London", "2004-07-15T00:00:00Z", "z", "GMT+01:00", "+1:00" },
-        { "ja", "Europe/London", "2004-07-15T00:00:00Z", "V", "GMT+01:00", "+1:00" },
+        { "ja", "Europe/London", "2004-07-15T00:00:00Z", "z", "GMT+1", "+1:00" },
         { "ja", "Europe/London", "2004-07-15T00:00:00Z", "zzzz", "\\u82f1\\u56fd\\u590f\\u6642\\u9593", "+1:00" },
         { "ja", "Europe/London", "2004-07-15T00:00:00Z", "v", "\\u30a4\\u30ae\\u30ea\\u30b9\\u6642\\u9593", "Europe/London" },
         { "ja", "Europe/London", "2004-07-15T00:00:00Z", "vvvv", "\\u30a4\\u30ae\\u30ea\\u30b9\\u6642\\u9593", "Europe/London" },
@@ -3089,23 +3072,23 @@ void DateFormatTest::TestTimeZoneDisplayName()
 
         { "ja", "Etc/GMT+3", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
         { "ja", "Etc/GMT+3", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
-        { "ja", "Etc/GMT+3", "2004-01-15T00:00:00Z", "z", "GMT-03:00", "-3:00" },
+        { "ja", "Etc/GMT+3", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
         { "ja", "Etc/GMT+3", "2004-01-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
         { "ja", "Etc/GMT+3", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
         { "ja", "Etc/GMT+3", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
-        { "ja", "Etc/GMT+3", "2004-07-15T00:00:00Z", "z", "GMT-03:00", "-3:00" },
+        { "ja", "Etc/GMT+3", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
         { "ja", "Etc/GMT+3", "2004-07-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
-        { "ja", "Etc/GMT+3", "2004-07-15T00:00:00Z", "v", "GMT-03:00", "-3:00" },
+        { "ja", "Etc/GMT+3", "2004-07-15T00:00:00Z", "v", "GMT-3", "-3:00" },
         { "ja", "Etc/GMT+3", "2004-07-15T00:00:00Z", "vvvv", "GMT-03:00", "-3:00" },
 
         // JB#5150
         { "ja", "Asia/Calcutta", "2004-01-15T00:00:00Z", "Z", "+0530", "+5:30" },
         { "ja", "Asia/Calcutta", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
-        { "ja", "Asia/Calcutta", "2004-01-15T00:00:00Z", "z", "GMT+05:30", "+5:30" },
+        { "ja", "Asia/Calcutta", "2004-01-15T00:00:00Z", "z", "GMT+5:30", "+5:30" },
         { "ja", "Asia/Calcutta", "2004-01-15T00:00:00Z", "zzzz", "\\u30A4\\u30F3\\u30C9\\u6642\\u9593", "+5:30" },
         { "ja", "Asia/Calcutta", "2004-07-15T00:00:00Z", "Z", "+0530", "+5:30" },
         { "ja", "Asia/Calcutta", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
-        { "ja", "Asia/Calcutta", "2004-07-15T00:00:00Z", "z", "GMT+05:30", "+05:30" },
+        { "ja", "Asia/Calcutta", "2004-07-15T00:00:00Z", "z", "GMT+5:30", "+05:30" },
         { "ja", "Asia/Calcutta", "2004-07-15T00:00:00Z", "zzzz", "\\u30A4\\u30F3\\u30C9\\u6642\\u9593", "+5:30" },
         { "ja", "Asia/Calcutta", "2004-07-15T00:00:00Z", "v", "\\u30A4\\u30F3\\u30C9\\u6642\\u9593", "Asia/Calcutta" },
         { "ja", "Asia/Calcutta", "2004-07-15T00:00:00Z", "vvvv", "\\u30A4\\u30F3\\u30C9\\u6642\\u9593", "Asia/Calcutta" },
@@ -3114,66 +3097,66 @@ void DateFormatTest::TestTimeZoneDisplayName()
 
         { "ti", "America/Los_Angeles", "2004-01-15T00:00:00Z", "Z", "-0800", "-8:00" },
         { "ti", "America/Los_Angeles", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-08:00", "-8:00" },
-        { "ti", "America/Los_Angeles", "2004-01-15T00:00:00Z", "z", "GMT-08:00", "-8:00" },
+        { "ti", "America/Los_Angeles", "2004-01-15T00:00:00Z", "z", "GMT-8", "-8:00" },
         { "ti", "America/Los_Angeles", "2004-01-15T00:00:00Z", "zzzz", "GMT-08:00", "-8:00" },
         { "ti", "America/Los_Angeles", "2004-07-15T00:00:00Z", "Z", "-0700", "-7:00" },
         { "ti", "America/Los_Angeles", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-07:00", "-7:00" },
-        { "ti", "America/Los_Angeles", "2004-07-15T00:00:00Z", "z", "GMT-07:00", "-7:00" },
+        { "ti", "America/Los_Angeles", "2004-07-15T00:00:00Z", "z", "GMT-7", "-7:00" },
         { "ti", "America/Los_Angeles", "2004-07-15T00:00:00Z", "zzzz", "GMT-07:00", "-7:00" },
         { "ti", "America/Los_Angeles", "2004-07-15T00:00:00Z", "v", "Los Angeles", "America/Los_Angeles" },
         { "ti", "America/Los_Angeles", "2004-07-15T00:00:00Z", "vvvv", "Los Angeles", "America/Los_Angeles" },
 
         { "ti", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
         { "ti", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
-        { "ti", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-03:00", "-3:00" },
+        { "ti", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
         { "ti", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
         { "ti", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
         { "ti", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
-        { "ti", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-03:00", "-3:00" },
+        { "ti", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
         { "ti", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
         { "ti", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "Buenos Aires", "America/Buenos_Aires" },
         { "ti", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "Buenos Aires", "America/Buenos_Aires" },
 
         { "ti", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
         { "ti", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
-        { "ti", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-03:00", "-3:00" },
+        { "ti", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
         { "ti", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
         { "ti", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
         { "ti", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
-        { "ti", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-03:00", "-3:00" },
+        { "ti", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
         { "ti", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
         { "ti", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "Buenos Aires", "America/Buenos_Aires" },
         { "ti", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "Buenos Aires", "America/Buenos_Aires" },
 
         { "ti", "America/Havana", "2004-01-15T00:00:00Z", "Z", "-0500", "-5:00" },
         { "ti", "America/Havana", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-05:00", "-5:00" },
-        { "ti", "America/Havana", "2004-01-15T00:00:00Z", "z", "GMT-05:00", "-5:00" },
+        { "ti", "America/Havana", "2004-01-15T00:00:00Z", "z", "GMT-5", "-5:00" },
         { "ti", "America/Havana", "2004-01-15T00:00:00Z", "zzzz", "GMT-05:00", "-5:00" },
         { "ti", "America/Havana", "2004-07-15T00:00:00Z", "Z", "-0400", "-4:00" },
         { "ti", "America/Havana", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-04:00", "-4:00" },
-        { "ti", "America/Havana", "2004-07-15T00:00:00Z", "z", "GMT-04:00", "-4:00" },
+        { "ti", "America/Havana", "2004-07-15T00:00:00Z", "z", "GMT-4", "-4:00" },
         { "ti", "America/Havana", "2004-07-15T00:00:00Z", "zzzz", "GMT-04:00", "-4:00" },
         { "ti", "America/Havana", "2004-07-15T00:00:00Z", "v", "CU", "America/Havana" },
         { "ti", "America/Havana", "2004-07-15T00:00:00Z", "vvvv", "CU", "America/Havana" },
 
         { "ti", "Australia/ACT", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
         { "ti", "Australia/ACT", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
-        { "ti", "Australia/ACT", "2004-01-15T00:00:00Z", "z", "GMT+11:00", "+11:00" },
+        { "ti", "Australia/ACT", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
         { "ti", "Australia/ACT", "2004-01-15T00:00:00Z", "zzzz", "GMT+11:00", "+11:00" },
         { "ti", "Australia/ACT", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
         { "ti", "Australia/ACT", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
-        { "ti", "Australia/ACT", "2004-07-15T00:00:00Z", "z", "GMT+10:00", "+10:00" },
+        { "ti", "Australia/ACT", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
         { "ti", "Australia/ACT", "2004-07-15T00:00:00Z", "zzzz", "GMT+10:00", "+10:00" },
         { "ti", "Australia/ACT", "2004-07-15T00:00:00Z", "v", "Sydney", "Australia/Sydney" },
         { "ti", "Australia/ACT", "2004-07-15T00:00:00Z", "vvvv", "Sydney", "Australia/Sydney" },
 
         { "ti", "Australia/Sydney", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
         { "ti", "Australia/Sydney", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
-        { "ti", "Australia/Sydney", "2004-01-15T00:00:00Z", "z", "GMT+11:00", "+11:00" },
+        { "ti", "Australia/Sydney", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
         { "ti", "Australia/Sydney", "2004-01-15T00:00:00Z", "zzzz", "GMT+11:00", "+11:00" },
         { "ti", "Australia/Sydney", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
         { "ti", "Australia/Sydney", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
-        { "ti", "Australia/Sydney", "2004-07-15T00:00:00Z", "z", "GMT+10:00", "+10:00" },
+        { "ti", "Australia/Sydney", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
         { "ti", "Australia/Sydney", "2004-07-15T00:00:00Z", "zzzz", "GMT+10:00", "+10:00" },
         { "ti", "Australia/Sydney", "2004-07-15T00:00:00Z", "v", "Sydney", "Australia/Sydney" },
         { "ti", "Australia/Sydney", "2004-07-15T00:00:00Z", "vvvv", "Sydney", "Australia/Sydney" },
@@ -3184,30 +3167,30 @@ void DateFormatTest::TestTimeZoneDisplayName()
         { "ti", "Europe/London", "2004-01-15T00:00:00Z", "zzzz", "GMT", "+0:00" },
         { "ti", "Europe/London", "2004-07-15T00:00:00Z", "Z", "+0100", "+1:00" },
         { "ti", "Europe/London", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+01:00", "+1:00" },
-        { "ti", "Europe/London", "2004-07-15T00:00:00Z", "z", "GMT+01:00", "+1:00" },
+        { "ti", "Europe/London", "2004-07-15T00:00:00Z", "z", "GMT+1", "+1:00" },
         { "ti", "Europe/London", "2004-07-15T00:00:00Z", "zzzz", "GMT+01:00", "+1:00" },
         { "ti", "Europe/London", "2004-07-15T00:00:00Z", "v", "GB", "Europe/London" },
         { "ti", "Europe/London", "2004-07-15T00:00:00Z", "vvvv", "GB", "Europe/London" },
 
         { "ti", "Etc/GMT+3", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
         { "ti", "Etc/GMT+3", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
-        { "ti", "Etc/GMT+3", "2004-01-15T00:00:00Z", "z", "GMT-03:00", "-3:00" },
+        { "ti", "Etc/GMT+3", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
         { "ti", "Etc/GMT+3", "2004-01-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
         { "ti", "Etc/GMT+3", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
         { "ti", "Etc/GMT+3", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
-        { "ti", "Etc/GMT+3", "2004-07-15T00:00:00Z", "z", "GMT-03:00", "-3:00" },
+        { "ti", "Etc/GMT+3", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
         { "ti", "Etc/GMT+3", "2004-07-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
-        { "ti", "Etc/GMT+3", "2004-07-15T00:00:00Z", "v", "GMT-03:00", "-3:00" },
+        { "ti", "Etc/GMT+3", "2004-07-15T00:00:00Z", "v", "GMT-3", "-3:00" },
         { "ti", "Etc/GMT+3", "2004-07-15T00:00:00Z", "vvvv", "GMT-03:00", "-3:00" },
 
         // JB#5150
         { "ti", "Asia/Calcutta", "2004-01-15T00:00:00Z", "Z", "+0530", "+5:30" },
         { "ti", "Asia/Calcutta", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
-        { "ti", "Asia/Calcutta", "2004-01-15T00:00:00Z", "z", "GMT+05:30", "+5:30" },
+        { "ti", "Asia/Calcutta", "2004-01-15T00:00:00Z", "z", "GMT+5:30", "+5:30" },
         { "ti", "Asia/Calcutta", "2004-01-15T00:00:00Z", "zzzz", "GMT+05:30", "+5:30" },
         { "ti", "Asia/Calcutta", "2004-07-15T00:00:00Z", "Z", "+0530", "+5:30" },
         { "ti", "Asia/Calcutta", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
-        { "ti", "Asia/Calcutta", "2004-07-15T00:00:00Z", "z", "GMT+05:30", "+05:30" },
+        { "ti", "Asia/Calcutta", "2004-07-15T00:00:00Z", "z", "GMT+5:30", "+05:30" },
         { "ti", "Asia/Calcutta", "2004-07-15T00:00:00Z", "zzzz", "GMT+05:30", "+5:30" },
         { "ti", "Asia/Calcutta", "2004-07-15T00:00:00Z", "v", "IN", "Alna/Calcutta" },
         { "ti", "Asia/Calcutta", "2004-07-15T00:00:00Z", "vvvv", "IN", "Asia/Calcutta" },
@@ -3225,8 +3208,8 @@ void DateFormatTest::TestTimeZoneDisplayName()
         { "en_GB", "Europe/Paris", "2004-07-15T00:00:00Z", "z", "CEST", "+2:00"},
         { "en_HK", "Europe/Paris", "2004-01-15T00:00:00Z", "zzzz", "Central European Standard Time", "+1:00"},
         { "en_HK", "Europe/Paris", "2004-07-15T00:00:00Z", "zzzz", "Central European Summer Time", "+2:00"},
-        { "en_HK", "Europe/Paris", "2004-01-15T00:00:00Z", "z", "GMT+01:00", "+1:00"},
-        { "en_HK", "Europe/Paris", "2004-07-15T00:00:00Z", "z", "GMT+02:00", "+2:00"},
+        { "en_HK", "Europe/Paris", "2004-01-15T00:00:00Z", "z", "GMT+1", "+1:00"},
+        { "en_HK", "Europe/Paris", "2004-07-15T00:00:00Z", "z", "GMT+2", "+2:00"},
 
         { NULL, NULL, NULL, NULL, NULL, NULL },
     };
@@ -3572,9 +3555,15 @@ void DateFormatTest::TestGMTParsing() {
         "HH:mm:ss vvvv",    "10:20:30 UT+10:00",    "10:20:30 +1000",
         "HH:mm:ss zzzz",    "10:20:30 UTC",         "10:20:30 +0000",   // standalone "UTC"
         "ZZZZ HH:mm:ss",    "UT 10:20:30",          "10:20:30 +0000",
-        "V HH:mm:ss",       "UT+0130 10:20:30",     "10:20:30 +0130",
-        "V HH:mm:ss",       "UTC+0130 10:20:30",    "10:20:30 +0130",
-        "HH mm Z ss",       "10 20 GMT-1100 30",    "10:20:30 -1100",
+        "z HH:mm:ss",       "UT+0130 10:20:30",     "10:20:30 +0130",
+        "z HH:mm:ss",       "UTC+0130 10:20:30",    "10:20:30 +0130",
+        // Note: GMT-1100 no longer works because of the introduction of the short
+        // localized GMT support. Previous implementation support this level of
+        // leniency (no separator char in localized GMT format), but the new
+        // implementation handles GMT-11 as the legitimate short localized GMT format
+        // and stop at there. Otherwise, roundtrip would be broken.
+        //"HH mm Z ss",       "10 20 GMT-1100 30",    "10:20:30 -1100",
+        "HH mm Z ss",       "10 20 GMT-11 30",    "10:20:30 -1100",
         "HH:mm:ssZZZZZ",    "14:25:45Z",            "14:25:45 +0000",
         "HH:mm:ssZZZZZ",    "15:00:00-08:00",       "15:00:00 -0800",
     };
index 37bd7501f6dd9405ad613dd1f3934b640cd02a16..26d848470f1a979aea0bc06ca6d1671300a09b21 100644 (file)
@@ -794,7 +794,7 @@ void DateIntervalFormatTest::testFormat() {
         "zh", "2007 11 10 10:10:10", "2007 11 20 10:10:10", "MMM", "11\\u6708", // (fixed expected result per ticket:6626: and others)
         
         
-        "zh", "2007 11 10 10:10:10", "2007 11 20 10:10:10", "hmz", "2007/11/10 \\u4e0a\\u534810:10 GMT-0800 \\u2013 2007/11/20 \\u4e0a\\u534810:10 GMT-0800", 
+        "zh", "2007 11 10 10:10:10", "2007 11 20 10:10:10", "hmz", "2007/11/10 \\u4e0a\\u534810:10 GMT-8 \\u2013 2007/11/20 \\u4e0a\\u534810:10 GMT-8", 
         
         "zh", "2007 11 10 10:10:10", "2007 11 20 10:10:10", "h", "2007/11/10 \\u4e0a\\u534810\\u65f6 \\u2013 2007/11/20 \\u4e0a\\u534810\\u65f6", 
         
@@ -803,7 +803,7 @@ void DateIntervalFormatTest::testFormat() {
         "zh", "2007 01 10 10:00:10", "2007 01 10 14:10:10", "hm", "\\u4e0a\\u534810:00\\u81f3\\u4e0b\\u53482:10", 
         
         
-        "zh", "2007 01 10 10:00:10", "2007 01 10 14:10:10", "hmz", "GMT-0800\\u4e0a\\u534810:00\\u81f3\\u4e0b\\u53482:10", 
+        "zh", "2007 01 10 10:00:10", "2007 01 10 14:10:10", "hmz", "GMT-8\\u4e0a\\u534810:00\\u81f3\\u4e0b\\u53482:10", 
         
         "zh", "2007 01 10 10:00:10", "2007 01 10 14:10:10", "h", "\\u4e0a\\u534810\\u65F6\\u81f3\\u4e0b\\u53482\\u65f6", 
         
@@ -813,7 +813,7 @@ void DateIntervalFormatTest::testFormat() {
         
         "zh", "2007 01 10 10:00:10", "2007 01 10 10:20:10", "hmv", "\\u6D1B\\u6749\\u77F6\\u65F6\\u95F4\\u4E0A\\u534810:00\\u81F310:20",
         
-        "zh", "2007 01 10 10:00:10", "2007 01 10 10:20:10", "hz", "\\u4e0a\\u534810\\u65f6 GMT-0800", 
+        "zh", "2007 01 10 10:00:10", "2007 01 10 10:20:10", "hz", "\\u4e0a\\u534810\\u65f6 GMT-8", 
         
         "zh", "2007 01 10 10:10:10", "2007 01 10 10:10:20", "hm", "\\u4e0a\\u534810:10", 
         
@@ -913,25 +913,25 @@ void DateIntervalFormatTest::testFormat() {
         
         "de", "2007 01 10 10:00:10", "2007 01 10 10:20:10", "hmv", "10:00-10:20 vorm. Los Angeles Zeit", 
         
-        "de", "2007 01 10 10:00:10", "2007 01 10 10:20:10", "hmz", "10:00-10:20 vorm. GMT-08:00", 
+        "de", "2007 01 10 10:00:10", "2007 01 10 10:20:10", "hmz", "10:00-10:20 vorm. GMT-8", 
         
         "de", "2007 01 10 10:00:10", "2007 01 10 10:20:10", "h", "10 vorm.", 
         "de", "2007 01 10 10:00:10", "2007 01 10 10:20:10", "H", "10 Uhr", 
         
         
-        "de", "2007 01 10 10:00:10", "2007 01 10 10:20:10", "hz", "10 vorm. GMT-08:00", 
+        "de", "2007 01 10 10:00:10", "2007 01 10 10:20:10", "hz", "10 vorm. GMT-8", 
         
         "de", "2007 01 10 10:10:10", "2007 01 10 10:10:20", "EEEEdMMMy", "Mittwoch, 10. Jan. 2007", 
         
         
         "de", "2007 01 10 10:10:10", "2007 01 10 10:10:20", "hmv", "10:10 vorm. Los Angeles Zeit", 
         
-        "de", "2007 01 10 10:10:10", "2007 01 10 10:10:20", "hmz", "10:10 vorm. GMT-08:00", 
+        "de", "2007 01 10 10:10:10", "2007 01 10 10:10:20", "hmz", "10:10 vorm. GMT-8", 
         
         
         "de", "2007 01 10 10:10:10", "2007 01 10 10:10:20", "hv", "10 vorm. Los Angeles Zeit", 
         
-        "de", "2007 01 10 10:10:10", "2007 01 10 10:10:20", "hz", "10 vorm. GMT-08:00", 
+        "de", "2007 01 10 10:10:10", "2007 01 10 10:10:20", "hz", "10 vorm. GMT-8", 
         
         // Thai (default calendar buddhist)
 
index 4ff82ef60c5f052434c02f34861a62ab5ee603ef..2662d9628486940a2b2885359cbb397699a89ae3 100644 (file)
@@ -1,6 +1,6 @@
 /*
 *******************************************************************************
-* Copyright (C) 2007-2012, International Business Machines Corporation and    *
+* Copyright (C) 2007-2013, International Business Machines Corporation and    *
 * others. All Rights Reserved.                                                *
 *******************************************************************************
 */
 #include "unicode/smpdtfmt.h"
 #include "unicode/uchar.h"
 #include "unicode/basictz.h"
+#include "unicode/tzfmt.h"
+#include "unicode/localpointer.h"
 #include "cstring.h"
-
-static const char* PATTERNS[] = {"z", "zzzz", "Z", "ZZZZ", "ZZZZZ", "v", "vvvv", "V", "VVVV"};
+#include "zonemeta.h"
+
+static const char* PATTERNS[] = {
+    "z",
+    "zzzz",
+    "Z",    // equivalent to "xxxx"
+    "ZZZZ", // equivalent to "OOOO"
+    "v",
+    "vvvv",
+    "O",
+    "OOOO",
+    "X",
+    "XX",
+    "XXX",
+    "XXXX",
+    "XXXXX",
+    "x",
+    "xx",
+    "xxx",
+    "xxxx",
+    "xxxxx",
+    "V",
+    "VV",
+    "VVV",
+    "VVVV"
+};
 static const int NUM_PATTERNS = sizeof(PATTERNS)/sizeof(const char*);
 
+static const UChar ETC_UNKNOWN[] = {0x45, 0x74, 0x63, 0x2F, 0x55, 0x6E, 0x6B, 0x6E, 0x6F, 0x77, 0x6E, 0};
+
+static const UChar ETC_SLASH[] = { 0x45, 0x74, 0x63, 0x2F, 0 }; // "Etc/"
+static const UChar SYSTEMV_SLASH[] = { 0x53, 0x79, 0x73, 0x74, 0x65, 0x6D, 0x56, 0x2F, 0 }; // "SystemV/
+static const UChar RIYADH8[] = { 0x52, 0x69, 0x79, 0x61, 0x64, 0x68, 0x38, 0 }; // "Riyadh8"
+
+static UBool contains(const char** list, const char* str) {
+    for (int32_t i = 0; list[i]; i++) {
+        if (uprv_strcmp(list[i], str) == 0) {
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
+
 void
 TimeZoneFormatTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
 {
@@ -32,6 +73,8 @@ TimeZoneFormatTest::runIndexedTest( int32_t index, UBool exec, const char* &name
     switch (index) {
         TESTCASE(0, TestTimeZoneRoundTrip);
         TESTCASE(1, TestTimeRoundTrip);
+        TESTCASE(2, TestParse);
+        TESTCASE(3, TestISOFormat);
         default: name = ""; break;
     }
 }
@@ -40,7 +83,7 @@ void
 TimeZoneFormatTest::TestTimeZoneRoundTrip(void) {
     UErrorCode status = U_ZERO_ERROR;
 
-    SimpleTimeZone unknownZone(-31415, (UnicodeString)"Etc/Unknown");
+    SimpleTimeZone unknownZone(-31415, ETC_UNKNOWN);
     int32_t badDstOffset = -1234;
     int32_t badZoneOffset = -2345;
 
@@ -172,7 +215,38 @@ TimeZoneFormatTest::TestTimeZoneRoundTrip(void) {
                         status = U_ZERO_ERROR;
                     }
 
-                    if (uprv_strcmp(PATTERNS[patidx], "VVVV") == 0) {
+                    if (uprv_strcmp(PATTERNS[patidx], "V") == 0) {
+                        // Short zone ID - should support roundtrip for canonical CLDR IDs
+                        UnicodeString canonicalID;
+                        TimeZone::getCanonicalID(*tzid, canonicalID, status);
+                        if (U_FAILURE(status)) {
+                            // Uknown ID - we should not get here
+                            errln((UnicodeString)"Unknown ID " + *tzid);
+                            status = U_ZERO_ERROR;
+                        } else if (outtzid != canonicalID) {
+                            if (outtzid.compare(ETC_UNKNOWN, -1) == 0) {
+                                // Note that some zones like Asia/Riyadh87 does not have
+                                // short zone ID and "unk" is used as fallback
+                                logln((UnicodeString)"Canonical round trip failed (probably as expected); tz=" + *tzid
+                                        + ", locale=" + LOCALES[locidx].getName() + ", pattern=" + PATTERNS[patidx]
+                                        + ", time=" + DATES[datidx] + ", str=" + tzstr
+                                        + ", outtz=" + outtzid);
+                            } else {
+                                errln((UnicodeString)"Canonical round trip failed; tz=" + *tzid
+                                    + ", locale=" + LOCALES[locidx].getName() + ", pattern=" + PATTERNS[patidx]
+                                    + ", time=" + DATES[datidx] + ", str=" + tzstr
+                                    + ", outtz=" + outtzid);
+                            }
+                        }
+                    } else if (uprv_strcmp(PATTERNS[patidx], "VV") == 0) {
+                        // Zone ID - full roundtrip support
+                        if (outtzid != *tzid) {
+                            errln((UnicodeString)"Zone ID round trip failued; tz="  + *tzid
+                                + ", locale=" + LOCALES[locidx].getName() + ", pattern=" + PATTERNS[patidx]
+                                + ", time=" + DATES[datidx] + ", str=" + tzstr
+                                + ", outtz=" + outtzid);
+                        }
+                    } else if (uprv_strcmp(PATTERNS[patidx], "VVV") == 0 || uprv_strcmp(PATTERNS[patidx], "VVVV") == 0) {
                         // Location: time zone rule must be preserved except
                         // zones not actually associated with a specific location.
                         // Time zones in this category do not have "/" in its ID.
@@ -187,12 +261,12 @@ TimeZoneFormatTest::TestTimeZoneRoundTrip(void) {
                             if (!((BasicTimeZone*)&outtz)->hasEquivalentTransitions((BasicTimeZone&)*tz, low, high, TRUE, status)) {
                                 if (canonical.indexOf((UChar)0x27 /*'/'*/) == -1) {
                                     // Exceptional cases, such as CET, EET, MET and WET
-                                    logln("Canonical round trip failed (as expected); tz=" + *tzid
+                                    logln((UnicodeString)"Canonical round trip failed (as expected); tz=" + *tzid
                                             + ", locale=" + LOCALES[locidx].getName() + ", pattern=" + PATTERNS[patidx]
                                             + ", time=" + DATES[datidx] + ", str=" + tzstr
                                             + ", outtz=" + outtzid);
                                 } else {
-                                    errln("Canonical round trip failed; tz=" + *tzid
+                                    errln((UnicodeString)"Canonical round trip failed; tz=" + *tzid
                                         + ", locale=" + LOCALES[locidx].getName() + ", pattern=" + PATTERNS[patidx]
                                         + ", time=" + DATES[datidx] + ", str=" + tzstr
                                         + ", outtz=" + outtzid);
@@ -205,8 +279,15 @@ TimeZoneFormatTest::TestTimeZoneRoundTrip(void) {
                         }
 
                     } else {
-                        // Check if localized GMT format or RFC format is used.
-                        UBool isOffsetFormat = (*PATTERNS[patidx] == 'Z');
+                        UBool isOffsetFormat = (*PATTERNS[patidx] == 'Z'
+                                                || *PATTERNS[patidx] == 'O'
+                                                || *PATTERNS[patidx] == 'X'
+                                                || *PATTERNS[patidx] == 'x');
+                        UBool minutesOffset = FALSE;
+                        if (*PATTERNS[patidx] == 'X' || *PATTERNS[patidx] == 'x') {
+                            minutesOffset = (uprv_strlen(PATTERNS[patidx]) <= 3);
+                        }
+
                         if (!isOffsetFormat) {
                             // Check if localized GMT format is used as a fallback of name styles
                             int32_t numDigits = 0;
@@ -215,13 +296,17 @@ TimeZoneFormatTest::TestTimeZoneRoundTrip(void) {
                                     numDigits++;
                                 }
                             }
-                            isOffsetFormat = (numDigits >= 3);
+                            isOffsetFormat = (numDigits > 0);
                         }
                         if (isOffsetFormat || tzstr == localGMTString) {
-                            // Localized GMT or RFC: total offset (raw + dst) must be preserved.
+                            // Localized GMT or ISO: total offset (raw + dst) must be preserved.
                             int32_t inOffset = inRaw + inDst;
                             int32_t outOffset = outRaw + outDst;
-                            if (inOffset != outOffset) {
+                            int32_t diff = outOffset - inOffset;
+                            if (minutesOffset) {
+                                diff = (diff / 60000) * 60000;
+                            }
+                            if (diff != 0) {
                                 errln((UnicodeString)"Offset round trip failed; tz=" + *tzid
                                     + ", locale=" + LOCALES[locidx].getName() + ", pattern=" + PATTERNS[patidx]
                                     + ", time=" + DATES[datidx] + ", str=" + tzstr
@@ -268,10 +353,14 @@ public:
         UErrorCode status = U_ZERO_ERROR;
         UBool REALLY_VERBOSE = FALSE;
 
-        // Whether each pattern is ambiguous at DST->STD local time overlap
-        UBool AMBIGUOUS_DST_DECESSION[] = { FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, FALSE, TRUE };
-        // Whether each pattern is ambiguous at STD->STD/DST->DST local time overlap
-        UBool AMBIGUOUS_NEGATIVE_SHIFT[] = { TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE };
+        // These patterns are ambiguous at DST->STD local time overlap
+        const char* AMBIGUOUS_DST_DECESSION[] = { "v", "vvvv", "V", "VV", "VVV", "VVVV", 0 };
+
+        // These patterns are ambiguous at STD->STD/DST->DST local time overlap
+        const char* AMBIGUOUS_NEGATIVE_SHIFT[] = { "z", "zzzz", "v", "vvvv", "V", "VV", "VVV", "VVVV", 0 };
+
+        // These patterns only support integer minutes offset
+        const char* MINUTES_OFFSET[] = { "X", "XX", "XXX", "x", "xx", "xxx", 0 };
 
         // Workaround for #6338
         //UnicodeString BASEPATTERN("yyyy-MM-dd'T'HH:mm:ss.SSS");
@@ -341,12 +430,32 @@ public:
                     continue;
                 }
 
+                UBool minutesOffset = contains(MINUTES_OFFSET, PATTERNS[patidx]);
+
                 tzids->reset(status);
                 const UnicodeString *tzid;
 
                 timer = Calendar::getNow();
 
                 while ((tzid = tzids->snext(status))) {
+                    if (uprv_strcmp(PATTERNS[patidx], "V") == 0) {
+                        // Some zones do not have short ID assigned, such as Asia/Riyadh87.
+                        // The time roundtrip will fail for such zones with pattern "V" (short zone ID).
+                        // This is expected behavior.
+                        const UChar* shortZoneID = ZoneMeta::getShortID(*tzid);
+                        if (shortZoneID == NULL) {
+                            continue;
+                        }
+                    } else if (uprv_strcmp(PATTERNS[patidx], "VVV") == 0) {
+                        // Some zones are not associated with any region, such as Etc/GMT+8.
+                        // The time roundtrip will fail for such zone with pattern "VVV" (exemplar location).
+                        // This is expected behavior.
+                        if (tzid->indexOf((UChar)0x2F) < 0 || tzid->indexOf(ETC_SLASH, -1, 0) >= 0
+                            || tzid->indexOf(SYSTEMV_SLASH, -1, 0) >= 0 || tzid->indexOf(RIYADH8, -1, 0) >= 0) {
+                            continue;
+                        }
+                    }
+
                     BasicTimeZone *tz = (BasicTimeZone*) TimeZone::createTimeZone(*tzid);
                     sdf->setTimeZone(*tz);
 
@@ -369,9 +478,13 @@ public:
                                 testTimes[0] = t + delta - 1;
                                 expectedRoundTrip[0] = TRUE;
                                 testTimes[1] = t + delta;
-                                expectedRoundTrip[1] = isDstDecession ? !AMBIGUOUS_DST_DECESSION[patidx] : !AMBIGUOUS_NEGATIVE_SHIFT[patidx];
+                                expectedRoundTrip[1] = isDstDecession ?
+                                    !contains(AMBIGUOUS_DST_DECESSION, PATTERNS[patidx]) :
+                                    !contains(AMBIGUOUS_NEGATIVE_SHIFT, PATTERNS[patidx]);
                                 testTimes[2] = t - 1;
-                                expectedRoundTrip[2] = isDstDecession ? !AMBIGUOUS_DST_DECESSION[patidx] : !AMBIGUOUS_NEGATIVE_SHIFT[patidx];
+                                expectedRoundTrip[2] = isDstDecession ?
+                                    !contains(AMBIGUOUS_DST_DECESSION, PATTERNS[patidx]) :
+                                    !contains(AMBIGUOUS_NEGATIVE_SHIFT, PATTERNS[patidx]);
                                 testTimes[3] = t;
                                 expectedRoundTrip[3] = TRUE;
                                 testLen = 4;
@@ -404,7 +517,11 @@ public:
                                 status = U_ZERO_ERROR;
                                 continue;
                             }
-                            if (parsedDate != testTimes[testidx]) {
+
+                            int32_t timeDiff = (int32_t)(parsedDate - testTimes[testidx]);
+                            UBool bTimeMatch = minutesOffset ?
+                                (timeDiff/60000)*60000 == 0 : timeDiff == 0;
+                            if (!bTimeMatch) {
                                 UnicodeString msg = (UnicodeString) "Time round trip failed for " + "tzid=" + *tzid + ", locale=" + data.locales[locidx].getName() + ", pattern=" + PATTERNS[patidx]
                                         + ", text=" + text + ", time=" + testTimes[testidx] + ", restime=" + parsedDate + ", diff=" + (parsedDate - testTimes[testidx]);
                                 // Timebomb for TZData update
@@ -561,4 +678,242 @@ TimeZoneFormatTest::TestTimeRoundTrip(void) {
     delete cal;
 }
 
+
+typedef struct {
+    const char*     text;
+    int32_t         inPos;
+    const char*     locale;
+    UTimeZoneFormatStyle    style;
+    UBool           parseAll;
+    const char*     expected;
+    int32_t         outPos;
+    UTimeZoneFormatTimeType timeType;
+} ParseTestData;
+
+void
+TimeZoneFormatTest::TestParse(void) {
+    const ParseTestData DATA[] = {
+        //   text               inPos   locale      style                               parseAll    expected            outPos  timeType
+            {"Z",               0,      "en_US",    UTZFMT_STYLE_ISO_EXTENDED_FULL,     false,      "Etc/GMT",          1,      UTZFMT_TIME_TYPE_UNKNOWN},
+            {"Z",               0,      "en_US",    UTZFMT_STYLE_SPECIFIC_LONG,         false,      "Etc/GMT",          1,      UTZFMT_TIME_TYPE_UNKNOWN},
+            {"Zambia time",     0,      "en_US",    UTZFMT_STYLE_ISO_EXTENDED_FULL,     true,       "Etc/GMT",          1,      UTZFMT_TIME_TYPE_UNKNOWN},
+            {"Zambia time",     0,      "en_US",    UTZFMT_STYLE_GENERIC_LOCATION,      false,      "Africa/Lusaka",    11,     UTZFMT_TIME_TYPE_UNKNOWN},
+            {"Zambia time",     0,      "en_US",    UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL,  true,       "Africa/Lusaka",    11,     UTZFMT_TIME_TYPE_UNKNOWN},
+            {"+00:00",          0,      "en_US",    UTZFMT_STYLE_ISO_EXTENDED_FULL,     false,      "Etc/GMT",          6,      UTZFMT_TIME_TYPE_UNKNOWN},
+            {"-01:30:45",       0,      "en_US",    UTZFMT_STYLE_ISO_EXTENDED_FULL,     false,      "GMT-01:30:45",     9,      UTZFMT_TIME_TYPE_UNKNOWN},
+            {"-7",              0,      "en_US",    UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL,  false,      "GMT-07:00",        2,      UTZFMT_TIME_TYPE_UNKNOWN},
+            {"-2222",           0,      "en_US",    UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL,  false,      "GMT-22:22",        5,      UTZFMT_TIME_TYPE_UNKNOWN},
+            {"-3333",           0,      "en_US",    UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL,  false,      "GMT-03:33",        4,      UTZFMT_TIME_TYPE_UNKNOWN},
+            {"XXX+01:30YYY",    3,      "en_US",    UTZFMT_STYLE_LOCALIZED_GMT,         false,      "GMT+01:30",        9,      UTZFMT_TIME_TYPE_UNKNOWN},
+            {"GMT0",            0,      "en_US",    UTZFMT_STYLE_SPECIFIC_SHORT,        false,      "Etc/GMT",          3,      UTZFMT_TIME_TYPE_UNKNOWN},
+            {"EST",             0,      "en_US",    UTZFMT_STYLE_SPECIFIC_SHORT,        false,      "America/New_York", 3,      UTZFMT_TIME_TYPE_STANDARD},
+            {"ESTx",            0,      "en_US",    UTZFMT_STYLE_SPECIFIC_SHORT,        false,      "America/New_York", 3,      UTZFMT_TIME_TYPE_STANDARD},
+            {"EDTx",            0,      "en_US",    UTZFMT_STYLE_SPECIFIC_SHORT,        false,      "America/New_York", 3,      UTZFMT_TIME_TYPE_DAYLIGHT},
+            {"EST",             0,      "en_US",    UTZFMT_STYLE_SPECIFIC_LONG,         false,      NULL,               0,      UTZFMT_TIME_TYPE_UNKNOWN},
+            {"EST",             0,      "en_US",    UTZFMT_STYLE_SPECIFIC_LONG,         true,       "America/New_York", 3,      UTZFMT_TIME_TYPE_STANDARD},
+            {"EST",             0,      "en_CA",    UTZFMT_STYLE_SPECIFIC_SHORT,        false,      "America/Toronto",  3,      UTZFMT_TIME_TYPE_STANDARD},
+            {NULL,              0,      NULL,       UTZFMT_STYLE_GENERIC_LOCATION,      false,      NULL,               0,      UTZFMT_TIME_TYPE_UNKNOWN}
+    };
+
+    for (int32_t i = 0; DATA[i].text; i++) {
+        UErrorCode status = U_ZERO_ERROR;
+        LocalPointer<TimeZoneFormat> tzfmt(TimeZoneFormat::createInstance(Locale(DATA[i].locale), status));
+        if (U_FAILURE(status)) {
+            dataerrln("Fail TimeZoneFormat::createInstance: %s", u_errorName(status));
+            continue;
+        }
+        UTimeZoneFormatTimeType ttype = UTZFMT_TIME_TYPE_UNKNOWN;
+        ParsePosition pos(DATA[i].inPos);
+        int32_t parseOptions = DATA[i].parseAll ? UTZFMT_PARSE_OPTION_ALL_STYLES : UTZFMT_PARSE_OPTION_NONE;
+        TimeZone* tz = tzfmt->parse(DATA[i].style, DATA[i].text, pos, parseOptions, &ttype);
+
+        UnicodeString errMsg;
+        if (tz) {
+            UnicodeString outID;
+            tz->getID(outID);
+            if (outID != UnicodeString(DATA[i].expected)) {
+                errMsg = (UnicodeString)"Time zone ID: " + outID + " - expected: " + DATA[i].expected;
+            } else if (pos.getIndex() != DATA[i].outPos) {
+                errMsg = (UnicodeString)"Parsed pos: " + pos.getIndex() + " - expected: " + DATA[i].outPos;
+            } else if (ttype != DATA[i].timeType) {
+                errMsg = (UnicodeString)"Time type: " + ttype + " - expected: " + DATA[i].timeType;
+            }
+            delete tz;
+        } else {
+            if (DATA[i].expected) {
+                errln((UnicodeString)"Fail: Parse failure - expected: " + DATA[i].expected);
+            }
+        }
+        if (errMsg.length() > 0) {
+            errln((UnicodeString)"Fail: " + errMsg + " [text=" + DATA[i].text + ", pos=" + DATA[i].inPos + ", style=" + DATA[i].style + "]");
+        }
+    }
+}
+
+void
+TimeZoneFormatTest::TestISOFormat(void) {
+    const int32_t OFFSET[] = {
+        0,          // 0
+        999,        // 0.999s
+        -59999,     // -59.999s
+        60000,      // 1m
+        -77777,     // -1m 17.777s
+        1800000,    // 30m
+        -3600000,   // -1h
+        36000000,   // 10h
+        -37800000,  // -10h 30m
+        -37845000,  // -10h 30m 45s
+        108000000,  // 30h
+    };
+
+    const char* ISO_STR[][11] = {
+        // 0
+        {
+            "Z", "Z", "Z", "Z", "Z",
+            "+00", "+0000", "+00:00", "+0000", "+00:00",
+            "+0000"
+        },
+        // 999
+        {
+            "Z", "Z", "Z", "Z", "Z",
+            "+00", "+0000", "+00:00", "+0000", "+00:00",
+            "+0000"
+        },
+        // -59999
+        {
+            "Z", "Z", "Z", "-000059", "-00:00:59",
+            "+00", "+0000", "+00:00", "-000059", "-00:00:59",
+            "-000059"
+        },
+        // 60000
+        {
+            "+0001", "+0001", "+00:01", "+0001", "+00:01",
+            "+0001", "+0001", "+00:01", "+0001", "+00:01",
+            "+0001"
+        },
+        // -77777
+        {
+            "-0001", "-0001", "-00:01", "-000117", "-00:01:17",
+            "-0001", "-0001", "-00:01", "-000117", "-00:01:17",
+            "-000117"
+        },
+        // 1800000
+        {
+            "+0030", "+0030", "+00:30", "+0030", "+00:30",
+            "+0030", "+0030", "+00:30", "+0030", "+00:30",
+            "+0030"
+        },
+        // -3600000
+        {
+            "-01", "-0100", "-01:00", "-0100", "-01:00",
+            "-01", "-0100", "-01:00", "-0100", "-01:00",
+            "-0100"
+        },
+        // 36000000
+        {
+            "+10", "+1000", "+10:00", "+1000", "+10:00",
+            "+10", "+1000", "+10:00", "+1000", "+10:00",
+            "+1000"
+        },
+        // -37800000
+        {
+            "-1030", "-1030", "-10:30", "-1030", "-10:30",
+            "-1030", "-1030", "-10:30", "-1030", "-10:30",
+            "-1030"
+        },
+        // -37845000
+        {
+            "-1030", "-1030", "-10:30", "-103045", "-10:30:45",
+            "-1030", "-1030", "-10:30", "-103045", "-10:30:45",
+            "-103045"
+        },
+        // 108000000
+        {
+            0, 0, 0, 0, 0,
+            0, 0, 0, 0, 0,
+            0
+        }
+    };
+
+    const char* PATTERN[] = {
+        "X", "XX", "XXX", "XXXX", "XXXXX",
+        "x", "xx", "xxx", "xxxx", "xxxxx",
+        "Z", // equivalent to "xxxx"
+        0
+    };
+
+    const int32_t MIN_OFFSET_UNIT[] = {
+        60000, 60000, 60000, 1000, 1000,
+        60000, 60000, 60000, 1000, 1000,
+        1000,
+    };
+
+    // Formatting
+    UErrorCode status = U_ZERO_ERROR;
+    LocalPointer<SimpleDateFormat> sdf(new SimpleDateFormat(status));
+    if (U_FAILURE(status)) {
+        dataerrln("Fail new SimpleDateFormat: %s", u_errorName(status));
+        return;
+    }
+    UDate d = Calendar::getNow();
+
+    for (uint32_t i = 0; i < sizeof(OFFSET)/sizeof(OFFSET[0]); i++) {
+        SimpleTimeZone* tz = new SimpleTimeZone(OFFSET[i], UnicodeString("Zone Offset:") + OFFSET[i] + "ms");
+        sdf->adoptTimeZone(tz);
+        for (int32_t j = 0; PATTERN[j] != 0; j++) {
+            sdf->applyPattern(UnicodeString(PATTERN[j]));
+            UnicodeString result;
+            sdf->format(d, result);
+
+            if (ISO_STR[i][j]) {
+                if (result != UnicodeString(ISO_STR[i][j])) {
+                    errln((UnicodeString)"FAIL: pattern=" + PATTERN[j] + ", offset=" + OFFSET[i] + " -> "
+                        + result + " (expected: " + ISO_STR[i][j] + ")");
+                }
+            } else {
+                // Offset out of range
+                // Note: for now, there is no way to propagate the error status through
+                // the SimpleDateFormat::format above.
+                if (result.length() > 0) {
+                    errln((UnicodeString)"FAIL: Non-Empty result for pattern=" + PATTERN[j] + ", offset=" + OFFSET[i]
+                        + " (expected: empty result)");
+                }
+            }
+        }
+    }
+
+    // Parsing
+    LocalPointer<Calendar> outcal(Calendar::createInstance(status));
+    if (U_FAILURE(status)) {
+        dataerrln("Fail new Calendar: %s", u_errorName(status));
+        return;
+    }
+    for (int32_t i = 0; ISO_STR[i][0] != NULL; i++) {
+        for (int32_t j = 0; PATTERN[j] != 0; j++) {
+            if (ISO_STR[i][j] == 0) {
+                continue;
+            }
+            ParsePosition pos(0);
+            SimpleTimeZone* bogusTZ = new SimpleTimeZone(-1, UnicodeString("Zone Offset: -1ms"));
+            outcal->adoptTimeZone(bogusTZ);
+            sdf->applyPattern(PATTERN[j]);
+
+            sdf->parse(UnicodeString(ISO_STR[i][j]), *(outcal.getAlias()), pos);
+
+            if (pos.getIndex() != (int32_t)uprv_strlen(ISO_STR[i][j])) {
+                errln((UnicodeString)"FAIL: Failed to parse the entire input string: " + ISO_STR[i][j]);
+            }
+
+            const TimeZone& outtz = outcal->getTimeZone();
+            int32_t outOffset = outtz.getRawOffset();
+            int32_t adjustedOffset = OFFSET[i] / MIN_OFFSET_UNIT[j] * MIN_OFFSET_UNIT[j];
+            if (outOffset != adjustedOffset) {
+                errln((UnicodeString)"FAIL: Incorrect offset:" + outOffset + "ms for input string: " + ISO_STR[i][j]
+                    + " (expected:" + adjustedOffset + "ms)");
+            }
+        }
+    }
+}
+
+
 #endif /* #if !UCONFIG_NO_FORMATTING */
index 5e7c39706c4b19f3dbf1f7e786680680d6a4fe9e..4635711f555f704421b2e86fc8425b0364fa1e5d 100644 (file)
@@ -1,6 +1,6 @@
 /*
 *******************************************************************************
-* Copyright (C) 2007-2010, International Business Machines Corporation and    *
+* Copyright (C) 2007-2013, International Business Machines Corporation and    *
 * others. All Rights Reserved.                                                *
 *******************************************************************************
 */
@@ -20,6 +20,8 @@ class TimeZoneFormatTest : public IntlTest {
 
     void TestTimeZoneRoundTrip(void);
     void TestTimeRoundTrip(void);
+    void TestParse(void);
+    void TestISOFormat(void);
 };
 
 #endif /* #if !UCONFIG_NO_FORMATTING */
index 08c07c480decf7bcb6b5c55be56d47555d9a0e16..274b3f561b79ff653277b1b00938334bfbbb5d25 100644 (file)
@@ -1,5 +1,5 @@
 /********************************************************************
- * Copyright (c) 1997-2011, International Business Machines
+ * Copyright (c) 1997-2013, International Business Machines
  * Corporation and others. All Rights Reserved.
  ********************************************************************/
  
@@ -950,25 +950,25 @@ void TimeZoneRegressionTest::Test4176686() {
     UnicodeString a,b,c,d,e,f,g,h,i,j,k,l;
     UnicodeString DATA[] = {
         "z1->getDisplayName(false, SHORT)/std zone",
-        z1->getDisplayName(FALSE, TimeZone::SHORT, a), "GMT+01:30",
+        z1->getDisplayName(FALSE, TimeZone::SHORT, a), "GMT+1:30",
         "z1->getDisplayName(false, LONG)/std zone",
         z1->getDisplayName(FALSE, TimeZone::LONG, b), "GMT+01:30",
         "z1->getDisplayName(true, SHORT)/std zone",
-        z1->getDisplayName(TRUE, TimeZone::SHORT, c), "GMT+01:30",
+        z1->getDisplayName(TRUE, TimeZone::SHORT, c), "GMT+1:30",
         "z1->getDisplayName(true, LONG)/std zone",
         z1->getDisplayName(TRUE, TimeZone::LONG, d ), "GMT+01:30",
         "z2->getDisplayName(false, SHORT)/dst zone",
-        z2->getDisplayName(FALSE, TimeZone::SHORT, e), "GMT+01:30",
+        z2->getDisplayName(FALSE, TimeZone::SHORT, e), "GMT+1:30",
         "z2->getDisplayName(false, LONG)/dst zone",
         z2->getDisplayName(FALSE, TimeZone::LONG, f ), "GMT+01:30",
         "z2->getDisplayName(true, SHORT)/dst zone",
-        z2->getDisplayName(TRUE, TimeZone::SHORT, g), "GMT+02:15",
+        z2->getDisplayName(TRUE, TimeZone::SHORT, g), "GMT+2:15",
         "z2->getDisplayName(true, LONG)/dst zone",
         z2->getDisplayName(TRUE, TimeZone::LONG, h ), "GMT+02:15",
-        "DateFormat.format(std)/std zone", fmt1->format(std, i), "GMT+01:30",
-        "DateFormat.format(dst)/std zone", fmt1->format(dst, j), "GMT+01:30",
-        "DateFormat.format(std)/dst zone", fmt2->format(std, k), "GMT+01:30",
-        "DateFormat.format(dst)/dst zone", fmt2->format(dst, l), "GMT+02:15",
+        "DateFormat.format(std)/std zone", fmt1->format(std, i), "GMT+1:30",
+        "DateFormat.format(dst)/std zone", fmt1->format(dst, j), "GMT+1:30",
+        "DateFormat.format(std)/dst zone", fmt2->format(std, k), "GMT+1:30",
+        "DateFormat.format(dst)/dst zone", fmt2->format(dst, l), "GMT+2:15",
     };
 
     for (int32_t idx=0; idx<(int32_t)ARRAY_LENGTH(DATA); idx+=3) {
index b2a7612417253f6cc28b17c1a59631bf18a39667..6c2d4eeb144cd861d2595bfc021cffe6bb59c5f2 100644 (file)
@@ -1,6 +1,6 @@
 /***********************************************************************
  * COPYRIGHT: 
- * Copyright (c) 1997-2012, International Business Machines Corporation
+ * Copyright (c) 1997-2013, International Business Machines Corporation
  * and others. All Rights Reserved.
  ***********************************************************************/
 
@@ -2113,7 +2113,7 @@ static struct   {
      //  zone id         locale   summer   format          expected display name
       {"Europe/London",     "en", FALSE, TimeZone::SHORT, "GMT"},
       {"Europe/London",     "en", FALSE, TimeZone::LONG,  "Greenwich Mean Time"},
-      {"Europe/London",     "en", TRUE,  TimeZone::SHORT, "GMT+01:00" /*"BST"*/},
+      {"Europe/London",     "en", TRUE,  TimeZone::SHORT, "GMT+1" /*"BST"*/},
       {"Europe/London",     "en", TRUE,  TimeZone::LONG,  "British Summer Time"},
       
       {"America/Anchorage", "en", FALSE, TimeZone::SHORT, "AKST"},
@@ -2122,17 +2122,17 @@ static struct   {
       {"America/Anchorage", "en", TRUE,  TimeZone::LONG,  "Alaska Daylight Time"},
       
       // Southern Hemisphere, all data from meta:Australia_Western
-      {"Australia/Perth",   "en", FALSE, TimeZone::SHORT, "GMT+08:00"/*"AWST"*/},
+      {"Australia/Perth",   "en", FALSE, TimeZone::SHORT, "GMT+8"/*"AWST"*/},
       {"Australia/Perth",   "en", FALSE, TimeZone::LONG,  "Australian Western Standard Time"},
       // Note: Perth does not observe DST currently. When display name is missing,
       // the localized GMT format with the current offset is used even daylight name was
       // requested. See #9350.
-      {"Australia/Perth",   "en", TRUE,  TimeZone::SHORT, "GMT+08:00"/*"AWDT"*/},
+      {"Australia/Perth",   "en", TRUE,  TimeZone::SHORT, "GMT+8"/*"AWDT"*/},
       {"Australia/Perth",   "en", TRUE,  TimeZone::LONG,  "Australian Western Daylight Time"},
        
-      {"America/Sao_Paulo",  "en", FALSE, TimeZone::SHORT, "GMT-03:00"/*"BRT"*/},
+      {"America/Sao_Paulo",  "en", FALSE, TimeZone::SHORT, "GMT-3"/*"BRT"*/},
       {"America/Sao_Paulo",  "en", FALSE, TimeZone::LONG,  "Brasilia Standard Time"},
-      {"America/Sao_Paulo",  "en", TRUE,  TimeZone::SHORT, "GMT-02:00"/*"BRST"*/},
+      {"America/Sao_Paulo",  "en", TRUE,  TimeZone::SHORT, "GMT-2"/*"BRST"*/},
       {"America/Sao_Paulo",  "en", TRUE,  TimeZone::LONG,  "Brasilia Summer Time"},
        
       // No Summer Time, but had it before 1983.
@@ -2142,14 +2142,14 @@ static struct   {
       {"Pacific/Honolulu",   "en", TRUE,  TimeZone::LONG,  "Hawaii-Aleutian Daylight Time"},
        
       // Northern, has Summer, not commonly used.
-      {"Europe/Helsinki",    "en", FALSE, TimeZone::SHORT, "GMT+02:00"/*"EET"*/},
+      {"Europe/Helsinki",    "en", FALSE, TimeZone::SHORT, "GMT+2"/*"EET"*/},
       {"Europe/Helsinki",    "en", FALSE, TimeZone::LONG,  "Eastern European Standard Time"},
-      {"Europe/Helsinki",    "en", TRUE,  TimeZone::SHORT, "GMT+03:00"/*"EEST"*/},
+      {"Europe/Helsinki",    "en", TRUE,  TimeZone::SHORT, "GMT+3"/*"EEST"*/},
       {"Europe/Helsinki",    "en", TRUE,  TimeZone::LONG,  "Eastern European Summer Time"},
 
       // Repeating the test data for DST.  The test data below trigger the problem reported
       // by Ticket#6644
-      {"Europe/London",       "en", TRUE, TimeZone::SHORT, "GMT+01:00" /*"BST"*/},
+      {"Europe/London",       "en", TRUE, TimeZone::SHORT, "GMT+1" /*"BST"*/},
       {"Europe/London",       "en", TRUE, TimeZone::LONG,  "British Summer Time"},
 
       {NULL, NULL, FALSE, TimeZone::SHORT, NULL}   // NULL values terminate list