Skip to content

Commit 7d30dea

Browse files
committed
Use _TimeZoneGMTICU for timezones whose identifier take the form of "GMT/UTC+<offset>" such as "GMT+8" for performance reasons.
Also update to uatimezone API for localizing names. 166054881
1 parent 3a0ea83 commit 7d30dea

File tree

3 files changed

+25
-17
lines changed

3 files changed

+25
-17
lines changed

Sources/FoundationEssentials/TimeZone/TimeZone_Cache.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,10 @@ struct TimeZoneCache : Sendable, ~Copyable {
227227
return offsetFixed(0)
228228
} else if let cached = fixedTimeZones[identifier] {
229229
return cached
230+
} else if let innerTZ = _timeZoneGMTClass().init(identifier: identifier) {
231+
// Identifier takes a form of GMT offset such as "GMT+8"
232+
fixedTimeZones[identifier] = innerTZ
233+
return innerTZ
230234
} else {
231235
if let innerTz = _timeZoneICUClass()?.init(identifier: identifier) {
232236
fixedTimeZones[identifier] = innerTz

Sources/FoundationEssentials/TimeZone/TimeZone_GMT.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,12 @@ package final class _TimeZoneGMT : _TimeZoneProtocol, @unchecked Sendable {
1515
let name: String
1616

1717
required package init?(identifier: String) {
18-
fatalError("Unexpected init")
18+
guard let offset = TimeZone.tryParseGMTName(identifier), let offsetName = TimeZone.nameForSecondsFromGMT(offset) else {
19+
return nil
20+
}
21+
22+
self.name = offsetName
23+
self.offset = offset
1924
}
2025

2126
required package init?(secondsFromGMT: Int) {

Sources/FoundationInternationalization/TimeZone/TimeZone_GMTICU.swift

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,15 @@ private func _timeZoneGMTClass_localized() -> _TimeZoneProtocol.Type {
2626
internal final class _TimeZoneGMTICU : _TimeZoneProtocol, @unchecked Sendable {
2727
let offset: Int
2828
let name: String
29-
29+
30+
// Allow using this class to represent time zone whose names take form of "GMT+<offset>" such as "GMT+8".
3031
init?(identifier: String) {
31-
fatalError("Unexpected init")
32+
guard let offset = TimeZone.tryParseGMTName(identifier), let offsetName = TimeZone.nameForSecondsFromGMT(offset) else {
33+
return nil
34+
}
35+
36+
self.name = offsetName
37+
self.offset = offset
3238
}
3339

3440
init?(secondsFromGMT: Int) {
@@ -79,29 +85,22 @@ internal final class _TimeZoneGMTICU : _TimeZoneProtocol, @unchecked Sendable {
7985
default: false
8086
}
8187

82-
// TODO: Consider using ICU C++ API instead of a date formatter here
88+
// TODO: Consider implementing this ourselves
8389
let timeZoneIdentifier = Array(name.utf16)
8490
let result: String? = timeZoneIdentifier.withUnsafeBufferPointer {
8591
var status = U_ZERO_ERROR
86-
guard let df = udat_open(UDAT_NONE, UDAT_NONE, locale?.identifier ?? "", $0.baseAddress, Int32($0.count), nil, 0, &status) else {
87-
return nil
92+
let tz = uatimezone_open($0.baseAddress, Int32($0.count), &status)
93+
defer {
94+
uatimezone_close(tz)
8895
}
89-
9096
guard status.isSuccess else {
9197
return nil
9298
}
9399

94-
defer { udat_close(df) }
95-
96-
let pattern = "vvvv"
97-
let patternUTF16 = Array(pattern.utf16)
98-
return patternUTF16.withUnsafeBufferPointer {
99-
udat_applyPattern(df, UBool.false, $0.baseAddress, Int32(isShort ? 1 : $0.count))
100-
101-
return _withResizingUCharBuffer { buffer, size, status in
102-
udat_format(df, ucal_getNow(), buffer, size, nil, &status)
103-
}
100+
let result: String? = _withResizingUCharBuffer { buffer, size, status in
101+
uatimezone_getDisplayName(tz, isShort ? UTIMEZONE_SHORT: UTIMEZONE_LONG, locale?.identifier ?? "", buffer, size, &status)
104102
}
103+
return result
105104
}
106105

107106
return result

0 commit comments

Comments
 (0)