iOS使用DateFormatter转换日期字符串为HH:mm时间结果异常如何解决
问题描述
现有如下带时区偏移的日期字符串:
"date": "2022-06-30T02:15:00.000+07:00"
编写formatTime方法尝试将其转换为HH:mm格式的时间字符串,预期返回结果为09:15,实际返回02:15,相关代码如下:
func formatTime(string: String) -> String { let dateFormatterGet = DateFormatter() dateFormatterGet.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ" let dateFormatterPrint = DateFormatter() dateFormatterPrint.dateFormat = "HH:mm" let date: Date? = dateFormatterGet.date(from: string) return dateFormatterPrint.string(from: date ?? Date()) }
问题原因
- 对ISO8601带时区偏移的时间格式存在认知偏差:格式中后缀的
+07:00表示前面的时间是UTC+7时区的本地时间,UTC标准时间计算规则为本地时间 - 时区偏移,示例字符串对应的UTC时间为2022-06-29 19:15。预期得到09:15,是误将字符串前缀时间当成了UTC时间,认为需要叠加7小时偏移得到UTC+7的本地时间,和ISO8601格式本身的定义冲突。 - 代码缺少
DateFormatter的必要标准配置:解析固定格式时间字符串时,没有设置locale为en_US_POSIX,在默认12小时制、非公历的设备区域下,容易出现解析失败、时间偏移的问题。 - 输出时间未显式指定时区:
DateFormatter默认使用设备当前系统时区,若设备时区恰好为UTC+7,会直接输出字符串内的02:15,无法匹配预期。 - 解析失败的兜底逻辑不合理:当时间解析失败时直接返回当前时间,容易误导问题排查,无法第一时间感知解析异常。
修复方案
如果确认接口返回的字符串实际为UTC时间(即02:15是UTC时间,后缀的+07:00为冗余/错误字段,需要输出UTC+7时区的时间得到09:15),可按如下方式修改代码:
func formatTime(string: String) -> String { let dateFormatterGet = DateFormatter() // 固定区域设置,避免不同设备区域配置导致解析异常 dateFormatterGet.locale = Locale(identifier: "en_US_POSIX") // 强制指定解析时区为UTC,忽略字符串内携带的时区偏移 dateFormatterGet.timeZone = TimeZone(secondsFromGMT: 0) dateFormatterGet.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ" let dateFormatterPrint = DateFormatter() dateFormatterPrint.locale = Locale(identifier: "en_US_POSIX") // 显式指定输出目标时区为UTC+7,即可得到09:15的结果 dateFormatterPrint.timeZone = TimeZone(secondsFromGMT: 7 * 3600) dateFormatterPrint.dateFormat = "HH:mm" guard let date = dateFormatterGet.date(from: string) else { // 解析失败返回空串,避免返回当前时间误导排查 return "" } return dateFormatterPrint.string(from: date) }
补充说明:如果接口返回的字符串符合ISO8601规范(即02:15确实是UTC+7时区的本地时间),则该时间点在全球通用时区下不存在09:15的对应结果,需要先和接口方确认时间数据的正确性,以及业务实际需要转换的目标时区。
内容的提问来源于stack exchange,提问作者Kevin
相关产品推荐
相关产品推荐

