采用12小时制(AM/PM)的用户无法查看24小时制设备创建的时间问题
问题场景
- 应用内用户选择日期后,该日期会在另一用户手机的底部弹窗(bottom sheet)中显示
- 双方设备均为12小时制(土耳其地区用ÖÖ/ÖS对应AM/PM)时,无任何问题
- 12小时制设备向24小时制设备发送时间,可正常显示
- 24小时制设备向12小时制设备发送时间时,对方无法查看时间,函数返回nil
代码问题分析
当前utcTime函数存在3个核心问题导致解析失败:
- 日期格式判断逻辑错误:用
dateStr.last == "M"判断是否为12小时制字符串,完全不具备通用性,无法准确识别输入格式 - AM/PM符号设置混乱:根据输入字符串是否包含ÖÖ/ÖS来动态设置符号,会干扰24小时制字符串的解析过程
- 解析与格式化逻辑耦合:将输入解析、时区转换、设备格式适配混在同一流程中,容易出现分支判断漏洞
修复方案
核心思路:先统一解析输入字符串为Date对象,再根据当前设备的时区和格式要求生成输出,同时针对性适配土耳其地区的AM/PM符号。
func utcTime(dateStr: String) -> String? { let parser = DateFormatter() parser.timeZone = TimeZone(abbreviation: "UTC") // 尝试解析土耳其12小时制格式(带ÖÖ/ÖS) parser.dateFormat = "yyyy-MM-dd a h:mm:ss" parser.amSymbol = "ÖÖ" parser.pmSymbol = "ÖS" if let date = parser.date(from: dateStr) { return formatForCurrentDevice(date: date) } // 尝试解析通用12小时制格式(带AM/PM) parser.amSymbol = "AM" parser.pmSymbol = "PM" if let date = parser.date(from: dateStr) { return formatForCurrentDevice(date: date) } // 尝试解析24小时制格式 parser.dateFormat = "yyyy-MM-dd HH:mm:ss" if let date = parser.date(from: dateStr) { return formatForCurrentDevice(date: date) } return nil } // 辅助函数:根据当前设备格式格式化日期 private func formatForCurrentDevice(date: Date) -> String { let formatter = DateFormatter() formatter.timeZone = TimeZone.current let is12HourFormat = DateFormatter.dateFormat(fromTemplate: "j", options: 0, locale: Locale.current)?.range(of: "a") != nil if is12HourFormat { formatter.dateFormat = "yyyy-MM-dd h:mm:ss a" // 适配土耳其地区的AM/PM符号 if Locale.current.identifier.hasPrefix("tr") { formatter.amSymbol = "ÖÖ" formatter.pmSymbol = "ÖS" } } else { formatter.dateFormat = "yyyy-MM-dd HH:mm:ss" } return formatter.string(from: date) }
修复说明
- 分阶段解析输入:依次尝试三种常见格式,确保任何合法输入都能被解析为
Date对象,避免单一判断逻辑的漏洞 - 分离解析与格式化:将输入解析和设备格式适配拆分为两个独立函数,逻辑更清晰,便于维护
- 精准适配地区符号:仅在当前设备为12小时制且是土耳其地区时,才使用ÖÖ/ÖS符号,避免符号设置干扰解析
- 鲁棒的格式判断:用系统API判断当前设备的时间格式,替代自定义的不可靠判断逻辑
内容的提问来源于stack exchange,提问作者Miaperolla
相关产品推荐
相关产品推荐

