diff --git a/Source/CFTimeZone.c b/Source/CFTimeZone.c index da8a104..6d52eb8 100644 --- a/Source/CFTimeZone.c +++ b/Source/CFTimeZone.c @@ -328,7 +328,29 @@ CFTimeZoneCreateWithName (CFAllocatorRef alloc, CFStringRef name, CFURLRef path; CFDataRef data; CFTimeZoneRef new; - + char cname[16]; + + /* A GMT offset such as GMT+05:00 has no zone file; build it directly. */ + if (CFStringGetCString (name, cname, sizeof (cname), kCFStringEncodingASCII) + && strncmp (cname, "GMT", 3) == 0 + && (cname[3] == '+' || cname[3] == '-')) + { + int sign = (cname[3] == '-') ? -1 : 1; + const char *p = cname + 4; + int hh = 0; + int mm = 0; + + while (*p >= '0' && *p <= '9') + hh = hh * 10 + (*p++ - '0'); + if (*p == ':') + ++p; + while (*p >= '0' && *p <= '9') + mm = mm * 10 + (*p++ - '0'); + + return CFTimeZoneCreateWithTimeIntervalFromGMT (alloc, + sign * (hh * 3600 + mm * 60)); + } + if (tryAbbrev) { CFDictionaryRef abbrevs; diff --git a/Tests/CFTimeZone/gmt.m b/Tests/CFTimeZone/gmt.m new file mode 100644 index 0000000..988497e --- /dev/null +++ b/Tests/CFTimeZone/gmt.m @@ -0,0 +1,43 @@ +#include "CoreFoundation/CFTimeZone.h" +#include "CoreFoundation/CFCalendar.h" +#include "../CFTesting.h" + +/* CFTimeZoneCreateWithName resolves GMT and UTC offset names, so a calendar + whose time zone is a GMT offset can be copied back. */ + +int main (void) +{ + CFTimeZoneRef z0 = CFTimeZoneCreateWithTimeIntervalFromGMT (NULL, 0.0); + CFTimeZoneRef tz; + CFCalendarRef cal; + + tz = CFTimeZoneCreateWithName (NULL, CFSTR ("GMT"), true); + PASS_CF (tz != NULL && CFTimeZoneGetSecondsFromGMT (tz, 0.0) == 0, + "GMT resolves to a zero offset."); + if (tz != NULL) + CFRelease (tz); + + tz = CFTimeZoneCreateWithName (NULL, CFSTR ("UTC"), true); + PASS_CF (tz != NULL && CFTimeZoneGetSecondsFromGMT (tz, 0.0) == 0, + "UTC resolves to a zero offset."); + if (tz != NULL) + CFRelease (tz); + + tz = CFTimeZoneCreateWithName (NULL, CFSTR ("GMT-05:00"), true); + PASS_CF (tz != NULL && CFTimeZoneGetSecondsFromGMT (tz, 0.0) == -18000, + "GMT-05:00 resolves to minus 18000 seconds."); + if (tz != NULL) + CFRelease (tz); + + cal = CFCalendarCreateWithIdentifier (NULL, kCFGregorianCalendar); + CFCalendarSetTimeZone (cal, z0); + tz = CFCalendarCopyTimeZone (cal); + PASS_CF (tz != NULL && CFTimeZoneGetSecondsFromGMT (tz, 0.0) == 0, + "A calendar's GMT time zone can be copied back."); + if (tz != NULL) + CFRelease (tz); + + CFRelease (cal); + CFRelease (z0); + return 0; +}