@_implementationOnly import CZoneDetect import Foundation public enum SwiftTimeZoneLookupError: Error { case couldNotFindTimezone21bin case couldNotOpenDatabase } public struct SwiftTimeZoneLookupResult { /// Timezone identifier like `Europe/Berlin` public let timezone: String /// Country name like `Germany` public let countryName: String? /// 2 character country code like `DE` for Germany public let countryAlpha2: String? } public final class SwiftTimeZoneLookup { /// 0.00017 degrees (~20m) resolution private let database21: OpaquePointer /// 0.0055 degrees (~0.5km) resolution private let database16: OpaquePointer /// Throws if the timezone database could not be opened public init() throws { guard let timezone21 = Bundle.module.url(forResource: "timezone21", withExtension: "bin") else { throw SwiftTimeZoneLookupError.couldNotFindTimezone21bin } guard let timezone16 = Bundle.module.url(forResource: "timezone16", withExtension: "bin") else { throw SwiftTimeZoneLookupError.couldNotFindTimezone21bin } guard let database21 = timezone21.withUnsafeFileSystemRepresentation(ZDOpenDatabase) else { throw SwiftTimeZoneLookupError.couldNotOpenDatabase } guard let database16 = timezone16.withUnsafeFileSystemRepresentation(ZDOpenDatabase) else { throw SwiftTimeZoneLookupError.couldNotOpenDatabase } self.database21 = database21 self.database16 = database16 } /// Try with lower resolution first and use high resolution database if too close to the border private func highResLookup(latitude: Float, longitude: Float) -> UnsafeMutablePointer? { var safezone: Float = .nan guard let result = ZDLookup(database16, latitude, longitude, &safezone) else { return nil } if safezone >= 0.0055*2 { return result } guard let result21 = ZDLookup(database21, latitude, longitude, &safezone) else { return nil } return result21 } /// Resolve timezone by coordinate and return timezone, country name and alpha2 public func lookup(latitude: Float, longitude: Float) -> SwiftTimeZoneLookupResult? { guard let result = highResLookup(latitude: latitude, longitude: longitude) else { return nil } defer { ZDFreeResults(result) } var countryName: String? = nil var countryAlpha2: String? = nil var timezoneIdPrefix: UnsafeMutablePointer? = nil var timezoneId: UnsafeMutablePointer? = nil for i in 0.. String? { guard let result = highResLookup(latitude: latitude, longitude: longitude) else { return nil } defer { ZDFreeResults(result) } var timezoneIdPrefix: UnsafeMutablePointer? = nil var timezoneId: UnsafeMutablePointer? = nil for i in 0..