Adjust tzset() implementation to better follow the POSIX specs and

make some more perl tests happy.
* no longer expect a ICU timezone ID in the TZ environment variable,
  but only expect this format if the TZ-value is starting with ':'
* accept "standard" TZ-values like "EST5" (of which only "EST" is
  relevant to us) - if such a value is specified, we hardcode the
  timezone name to the given value, no matter how ICU calls it
* adjust tests accordingly


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@39415 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Oliver Tappe
2010-11-13 01:13:38 +00:00
parent 2dfeefba17
commit de2e54ace0
7 changed files with 117 additions and 54 deletions
@@ -45,7 +45,7 @@ public:
virtual status_t Strxfrm(char* out, const char* in, size_t size,
size_t& outSize);
virtual status_t TZSet(const char* timeZoneID);
virtual status_t TZSet(const char* timeZoneID, const char* tz);
virtual status_t Localtime(const time_t* inTime,
struct tm* tmOut);
virtual status_t Gmtime(const time_t* inTime, struct tm* tmOut);
@@ -25,7 +25,7 @@ public:
virtual void Initialize(
TimeConversionDataBridge* dataBridge);
status_t TZSet(const char* timeZoneID);
status_t TZSet(const char* timeZoneID, const char* tz);
status_t Localtime(const time_t* inTime,
struct tm* tmOut);
@@ -127,7 +127,8 @@ public:
virtual status_t Strxfrm(char* out, const char* in, size_t size,
size_t& outSize) = 0;
virtual status_t TZSet(const char* timeZoneID) = 0;
virtual status_t TZSet(const char* timeZoneID,
const char* tz) = 0;
virtual status_t Localtime(const time_t* inTime,
struct tm* tmOut) = 0;
virtual status_t Gmtime(const time_t* inTime,
@@ -245,11 +245,11 @@ ICULocaleBackend::Strxfrm(char* out, const char* in, size_t size,
status_t
ICULocaleBackend::TZSet(const char* timeZoneID)
ICULocaleBackend::TZSet(const char* timeZoneID, const char* tz)
{
ErrnoMaintainer errnoMaintainer;
return fTimeConversion.TZSet(timeZoneID);
return fTimeConversion.TZSet(timeZoneID, tz);
}
@@ -39,13 +39,41 @@ ICUTimeConversion::Initialize(TimeConversionDataBridge* dataBridge)
status_t
ICUTimeConversion::TZSet(const char* timeZoneID)
ICUTimeConversion::TZSet(const char* timeZoneID, const char* tz)
{
// nothing to do if the given name matches any name of the current timezone
if (strcasecmp(fTimeZoneID, timeZoneID) == 0)
return B_OK;
// The given TZ environment variable's content overrides the default
// system timezone.
if (tz != NULL) {
// If the value given in the TZ env-var starts with a colon, that
// value is implementation specific, we expect a full timezone ID.
if (*tz == ':') {
// nothing to do if the given name matches the current timezone
if (strcasecmp(fTimeZoneID, tz + 1) == 0)
return B_OK;
strlcpy(fTimeZoneID, timeZoneID, sizeof(fTimeZoneID));
strlcpy(fTimeZoneID, tz + 1, sizeof(fTimeZoneID));
} else {
// We ignore anything following the timezone name, as those values
// are determined by the corresponding ICU-timezone (and glibc's
// tzset() implementation seems to do the same).
const char* tzNameEnd = tz;
while(isalpha(*tzNameEnd))
++tzNameEnd;
strlcpy(fTimeZoneID, tz,
min_c((uint32)(1 + tzNameEnd - tz), sizeof(fTimeZoneID)));
// nothing to do if the given name matches the current timezone
if (strcasecmp(fTimeZoneID, fDataBridge->addrOfTZName[0]) == 0)
return B_OK;
}
} else {
// nothing to do if the given name matches the current timezone
if (strcasecmp(fTimeZoneID, timeZoneID) == 0)
return B_OK;
strlcpy(fTimeZoneID, timeZoneID, sizeof(fTimeZoneID));
}
ObjectDeleter<TimeZone> icuTimeZone = TimeZone::createTimeZone(fTimeZoneID);
if (icuTimeZone.Get() == NULL)
@@ -71,16 +99,20 @@ ICUTimeConversion::TZSet(const char* timeZoneID)
*fDataBridge->addrOfDaylight = icuTimeZone->useDaylightTime();
for (int i = 0; i < 2; ++i) {
UnicodeString icuString;
icuTimeZone->getDisplayName(i == 1, TimeZone::SHORT_COMMONLY_USED,
fTimeData.ICULocale(), icuString);
CheckedArrayByteSink byteSink(fDataBridge->addrOfTZName[i],
sizeof(fTimeZoneID));
icuString.toUTF8(byteSink);
if (tz != NULL && *tz != ':' && i == 0) {
strcpy(fDataBridge->addrOfTZName[0], fTimeZoneID);
} else {
UnicodeString icuString;
icuTimeZone->getDisplayName(i == 1, TimeZone::SHORT_COMMONLY_USED,
fTimeData.ICULocale(), icuString);
CheckedArrayByteSink byteSink(fDataBridge->addrOfTZName[i],
sizeof(fTimeZoneID));
icuString.toUTF8(byteSink);
// make sure to canonicalize "GMT+00:00" to just "GMT"
if (strcmp(fDataBridge->addrOfTZName[i], "GMT+00:00") == 0)
fDataBridge->addrOfTZName[i][3] = '\0';
// make sure to canonicalize "GMT+00:00" to just "GMT"
if (strcmp(fDataBridge->addrOfTZName[i], "GMT+00:00") == 0)
fDataBridge->addrOfTZName[i][3] = '\0';
}
}
return B_OK;
+2 -8
View File
@@ -39,15 +39,9 @@ tzset(void)
return;
char timeZoneID[B_FILE_NAME_LENGTH] = { "GMT" };
_kern_get_timezone(NULL, timeZoneID, sizeof(timeZoneID));
const char* tz = getenv("TZ");
if (tz != NULL)
strlcpy(timeZoneID, tz, sizeof(timeZoneID));
else
_kern_get_timezone(NULL, timeZoneID, sizeof(timeZoneID));
if (gLocaleBackend != NULL)
gLocaleBackend->TZSet(timeZoneID);
gLocaleBackend->TZSet(timeZoneID, getenv("TZ"));
}
+63 -27
View File
@@ -1819,30 +1819,42 @@ test_timeconversions()
gtm.tm_wday = -1;
gtm.tm_yday = -1;
test_mktime("GMT", gtm, testTime, 6, 197);
tm btm = {
9, 26, 20, 17, 6, 110, 6, 197, 1, 2 * 3600, (char*)"CEST"
};
test_localtime("Europe/Berlin", testTime, btm);
test_gmtime("Europe/Berlin", testTime, gtm);
test_localtime(":Europe/Berlin", testTime, btm);
test_gmtime(":Europe/Berlin", testTime, gtm);
btm.tm_wday = -1;
btm.tm_yday = -1;
test_mktime("Europe/Berlin", btm, testTime, 6, 197);
test_mktime(":Europe/Berlin", btm, testTime, 6, 197);
tm ctm = {
9, 26, 20, 17, 6, 110, 6, 197, 1, 2 * 3600, (char*)"CEST"
};
test_localtime("CET", testTime, ctm);
test_gmtime("CET", testTime, gtm);
ctm.tm_wday = -1;
ctm.tm_yday = -1;
test_mktime("CET", ctm, testTime, 6, 197);
tm latm = {
9, 26, 11, 17, 6, 110, 6, 197, 1, -7 * 3600, (char*)"PDT"
};
test_localtime("America/Los_Angeles", testTime, latm);
test_gmtime("America/Los_Angeles", testTime, gtm);
test_localtime(":America/Los_Angeles", testTime, latm);
test_gmtime(":America/Los_Angeles", testTime, gtm);
latm.tm_wday = -1;
latm.tm_yday = -1;
test_mktime("America/Los_Angeles", latm, testTime, 6, 197);
test_mktime(":America/Los_Angeles", latm, testTime, 6, 197);
tm ttm = {
9, 26, 3, 18, 6, 110, 0, 198, 0, 9 * 3600, (char*)"JST"
};
test_localtime("Asia/Tokyo", testTime, ttm);
test_gmtime("Asia/Tokyo", testTime, gtm);
test_localtime(":Asia/Tokyo", testTime, ttm);
test_gmtime(":Asia/Tokyo", testTime, gtm);
ttm.tm_wday = -1;
ttm.tm_yday = -1;
test_mktime("Asia/Tokyo", ttm, testTime, 0, 198);
test_mktime(":Asia/Tokyo", ttm, testTime, 0, 198);
}
{
@@ -1855,30 +1867,42 @@ test_timeconversions()
gtm.tm_wday = -1;
gtm.tm_yday = -1;
test_mktime("GMT", gtm, testTime, 2, 67);
tm btm = {
9, 26, 19, 9, 2, 110, 2, 67, 0, 3600, (char*)"CET"
};
test_localtime("Europe/Berlin", testTime, btm);
test_gmtime("Europe/Berlin", testTime, gtm);
test_localtime(":Europe/Berlin", testTime, btm);
test_gmtime(":Europe/Berlin", testTime, gtm);
btm.tm_wday = -1;
btm.tm_yday = -1;
test_mktime("Europe/Berlin", btm, testTime, 2, 67);
test_mktime(":Europe/Berlin", btm, testTime, 2, 67);
tm ctm = {
9, 26, 19, 9, 2, 110, 2, 67, 0, 3600, (char*)"CET"
};
test_localtime("CET", testTime, ctm);
test_gmtime("CET", testTime, gtm);
ctm.tm_wday = -1;
ctm.tm_yday = -1;
test_mktime("CET", ctm, testTime, 2, 67);
tm latm = {
9, 26, 10, 9, 2, 110, 2, 67, 0, -8 * 3600, (char*)"PST"
};
test_localtime("America/Los_Angeles", testTime, latm);
test_gmtime("America/Los_Angeles", testTime, gtm);
test_localtime(":America/Los_Angeles", testTime, latm);
test_gmtime(":America/Los_Angeles", testTime, gtm);
latm.tm_wday = -1;
latm.tm_yday = -1;
test_mktime("America/Los_Angeles", latm, testTime, 2, 67);
test_mktime(":America/Los_Angeles", latm, testTime, 2, 67);
tm ttm = {
9, 26, 3, 10, 2, 110, 3, 68, 0, 9 * 3600, (char*)"JST"
};
test_localtime("Asia/Tokyo", testTime, ttm);
test_gmtime("Asia/Tokyo", testTime, gtm);
test_localtime(":Asia/Tokyo", testTime, ttm);
test_gmtime(":Asia/Tokyo", testTime, gtm);
ttm.tm_wday = -1;
ttm.tm_yday = -1;
test_mktime("Asia/Tokyo", ttm, testTime, 3, 68);
test_mktime(":Asia/Tokyo", ttm, testTime, 3, 68);
}
{
@@ -1891,30 +1915,42 @@ test_timeconversions()
gtm.tm_wday = -1;
gtm.tm_yday = -1;
test_mktime("GMT", gtm, testTime, 4, 0);
tm btm = {
0, 0, 1, 1, 0, 70, 4, 0, 0, 1 * 3600, (char*)"CET"
};
test_localtime("Europe/Berlin", testTime, btm);
test_gmtime("Europe/Berlin", testTime, gtm);
test_localtime(":Europe/Berlin", testTime, btm);
test_gmtime(":Europe/Berlin", testTime, gtm);
btm.tm_wday = -1;
btm.tm_yday = -1;
test_mktime("Europe/Berlin", btm, testTime, 4, 0);
test_mktime(":Europe/Berlin", btm, testTime, 4, 0);
tm ctm = {
0, 0, 1, 1, 0, 70, 4, 0, 0, 1 * 3600, (char*)"CET"
};
test_localtime("CET", testTime, ctm);
test_gmtime("CET", testTime, gtm);
ctm.tm_wday = -1;
ctm.tm_yday = -1;
test_mktime("CET", ctm, testTime, 4, 0);
tm latm = {
0, 0, 16, 31, 11, 69, 3, 364, 0, -8 * 3600, (char*)"PST"
};
test_localtime("America/Los_Angeles", testTime, latm);
test_gmtime("America/Los_Angeles", testTime, gtm);
test_localtime(":America/Los_Angeles", testTime, latm);
test_gmtime(":America/Los_Angeles", testTime, gtm);
latm.tm_wday = -1;
latm.tm_yday = -1;
test_mktime("America/Los_Angeles", latm, testTime, 3, 364);
test_mktime(":America/Los_Angeles", latm, testTime, 3, 364);
tm ttm = {
0, 0, 9, 1, 0, 70, 4, 0, 0, 9 * 3600, (char*)"JST"
};
test_localtime("Asia/Tokyo", testTime, ttm);
test_gmtime("Asia/Tokyo", testTime, gtm);
test_localtime(":Asia/Tokyo", testTime, ttm);
test_gmtime(":Asia/Tokyo", testTime, gtm);
ttm.tm_wday = -1;
ttm.tm_yday = -1;
test_mktime("Asia/Tokyo", ttm, testTime, 4, 0);
test_mktime(":Asia/Tokyo", ttm, testTime, 4, 0);
}
}