return canonicalID;
}
+#ifndef U_HIDE_DRAFT_API
+UnicodeString&
+TimeZone::getWindowsID(const UnicodeString& id, UnicodeString& winid, UErrorCode& status) {
+ winid.remove();
+ if (U_FAILURE(status)) {
+ return winid;
+ }
+
+ // canonicalize the input ID
+ UnicodeString canonicalID;
+ UBool isSystemID = FALSE;
+
+ getCanonicalID(id, canonicalID, isSystemID, status);
+ if (U_FAILURE(status) || !isSystemID) {
+ // mapping data is only applicable to tz database IDs
+ return winid;
+ }
+
+ UResourceBundle *mapTimezones = ures_openDirect(NULL, "windowsZones", &status);
+ ures_getByKey(mapTimezones, "mapTimezones", mapTimezones, &status);
+
+ if (U_FAILURE(status)) {
+ return winid;
+ }
+
+ UResourceBundle *winzone = NULL;
+ UBool found = FALSE;
+ while (ures_hasNext(mapTimezones) && !found) {
+ winzone = ures_getNextResource(mapTimezones, winzone, &status);
+ if (U_FAILURE(status)) {
+ break;
+ }
+ if (ures_getType(winzone) != URES_TABLE) {
+ continue;
+ }
+ UResourceBundle *regionalData = NULL;
+ while (ures_hasNext(winzone) && !found) {
+ regionalData = ures_getNextResource(winzone, regionalData, &status);
+ if (U_FAILURE(status)) {
+ break;
+ }
+ if (ures_getType(regionalData) != URES_STRING) {
+ continue;
+ }
+ int32_t len;
+ const UChar *tzids = ures_getString(regionalData, &len, &status);
+ if (U_FAILURE(status)) {
+ break;
+ }
+
+ const UChar *start = tzids;
+ UBool hasNext = TRUE;
+ while (hasNext) {
+ const UChar *end = u_strchr(start, (UChar)0x20);
+ if (end == NULL) {
+ end = tzids + len;
+ hasNext = FALSE;
+ }
+ if (canonicalID.compare(start, end - start) == 0) {
+ winid = UnicodeString(ures_getKey(winzone));
+ found = TRUE;
+ break;
+ }
+ start = end + 1;
+ }
+ }
+ ures_close(regionalData);
+ }
+ ures_close(winzone);
+
+ return winid;
+}
+
+#define MAX_WINDOWS_ID_SIZE 128
+
+UnicodeString&
+TimeZone::getIDForWindowsID(const UnicodeString& winid, const char* region, UnicodeString& id, UErrorCode& status) {
+ id.remove();
+ if (U_FAILURE(status)) {
+ return id;
+ }
+
+ UResourceBundle *zones = ures_openDirect(NULL, "windowsZones", &status);
+ ures_getByKey(zones, "mapTimezones", zones, &status);
+ if (U_FAILURE(status)) {
+ return id;
+ }
+
+ UErrorCode tmperr = U_ZERO_ERROR;
+ char winidKey[MAX_WINDOWS_ID_SIZE];
+ int32_t winKeyLen = winid.extract(0, winid.length(), winidKey, sizeof(winidKey) - 1);
+
+ if (winKeyLen == 0 || winKeyLen >= sizeof(winidKey)) {
+ return id;
+ }
+ winidKey[winKeyLen] = 0;
+
+ ures_getByKey(zones, winidKey, zones, &tmperr); // use tmperr, because windows mapping might not
+ // be avaiable by design
+ if (U_FAILURE(tmperr)) {
+ return id;
+ }
+
+ const UChar *tzid = NULL;
+ int32_t len = 0;
+ if (region) {
+ int32_t tzidsLen = 0;
+ const UChar *tzids = ures_getStringByKey(zones, region, &len, &tmperr); // use tmperr, because
+ // regional mapping is optional
+ if (U_SUCCESS(tmperr)) {
+ // first ID delimited by space is the defasult one
+ const UChar *end = u_strchr(tzids, (UChar)0x20);
+ if (end == NULL) {
+ id.setTo(tzids, -1);
+ } else {
+ id.setTo(tzids, end - tzids);
+ }
+ return id;
+ }
+ }
+
+ tzid = ures_getStringByKey(zones, "001", &len, &status); // using status, because "001" must be
+ // available at this point
+ if (U_SUCCESS(status)) {
+ id.setTo(tzid, len);
+ }
+
+ return id;
+}
+#endif /* U_HIDE_DRAFT_API */
+
+
U_NAMESPACE_END
#endif /* #if !UCONFIG_NO_FORMATTING */
return FALSE;
}
+#ifndef U_HIDE_DRAFT_API
+U_CAPI int32_t U_EXPORT2
+ucal_getWindowsTimeZoneID(const UChar* id, int32_t len, UChar* winid, int32_t winidCapacity, UErrorCode* status) {
+ if (U_FAILURE(*status)) {
+ return 0;
+ }
+
+ int32_t resultLen = 0;
+ UnicodeString resultWinID;
+
+ TimeZone::getWindowsID(UnicodeString(id, len), resultWinID, *status);
+ if (U_SUCCESS(*status) && resultWinID.length() > 0) {
+ resultLen = resultWinID.length();
+ resultWinID.extract(winid, winidCapacity, *status);
+ }
+
+ return resultLen;
+}
+
+U_CAPI int32_t U_EXPORT2
+ucal_getTimeZoneIDForWindowsID(const UChar* winid, int32_t len, const char* region, UChar* id, int32_t idCapacity, UErrorCode* status) {
+ if (U_FAILURE(*status)) {
+ return 0;
+ }
+
+ int32_t resultLen = 0;
+ UnicodeString resultID;
+
+ TimeZone::getIDForWindowsID(UnicodeString(winid, len), region, resultID, *status);
+ if (U_SUCCESS(*status) && resultID.length() > 0) {
+ resultLen = resultID.length();
+ resultID.extract(id, idCapacity, *status);
+ }
+
+ return resultLen;
+}
+
+#endif /* U_HIDE_DRAFT_API */
+
#endif /* #if !UCONFIG_NO_FORMATTING */
static UnicodeString& U_EXPORT2 getCanonicalID(const UnicodeString& id,
UnicodeString& canonicalID, UBool& isSystemID, UErrorCode& status);
+#ifndef U_HIDE_DRAFT_API
+ /**
+ * Converts a system time zone ID to an equivalent Windows time zone ID. For example,
+ * Windows time zone ID "Pacific Standard Time" is returned for input "America/Los_Angeles".
+ *
+ * <p>There are system time zones that cannot be mapped to Windows zones. When the input
+ * system time zone ID is unknown or unmappable to a Windows time zone, then the result will be
+ * empty, but the operation itself remains successful (no error status set on return).
+ *
+ * <p>This implementation utilizes <a href="http://unicode.org/cldr/charts/supplemental/zone_tzid.html">
+ * Zone-Tzid mapping data</a>. The mapping data is updated time to time. To get the latest changes,
+ * please read the ICU user guide section <a href="http://userguide.icu-project.org/datetime/timezone#TOC-Updating-the-Time-Zone-Data">
+ * Updating the Time Zone Data</a>.
+ *
+ * @param id A system time zone ID.
+ * @param winid Receives a Windows time zone ID. When the input system time zone ID is unknown
+ * or unmappable to a Windows time zone ID, then an empty string is set on return.
+ * @param status Receives the status.
+ * @return A reference to the result (<code>winid</code>).
+ * @see getIDForWindowsID
+ *
+ * @draft ICU 52
+ */
+ static UnicodeString& U_EXPORT2 getWindowsID(const UnicodeString& id,
+ UnicodeString& winid, UErrorCode& status);
+
+ /**
+ * Converts a Windows time zone ID to an equivalent system time zone ID
+ * for a region. For example, system time zone ID "America/Los_Angeles" is returned
+ * for input Windows ID "Pacific Standard Time" and region "US" (or <code>null</code>),
+ * "America/Vancouver" is returned for the same Windows ID "Pacific Standard Time" and
+ * region "CA".
+ *
+ * <p>Not all Windows time zones can be mapped to system time zones. When the input
+ * Windows time zone ID is unknown or unmappable to a system time zone, then the result
+ * will be empty, but the operation itself remains successful (no error status set on return).
+ *
+ * <p>This implementation utilizes <a href="http://unicode.org/cldr/charts/supplemental/zone_tzid.html">
+ * Zone-Tzid mapping data</a>. The mapping data is updated time to time. To get the latest changes,
+ * please read the ICU user guide section <a href="http://userguide.icu-project.org/datetime/timezone#TOC-Updating-the-Time-Zone-Data">
+ * Updating the Time Zone Data</a>.
+ *
+ * @param winid A Windows time zone ID.
+ * @param region A null-terminated region code, or <code>NULL</code> if no regional preference.
+ * @param id Receives a system time zone ID. When the input Windows time zone ID is unknown
+ * or unmappable to a system time zone ID, then an empty string is set on return.
+ * @param status Receives the status.
+ * @return A reference to the result (<code>id</code>).
+ * @see getWindowsID
+ *
+ * @draft ICU 52
+ */
+ static UnicodeString& U_EXPORT2 getIDForWindowsID(const UnicodeString& winid, const char* region,
+ UnicodeString& id, UErrorCode& status);
+
+#endif /* U_HIDE_DRAFT_API */
+
/**
* Returns true if the two TimeZones are equal. (The TimeZone version only compares
* IDs, but subclasses are expected to also compare the fields they add.)
#endif /* U_HIDE_DRAFT_API */
+#ifndef U_HIDE_DRAFT_API
+/**
+* Converts a system time zone ID to an equivalent Windows time zone ID. For example,
+* Windows time zone ID "Pacific Standard Time" is returned for input "America/Los_Angeles".
+*
+* <p>There are system time zones that cannot be mapped to Windows zones. When the input
+* system time zone ID is unknown or unmappable to a Windows time zone, then this
+* function returns 0 as the result length, but the operation itself remains successful
+* (no error status set on return).
+*
+* <p>This implementation utilizes <a href="http://unicode.org/cldr/charts/supplemental/zone_tzid.html">
+* Zone-Tzid mapping data</a>. The mapping data is updated time to time. To get the latest changes,
+* please read the ICU user guide section <a href="http://userguide.icu-project.org/datetime/timezone#TOC-Updating-the-Time-Zone-Data">
+* Updating the Time Zone Data</a>.
+*
+* @param id A system time zone ID.
+* @param len The length of <code>id</code>, or -1 if null-terminated.
+* @param winid A buffer to receive a Windows time zone ID.
+* @param winidCapacity The capacity of the result buffer <code>winid</code>.
+* @param status Receives the status.
+* @return The result string length, not including the terminating null.
+* @see ucal_getTimeZoneIDForWindowsID
+*
+* @draft ICU 52
+*/
+U_DRAFT int32_t U_EXPORT2
+ucal_getWindowsTimeZoneID(const UChar* id, int32_t len,
+ UChar* winid, int32_t winidCapacity, UErrorCode* status);
+
+/**
+* Converts a Windows time zone ID to an equivalent system time zone ID
+* for a region. For example, system time zone ID "America/Los_Angeles" is returned
+* for input Windows ID "Pacific Standard Time" and region "US" (or <code>null</code>),
+* "America/Vancouver" is returned for the same Windows ID "Pacific Standard Time" and
+* region "CA".
+*
+* <p>Not all Windows time zones can be mapped to system time zones. When the input
+* Windows time zone ID is unknown or unmappable to a system time zone, then this
+* function returns 0 as the result length, but the operation itself remains successful
+* (no error status set on return).
+*
+* <p>This implementation utilizes <a href="http://unicode.org/cldr/charts/supplemental/zone_tzid.html">
+* Zone-Tzid mapping data</a>. The mapping data is updated time to time. To get the latest changes,
+* please read the ICU user guide section <a href="http://userguide.icu-project.org/datetime/timezone#TOC-Updating-the-Time-Zone-Data">
+* Updating the Time Zone Data</a>.
+*
+* @param winid A Windows time zone ID.
+* @param len The length of <code>winid</code>, or -1 if null-terminated.
+* @param region A null-terminated region code, or <code>NULL</code> if no regional preference.
+* @param id A buffer to receive a system time zone ID.
+* @param idCapacity The capacity of the result buffer <code>id</code>.
+* @param status Receives the status.
+* @return The result string length, not including the terminating null.
+* @see ucal_getWindowsTimeZoneID
+*
+* @draft ICU 52
+*/
+U_DRAFT int32_t U_EXPORT2
+ucal_getTimeZoneIDForWindowsID(const UChar* winid, int32_t len, const char* region,
+ UChar* id, int32_t idCapacity, UErrorCode* status);
+
+#endif /* U_HIDE_DRAFT_API */
+
#endif /* #if !UCONFIG_NO_FORMATTING */
#endif
void TestAddRollEra0AndEraBounds(void);
void TestGetTZTransition(void);
+void TestGetWindowsTimeZoneID(void);
+void TestGetTimeZoneIDByWindowsID(void);
+
void addCalTest(TestNode** root);
void addCalTest(TestNode** root)
addTest(root, &TestAmbiguousWallTime, "tsformat/ccaltst/TestAmbiguousWallTime");
addTest(root, &TestAddRollEra0AndEraBounds, "tsformat/ccaltst/TestAddRollEra0AndEraBounds");
addTest(root, &TestGetTZTransition, "tsformat/ccaltst/TestGetTZTransition");
+ addTest(root, &TestGetWindowsTimeZoneID, "tsformat/ccaltst/TestGetWindowsTimeZoneID");
+ addTest(root, &TestGetTimeZoneIDByWindowsID, "tsformat/ccaltst/TestGetTimeZoneIDByWindowsID");
}
/* "GMT" */
}
}
+static const UChar winEastern[] = /* Eastern Standard Time */
+ {0x45,0x61,0x73,0x74,0x65,0x72,0x6E,0x20,0x53,0x74,0x61,0x6E,0x64,0x61,0x72,0x64,0x20,0x54,0x69,0x6D,0x65,0x00};
+
+static const UChar tzNewYork[] = /* America/New_York */
+ {0x41,0x6D,0x65,0x72,0x69,0x63,0x61,0x2F,0x4E,0x65,0x77,0x5F,0x59,0x6F,0x72,0x6B,0x00};
+static const UChar tzTronto[] = /* America/Toronto */
+ {0x41,0x6D,0x65,0x72,0x69,0x63,0x61,0x2F,0x54,0x6F,0x72,0x6F,0x6E,0x74,0x6F,0x00};
+
+static const UChar sBogus[] = /* Bogus */
+ {0x42,0x6F,0x67,0x75,0x73,0x00};
+
+void TestGetWindowsTimeZoneID() {
+ UErrorCode status;
+ UChar winID[64];
+ int32_t len;
+
+ {
+ status = U_ZERO_ERROR;
+ len = ucal_getWindowsTimeZoneID(tzNewYork, u_strlen(tzNewYork), winID, sizeof(winID)/sizeof(winID[0]), &status);
+ if (U_FAILURE(status)) {
+ log_data_err("FAIL: Windows ID for America/New_York, status %s\n", u_errorName(status));
+ } else if (len != u_strlen(winEastern) || u_strncmp(winID, winEastern, len) != 0) {
+ log_err("FAIL: Windows ID for America/New_York\n");
+ }
+ }
+ {
+ status = U_ZERO_ERROR;
+ len = ucal_getWindowsTimeZoneID(tzTronto, u_strlen(tzTronto), winID, sizeof(winID)/sizeof(winID[0]), &status);
+ if (U_FAILURE(status)) {
+ log_data_err("FAIL: Windows ID for America/Toronto, status %s\n", u_errorName(status));
+ } else if (len != u_strlen(winEastern) || u_strncmp(winID, winEastern, len) != 0) {
+ log_err("FAIL: Windows ID for America/Toronto\n");
+ }
+ }
+ {
+ status = U_ZERO_ERROR;
+ len = ucal_getWindowsTimeZoneID(sBogus, u_strlen(sBogus), winID, sizeof(winID)/sizeof(winID[0]), &status);
+ if (U_FAILURE(status)) {
+ log_data_err("FAIL: Windows ID for Bogus, status %s\n", u_errorName(status));
+ } else if (len != 0) {
+ log_err("FAIL: Windows ID for Bogus\n");
+ }
+ }
+}
+
+void TestGetTimeZoneIDByWindowsID() {
+ UErrorCode status;
+ UChar tzID[64];
+ int32_t len;
+
+ {
+ status = U_ZERO_ERROR;
+ len = ucal_getTimeZoneIDForWindowsID(winEastern, -1, NULL, tzID, sizeof(tzID)/sizeof(tzID[0]), &status);
+ if (U_FAILURE(status)) {
+ log_data_err("FAIL: TZ ID for Eastern Standard Time, status %s\n", u_errorName(status));
+ } else if (len != u_strlen(tzNewYork) || u_strncmp(tzID, tzNewYork, len) != 0) {
+ log_err("FAIL: TZ ID for Eastern Standard Time\n");
+ }
+ }
+ {
+ status = U_ZERO_ERROR;
+ len = ucal_getTimeZoneIDForWindowsID(winEastern, u_strlen(winEastern), "US", tzID, sizeof(tzID)/sizeof(tzID[0]), &status);
+ if (U_FAILURE(status)) {
+ log_data_err("FAIL: TZ ID for Eastern Standard Time - US, status %s\n", u_errorName(status));
+ } else if (len != u_strlen(tzNewYork) || u_strncmp(tzID, tzNewYork, len) != 0) {
+ log_err("FAIL: TZ ID for Eastern Standard Time - US\n");
+ }
+ }
+ {
+ status = U_ZERO_ERROR;
+ len = ucal_getTimeZoneIDForWindowsID(winEastern, u_strlen(winEastern), "CA", tzID, sizeof(tzID)/sizeof(tzID[0]), &status);
+ if (U_FAILURE(status)) {
+ log_data_err("FAIL: TZ ID for Eastern Standard Time - CA, status %s\n", u_errorName(status));
+ } else if (len != u_strlen(tzTronto) || u_strncmp(tzID, tzTronto, len) != 0) {
+ log_err("FAIL: TZ ID for Eastern Standard Time - CA\n");
+ }
+ }
+
+ {
+ status = U_ZERO_ERROR;
+ len = ucal_getTimeZoneIDForWindowsID(sBogus, -1, NULL, tzID, sizeof(tzID)/sizeof(tzID[0]), &status);
+ if (U_FAILURE(status)) {
+ log_data_err("FAIL: TZ ID for Bogus, status %s\n", u_errorName(status));
+ } else if (len != 0) {
+ log_err("FAIL: TZ ID for Bogus\n");
+ }
+ }
+}
+
+
#endif /* #if !UCONFIG_NO_FORMATTING */
TESTCASE_AUTO(TestGetRegion);
TESTCASE_AUTO(TestGetAvailableIDsNew);
TESTCASE_AUTO(TestGetUnknown);
+ TESTCASE_AUTO(TestGetWindowsID);
+ TESTCASE_AUTO(TestGetIDForWindowsID);
TESTCASE_AUTO_END;
}
assertFalse("getUnknown() uses DST", unknown.useDaylightTime());
}
+void TimeZoneTest::TestGetWindowsID(void) {
+ static const struct {
+ const char *id;
+ const char *winid;
+ } TESTDATA[] = {
+ {"America/New_York", "Eastern Standard Time"},
+ {"America/Montreal", "Eastern Standard Time"},
+ {"America/Los_Angeles", "Pacific Standard Time"},
+ {"America/Vancouver", "Pacific Standard Time"},
+ {"Asia/Shanghai", "China Standard Time"},
+ {"Asia/Chongqing", "China Standard Time"},
+ {"America/Indianapolis", "US Eastern Standard Time"}, // CLDR canonical name
+ {"America/Indiana/Indianapolis", "US Eastern Standard Time"}, // tzdb canonical name
+ {"Asia/Khandyga", "Yakutsk Standard Time"},
+ {"Australia/Eucla", ""}, // No Windows ID mapping
+ {"Bogus", ""},
+ {0, 0},
+ };
+
+ for (int32_t i = 0; TESTDATA[i].id != 0; i++) {
+ UErrorCode sts = U_ZERO_ERROR;
+ UnicodeString windowsID;
+
+ TimeZone::getWindowsID(UnicodeString(TESTDATA[i].id), windowsID, sts);
+ assertSuccess(TESTDATA[i].id, sts);
+ assertEquals(TESTDATA[i].id, UnicodeString(TESTDATA[i].winid), windowsID);
+ }
+}
+
+void TimeZoneTest::TestGetIDForWindowsID(void) {
+ static const struct {
+ const char *winid;
+ const char *region;
+ const char *id;
+ } TESTDATA[] = {
+ {"Eastern Standard Time", 0, "America/New_York"},
+ {"Eastern Standard Time", "US", "America/New_York"},
+ {"Eastern Standard Time", "CA", "America/Toronto"},
+ {"Eastern Standard Time", "CN", "America/New_York"},
+ {"China Standard Time", 0, "Asia/Shanghai"},
+ {"China Standard Time", "CN", "Asia/Shanghai"},
+ {"China Standard Time", "HK", "Asia/Hong_Kong"},
+ {"Mid-Atlantic Standard Time", 0, ""}, // No tz database mapping
+ {"Bogus", 0, ""},
+ {0, 0, 0},
+ };
+
+ for (int32_t i = 0; TESTDATA[i].winid != 0; i++) {
+ UErrorCode sts = U_ZERO_ERROR;
+ UnicodeString id;
+
+ TimeZone::getIDForWindowsID(UnicodeString(TESTDATA[i].winid), TESTDATA[i].region,
+ id, sts);
+ assertSuccess(UnicodeString(TESTDATA[i].winid) + "/" + TESTDATA[i].region, sts);
+ assertEquals(UnicodeString(TESTDATA[i].winid) + "/" + TESTDATA[i].region, TESTDATA[i].id, id);
+ }
+}
+
#endif /* #if !UCONFIG_NO_FORMATTING */
/********************************************************************
- * Copyright (c) 1997-2011, International Business Machines
+ * Copyright (c) 1997-2013, International Business Machines
* Corporation and others. All Rights Reserved.
********************************************************************/
void TestGetRegion(void);
void TestGetUnknown();
+ void TestGetWindowsID(void);
+ void TestGetIDForWindowsID(void);
+
static const UDate INTERVAL;
private: