Repository navigation
Build TimeZone.abbreviationDictionary on first use - #136
Merged
piercifani merged 1 commit intoOct 19, 2026
Merged
Conversation
On Android a stored static's initializer runs when the class loads, so the walk over every known zone ran the first time anything touched TimeZone. UserDefaults does that during its own static init, putting the walk on the main thread at app launch. Build and cache the dictionary on first read instead; assigning it still replaces it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
#95 added
TimeZone.abbreviationDictionaryas a storedstatic varwith an initializer that walks every known zone and asks ICU for its short standard and daylight names. In Swift that initializer is lazy. On Android it becomes part of theTimeZoneclass initializer, so the walk runs the first time anything touchesTimeZone, whether or not abbreviations are ever used.UserDefaultstouches it during its own static init (UserDefaults→ISO8601DateFormatter→TimeZone), so in practice the walk runs on the main thread at app launch, usually as the app's firstUserDefaultsread:abbreviationDictionaryis now a computed property backed by a cache. It's built the first time it's read, which in practice meansTimeZone(abbreviation:). The public API is unchanged: reads return the same dictionary, and assigning it still replaces it. The cache isn't synchronized, so concurrent first reads may each build the same dictionary, which is harmless.Measurements
A production Skip Fuse app on a low-end Android 14 device (Redmi 10 5G, 4 GB RAM), cold starts with a main-thread stall watchdog (stalls over 250 ms), 5–6 runs per build. The two builds are identical apart from this change:
TimeZoneinitam start -W,WaitTime)The ~400 ms difference is the dictionary walk. The rest of that message is app code.
Testing
test_abbreviationDictionaryIsBuiltOnFirstUse(Robolectric): it clears the cache, then creates time zones by identifier and by offset and readsTimeZone.current, and checks that the dictionary hasn't been built yet. ATimeZone(abbreviation:)lookup then builds it.test_abbreviationDictionary,test_abbreviationDictionaryResolvesSystemZones,test_initializingTimeZoneWithAbbreviation,test_initializingTimeZoneWithCustomAbbreviations) pass unchanged.swift test --filter XCSkipTestspasses.Skip Pull Request Checklist:
swift test🤖 Generated with Claude Code