From: Yoshito Umaoka Date: Mon, 11 Feb 2013 00:23:55 +0000 (+0000) Subject: ICU-9867 New time zone pattern letters/types support for CLDR 23/ICU 51. X-Git-Tag: milestone-59-0-1~3159 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=87158d4fbad7bde5fb127a0f275ce98cf8b50ea8;p=icu ICU-9867 New time zone pattern letters/types support for CLDR 23/ICU 51. X-SVN-Rev: 33159 --- diff --git a/icu4c/source/i18n/dtfmtsym.cpp b/icu4c/source/i18n/dtfmtsym.cpp index a9034a80879..270cfe1ea4b 100644 --- a/icu4c/source/i18n/dtfmtsym.cpp +++ b/icu4c/source/i18n/dtfmtsym.cpp @@ -47,17 +47,18 @@ * 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 */ diff --git a/icu4c/source/i18n/smpdtfmt.cpp b/icu4c/source/i18n/smpdtfmt.cpp index 79e03affd43..8ebd0d171f2 100644 --- a/icu4c/source/i18n/smpdtfmt.cpp +++ b/icu4c/source/i18n/smpdtfmt.cpp @@ -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; diff --git a/icu4c/source/i18n/timezone.cpp b/icu4c/source/i18n/timezone.cpp index ca98ef30bd0..de324ae8b65 100644 --- a/icu4c/source/i18n/timezone.cpp +++ b/icu4c/source/i18n/timezone.cpp @@ -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 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 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)) { diff --git a/icu4c/source/i18n/tzfmt.cpp b/icu4c/source/i18n/tzfmt.cpp index a7c7f9a4e3c..f54193d7aa6 100644 --- a/icu4c/source/i18n/tzfmt.cpp +++ b/icu4c/source/i18n/tzfmt.cpp @@ -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. * ******************************************************************************* */ @@ -25,22 +25,56 @@ #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 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 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(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 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(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 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 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 diff --git a/icu4c/source/i18n/tznames.cpp b/icu4c/source/i18n/tznames.cpp index 923eb7ae9e3..c887997e82d 100644 --- a/icu4c/source/i18n/tznames.cpp +++ b/icu4c/source/i18n/tznames.cpp @@ -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. * ******************************************************************************* */ @@ -25,13 +25,6 @@ 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& diff --git a/icu4c/source/i18n/tznames_impl.cpp b/icu4c/source/i18n/tznames_impl.cpp index 876411bc599..e3b0c3c0431 100644 --- a/icu4c/source/i18n/tznames_impl.cpp +++ b/icu4c/source/i18n/tznames_impl.cpp @@ -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[] = ""; // 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(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 diff --git a/icu4c/source/i18n/tznames_impl.h b/icu4c/source/i18n/tznames_impl.h index c03eb8e6ed4..c677a8b9537 100644 --- a/icu4c/source/i18n/tznames_impl.h +++ b/icu4c/source/i18n/tznames_impl.h @@ -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; diff --git a/icu4c/source/i18n/ucln_in.h b/icu4c/source/i18n/ucln_in.h index fc3565208e2..494f73e2aac 100644 --- a/icu4c/source/i18n/ucln_in.h +++ b/icu4c/source/i18n/ucln_in.h @@ -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, diff --git a/icu4c/source/i18n/unicode/smpdtfmt.h b/icu4c/source/i18n/unicode/smpdtfmt.h index 299449d2f9d..02966617fec 100644 --- a/icu4c/source/i18n/unicode/smpdtfmt.h +++ b/icu4c/source/i18n/unicode/smpdtfmt.h @@ -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 diff --git a/icu4c/source/i18n/unicode/tzfmt.h b/icu4c/source/i18n/unicode/tzfmt.h index 90b43b01a7f..2b20f353fe3 100644 --- a/icu4c/source/i18n/unicode/tzfmt.h +++ b/icu4c/source/i18n/unicode/tzfmt.h @@ -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: *
  • Offset digits (e.g. "0123456789" - see {@link #getGMTOffsetDigits}) *
  • GMT zero format (e.g. "GMT" - see {@link #getGMTZeroFormat}) * + * 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; + *
      + *
    • GMT format pattern (e.g. "GMT {0}" - see {@link #getGMTPattern}) + *
    • Offset time pattern (e.g. "+HH:mm" - see {@link #getGMTOffsetPattern}) + *
    • Offset digits (e.g. "0123456789" - see {@link #getGMTOffsetDigits}) + *
    • GMT zero format (e.g. "GMT" - see {@link #getGMTZeroFormat}) + *
    + * 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 ParsePosition pos 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 ParsePosition pos + * 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 TimeZone 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 diff --git a/icu4c/source/i18n/unicode/tznames.h b/icu4c/source/i18n/unicode/tznames.h index 8211b3b1ab9..99b71d42af9 100644 --- a/icu4c/source/i18n/unicode/tznames.h +++ b/icu4c/source/i18n/unicode/tznames.h @@ -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 diff --git a/icu4c/source/i18n/unicode/udat.h b/icu4c/source/i18n/unicode/udat.h index 1d21c74eaff..6f542d379f3 100644 --- a/icu4c/source/i18n/unicode/udat.h +++ b/icu4c/source/i18n/unicode/udat.h @@ -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; diff --git a/icu4c/source/i18n/zonemeta.cpp b/icu4c/source/i18n/zonemeta.cpp index 53a3ef3465b..522c3f04990 100644 --- a/icu4c/source/i18n/zonemeta.cpp +++ b/icu4c/source/i18n/zonemeta.cpp @@ -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(&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 diff --git a/icu4c/source/i18n/zonemeta.h b/icu4c/source/i18n/zonemeta.h index 26c2b04fa35..3c4218276ac 100644 --- a/icu4c/source/i18n/zonemeta.h +++ b/icu4c/source/i18n/zonemeta.h @@ -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 diff --git a/icu4c/source/test/cintltst/cdattst.c b/icu4c/source/test/cintltst/cdattst.c index 90d27c9e45e..bd4fd8482e6 100644 --- a/icu4c/source/test/cintltst/cdattst.c +++ b/icu4c/source/test/cintltst/cdattst.c @@ -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) { diff --git a/icu4c/source/test/intltest/dtfmttst.cpp b/icu4c/source/test/intltest/dtfmttst.cpp index c879ba866a3..3ebec5cc854 100644 --- a/icu4c/source/test/intltest/dtfmttst.cpp +++ b/icu4c/source/test/intltest/dtfmttst.cpp @@ -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", }; diff --git a/icu4c/source/test/intltest/dtifmtts.cpp b/icu4c/source/test/intltest/dtifmtts.cpp index 37bd7501f6d..26d848470f1 100644 --- a/icu4c/source/test/intltest/dtifmtts.cpp +++ b/icu4c/source/test/intltest/dtifmtts.cpp @@ -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) diff --git a/icu4c/source/test/intltest/tzfmttst.cpp b/icu4c/source/test/intltest/tzfmttst.cpp index 4ff82ef60c5..2662d962848 100644 --- a/icu4c/source/test/intltest/tzfmttst.cpp +++ b/icu4c/source/test/intltest/tzfmttst.cpp @@ -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. * ******************************************************************************* */ @@ -18,11 +18,52 @@ #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 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 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 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 */ diff --git a/icu4c/source/test/intltest/tzfmttst.h b/icu4c/source/test/intltest/tzfmttst.h index 5e7c39706c4..4635711f555 100644 --- a/icu4c/source/test/intltest/tzfmttst.h +++ b/icu4c/source/test/intltest/tzfmttst.h @@ -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 */ diff --git a/icu4c/source/test/intltest/tzregts.cpp b/icu4c/source/test/intltest/tzregts.cpp index 08c07c480de..274b3f561b7 100644 --- a/icu4c/source/test/intltest/tzregts.cpp +++ b/icu4c/source/test/intltest/tzregts.cpp @@ -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) { diff --git a/icu4c/source/test/intltest/tztest.cpp b/icu4c/source/test/intltest/tztest.cpp index b2a76124172..6c2d4eeb144 100644 --- a/icu4c/source/test/intltest/tztest.cpp +++ b/icu4c/source/test/intltest/tztest.cpp @@ -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