iOS字符串转Date结果异常:日期差一月/时间差一小时求解
嘿,我来帮你拆解一下你遇到的这两个日期转换坑!你的问题其实源于两个很容易踩的细节:周年份格式YYYY的误用和Date对象的UTC显示特性,下面逐个说清楚:
1. 日期少了一个月?—— 别把YYYY和yyyy搞混!
你最开始的代码里用了"MM/dd/YYYY hh:mm:ss",这里的大写YYYY可不是我们日常用的公历年份!它代表的是基于周的年份(Week-based Year),计算逻辑是从一年的第一周(通常是包含1月4日的那一周)开始算。
举个例子,2018年1月1日其实属于2017年的第52周,如果用YYYY解析,就会得到2017年的日期。你的初始日期是01/24/2018,虽然已经在2018年的周范围内,但YYYY的特性还是导致解析时出现了偏移。正确的日历年格式必须用小写的yyyy,这才是我们熟悉的公历年份。
2. 时间少了一小时?—— 这是UTC和本地时区的显示差异!
你补充代码后打印的2018-01-23 23:48:33 +0000是Date对象的UTC标准时间,而你用toString输出的01/24/2018 12:48:33是当前时区的本地时间(比如你所在时区是UTC+13)。两者其实是同一个时间点,只是时区换算后的结果:
- 本地时间:2018-01-24 12:48:33(UTC+13)
- 转成UTC时间就是:2018-01-23 23:48:33(+0000)
所以这根本不是转换错误,只是Date对象默认打印的是UTC时间,和你的本地时间有偏移而已。你可以把转换后的Date再转回本地时区的字符串,就会发现和原字符串完全一致。
修正后的代码验证
你的补充代码已经把YYYY改成了yyyy,还设置了locale和timeZone,这部分是对的!我给你加了点容错处理(别强制解包,避免崩溃),你可以跑一下测试:
import UIKit extension String { func toDate(dateFormat: String) -> Date? { // 改成可选类型更安全 let dateFormatter = DateFormatter() dateFormatter.dateFormat = dateFormat dateFormatter.timeZone = TimeZone.current dateFormatter.locale = Locale(identifier: "en_US_POSIX") return dateFormatter.date(from: self) } } extension Date { func toString(_ format: String) -> String { let dateFormatter = DateFormatter() dateFormatter.dateFormat = format dateFormatter.timeZone = TimeZone.current dateFormatter.locale = Locale(identifier: "en_US_POSIX") return dateFormatter.string(from: self) } } // 测试转换闭环 let originalDateStr = "01/24/2018 09:59:24" if let convertedDate = originalDateStr.toDate(dateFormat: "MM/dd/yyyy hh:mm:ss") { let convertedBackStr = convertedDate.toString("MM/dd/yyyy hh:mm:ss") print("原字符串:\(originalDateStr)") print("转换后的Date(UTC显示):\(convertedDate)") print("转回字符串:\(convertedBackStr)") } else { print("日期解析失败,请检查格式是否匹配") }
运行后你会看到convertedBackStr和originalDateStr完全一样,说明转换是正确的!
最后再划几个重点
- 日常用公历年份就用
yyyy,YYYY只在处理周相关业务(比如统计周数)时才用。 - 永远别强制解包
dateFormatter.date(from:),万一字符串格式不对,直接崩溃就麻烦了,返回可选类型或者做容错处理更稳妥。 - 设置
locale = Locale(identifier: "en_US_POSIX")是对的,尤其是解析固定格式的字符串时,能避免系统区域设置干扰解析结果。
内容的提问来源于stack exchange,提问作者noname

