iOS11+禁用24小时制时Swift字符串转日期失败求助
问题分析与解决方案
没错,你猜的完全正确——问题的核心就是没有强制DateFormatter忽略用户的系统时间格式偏好,严格按照24小时制解析字符串,而iOS 11及以上版本对日期格式化的逻辑做了调整,导致用户关闭24小时制时,你的代码解析失效。
为什么iOS 11+才会出问题?
在iOS 11之前,DateFormatter对自定义dateFormat的优先级更高,即使用户设置了12小时制,它也会尽量匹配你指定的HHmm(24小时制小时格式)规则。但iOS 11及以后,系统更严格地遵循用户的时间格式偏好,当用户禁用24小时制时,HH这个格式符会被系统忽略,自然就解析失败了。
解决办法:强制使用24小时制解析
有两种可靠的方式解决这个问题,你可以根据需求选择:
方式一:给fr_FR区域设置强制启用24小时制
如果你需要保留fr_FR的区域特性(比如日期显示的语言等),可以修改Locale的配置,强制它使用24小时制,忽略用户系统设置:
let dateTimeFormatter = DateFormatter() // 创建基于fr_FR的Locale,并强制开启24小时制 var locale = Locale(identifier: "fr_FR") // 通过设置hourCycle为h23,强制使用24小时制(h23代表0-23的小时格式) let localeComponents = Locale.components(fromIdentifier: "fr_FR") .merging([NSLocale.Key.hourCycle.rawValue: "h23"]) { $1 } locale = Locale(identifier: Locale.identifier(fromComponents: localeComponents)) dateTimeFormatter.locale = locale dateTimeFormatter.timeZone = TimeZone.autoupdatingCurrent dateTimeFormatter.dateFormat = "yyyyMMdd HHmm" if let date = dateTimeFormatter.date(from: date + " " + beginHour) { // 处理解析后的日期 }
方式二:使用POSIX Locale(更推荐)
如果只是要解析服务端返回的标准化日期字符串,不需要依赖fr_FR的区域特性,直接使用POSIX Locale是最稳妥的选择——它完全不受用户系统设置影响,会严格按照你指定的dateFormat解析:
let dateTimeFormatter = DateFormatter() // POSIX Locale是标准化的,忽略任何用户偏好 dateTimeFormatter.locale = Locale(identifier: "en_US_POSIX") dateTimeFormatter.timeZone = TimeZone.autoupdatingCurrent dateTimeFormatter.dateFormat = "yyyyMMdd HHmm" if let date = dateTimeFormatter.date(from: date + " " + beginHour) { // 处理解析后的日期 }
补充说明
服务端返回的2359这种格式是标准的24小时制时间,所以我们必须确保解析器不受用户本地设置干扰,以上两种方式都能让你的代码在iOS 11及以上版本,无论用户是否开启24小时制,都能正常解析日期。
内容的提问来源于stack exchange,提问作者Florian Mac Langlade
相关产品推荐
相关产品推荐

