From 19af385d6058e106747b58f57d9a4b2a761ba9c5 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Fri, 21 Feb 2020 21:14:43 -0800 Subject: [PATCH] TimeZone: delegate to ICU on Windows Unfortunately, Windows does not have full time zone information available. For many cases we can make do with the system information, augmented with alternate names (the Olson-to-Windows conversion database). This papers over the inability to deserialize the full information in the registry by falling back to ICU to get the information for the DST time conversion. --- .../NumberDate.subproj/CFTimeZone.c | 37 ++++++++++++++++++- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/CoreFoundation/NumberDate.subproj/CFTimeZone.c b/CoreFoundation/NumberDate.subproj/CFTimeZone.c index 6a4acd3d4a..fe87704c3c 100644 --- a/CoreFoundation/NumberDate.subproj/CFTimeZone.c +++ b/CoreFoundation/NumberDate.subproj/CFTimeZone.c @@ -1648,13 +1648,32 @@ CFTimeInterval CFTimeZoneGetSecondsFromGMT(CFTimeZoneRef tz, CFAbsoluteTime at) return __CFTZPeriodGMTOffset(&(tz->_periods[idx])); } +extern UCalendar *__CFCalendarCreateUCalendar(CFStringRef calendarID, CFStringRef localeID, CFTimeZoneRef tz); + CFStringRef CFTimeZoneCopyAbbreviation(CFTimeZoneRef tz, CFAbsoluteTime at) { CFStringRef result; CFIndex idx; __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); +#if TARGET_OS_WIN32 + UErrorCode status = U_ZERO_ERROR; + UCalendar *ucal = __CFCalendarCreateUCalendar(NULL, CFSTR("C"), tz); + if (ucal == NULL) { + return NULL; + } + ucal_setMillis(ucal, (at + kCFAbsoluteTimeIntervalSince1970) * 1000.0, &status); + + UChar buffer[64]; + int32_t length; + length = ucal_getTimeZoneDisplayName(ucal, UCAL_SHORT_STANDARD, "C", buffer, sizeof(buffer), &status); + + ucal_close(ucal); + + return length <= sizeof(buffer) ? CFStringCreateWithCharacters(kCFAllocatorSystemDefault, buffer, length) : NULL; +#else idx = __CFBSearchTZPeriods(tz, at); result = __CFTZPeriodAbbreviation(&(tz->_periods[idx])); return result ? (CFStringRef)CFRetain(result) : NULL; +#endif } Boolean CFTimeZoneIsDaylightSavingTime(CFTimeZoneRef tz, CFAbsoluteTime at) { @@ -1682,15 +1701,29 @@ CFTimeInterval CFTimeZoneGetDaylightSavingTimeOffset(CFTimeZoneRef tz, CFAbsolut CFAbsoluteTime CFTimeZoneGetNextDaylightSavingTimeTransition(CFTimeZoneRef tz, CFAbsoluteTime at) { CF_OBJC_FUNCDISPATCHV(CFTimeZoneGetTypeID(), CFTimeInterval, (NSTimeZone *)tz, _nextDaylightSavingTimeTransitionAfterAbsoluteTime:at); __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); +#if TARGET_OS_WIN32 + UErrorCode status = U_ZERO_ERROR; + UCalendar *ucal = __CFCalendarCreateUCalendar(NULL, CFSTR("C"), tz); + if (ucal == NULL) { + return 0.0; + } + ucal_setMillis(ucal, (at + kCFAbsoluteTimeIntervalSince1970) * 1000.0, &status); + + UDate date; + ucal_getTimeZoneTransitionDate(ucal, UCAL_TZ_TRANSITION_NEXT, &date, &status); + + ucal_close(ucal); + + return (date / 1000.0) - kCFAbsoluteTimeIntervalSince1970; +#else CFIndex idx = __CFBSearchTZPeriods(tz, at); if (tz->_periodCnt <= idx + 1) { return 0.0; } return (CFAbsoluteTime)__CFTZPeriodStartSeconds(&(tz->_periods[idx + 1])); +#endif } -extern UCalendar *__CFCalendarCreateUCalendar(CFStringRef calendarID, CFStringRef localeID, CFTimeZoneRef tz); - #define BUFFER_SIZE 768 CFStringRef CFTimeZoneCopyLocalizedName(CFTimeZoneRef tz, CFTimeZoneNameStyle style, CFLocaleRef locale) {