iOS切换部分地区时24小时制时间开关被忽略问题及解决方案
问题原因
你遇到的部分地区24小时制开关不生效的问题,根源是setLocalizedDateFormatFromTemplate API的设计逻辑:该API生成格式化规则时,会优先匹配当前地区(Locale)的默认本地化时间惯例,而非完全遵循用户的系统24小时制开关设置。
日本、法国这类地区的系统Locale默认配置中,12小时制的优先级高于用户手动设置的24小时开关,因此不管用户怎么调整开关,该API返回的格式化规则始终是12小时制;而美国、印度等地区的Locale配置会优先读取用户的24小时制开关状态,因此表现符合预期。
地区与时间格式的关联
二者存在直接关联:每个地区对应的Locale配置中,预置了当地通用的时间显示惯例、日期排版规则、数字展示格式等本地化参数,所有苹果官方的本地化格式化API都会优先适配对应地区的使用习惯,部分地区的默认惯例权重高于用户的个性化开关设置,就会出现你观测到的地区差异化表现。
解决方案
你可以先主动读取用户设备的24小时制开关状态,再按需生成对应的时间格式,即可规避setLocalizedDateFormatFromTemplate的地区适配问题,同时完全遵循用户的设备设置,不会强制固定24小时制。
步骤1:添加24小时制状态判断逻辑
var isTwentyFourHourTimeSet: Bool { let formatString = DateFormatter.dateFormat(fromTemplate: "j", options: 0, locale: Locale.current)! return !formatString.contains("a") }
说明:模板
j是苹果官方专门提供的、用于查询当前Locale下小时制规则的专用模板,返回的格式字符串中如果包含a(代表上午/下午标记),就说明当前是12小时制。
步骤2:修改时间格式化方法
根据读取到的小时制状态,显式指定匹配的格式模板即可,修改后代码如下:
func formattedCloseTime(for date: DateTimeZone) -> String { let formatter = dateProvider.formatter formatter.timeZone = date.timeZone formatter.locale = .autoupdatingCurrent let stopTimeMinutes = dateProvider.minutesOfDay(from: date.value, timeZone: date.timeZone) // 先判断用户的24小时制开关状态 let hourFormatTemplate: String if isTwentyFourHourTimeSet { hourFormatTemplate = stopTimeMinutes == 0 ? "HH" : "HH:mm" } else { hourFormatTemplate = stopTimeMinutes == 0 ? "h" : "h:mm" } formatter.setLocalizedDateFormatFromTemplate(hourFormatTemplate) return formatter.string(from: date.value) }
注意:如果你的项目中
Constants.DateFormat已经定义了对应的12/24小时制模板,可以直接替换上面的硬编码模板值。
内容的提问来源于stack exchange,提问作者tejasree vangapalli

