Swift中DateFormatter年份解析控制:区分1977/2077与2009/2109
这个问题我碰到过好多次了——本质是DateFormatter默认的两位年份解析逻辑和你的业务预期不匹配,它默认会以当前年份为中心,取前后50年作为解析的100年窗口,这就导致了你的问题:比如当前是2024年,窗口是1974-2073,所以77落在1974-1999区间被解析成1977,而09落在2000-2073区间被解析成2009,但你想要的是77→2077、09→2009,也就是所有两位年份都映射到2000-2099,或者有自定义的阈值规则。下面给你两种靠谱的解决方案:
方案1:通过twoDigitStartDate自定义解析窗口
DateFormatter提供了twoDigitStartDate属性,用来定义两位年份解析的起始基准,它会自动把两位年份映射到起始基准到起始基准+100年这个100年区间里。如果想让所有两位年份都解析到2000-2099,只需要把起始基准设为2000年1月1日即可:
let dateFormatter = DateFormatter() dateFormatter.dateFormat = "MM/dd/yy" // 设置两位年份解析的起始基准为2000年1月1日 let calendar = Calendar.current var startComponents = DateComponents() startComponents.year = 2000 startComponents.month = 1 startComponents.day = 1 dateFormatter.twoDigitStartDate = calendar.date(from: startComponents) // 测试你的案例 if let date1 = dateFormatter.date(from: "10/01/77") { print(dateFormatter.string(from: date1)) // 输出 "10/01/77",实际解析为2077-10-01 } if let date2 = dateFormatter.date(from: "02/26/09") { print(dateFormatter.string(from: date2)) // 输出 "02/26/09",实际解析为2009-02-26 }
如果你的阈值不是全20xx,比如想让两位年份≥70时映射到2070-2099,<70时映射到2000-2069,那只需要把twoDigitStartDate设为2000年1月1日就行,因为窗口是2000-2099,所有两位年份都会落在这个区间里。
方案2:手动拆分字符串自定义年份规则
如果你需要更灵活的逻辑(比如不同业务场景有不同的年份阈值),可以手动拆分日期字符串,自己补全四位年份后再解析,完全不受系统默认规则限制:
func parseCustomDate(_ dateString: String) -> Date? { let formatter = DateFormatter() formatter.dateFormat = "MM/dd/yyyy" formatter.isLenient = false // 关闭宽松解析,严格验证日期有效性 // 拆分日期字符串 let dateParts = dateString.components(separatedBy: "/") guard dateParts.count == 3, let month = Int(dateParts[0]), let day = Int(dateParts[1]), let twoDigitYear = Int(dateParts[2]) else { return nil } // 自定义年份补全规则:这里是所有两位年份都补为20xx let fourDigitYear = 2000 + twoDigitYear // 如果需要其他规则,比如:twoDigitYear >= 70 ? 2000 + twoDigitYear : 1900 + twoDigitYear // 可以直接修改上面的逻辑 // 组装成带四位年份的日期字符串 let fullDateString = String(format: "%02d/%02d/%04d", month, day, fourDigitYear) return formatter.date(from: fullDateString) } // 测试 if let date1 = parseCustomDate("10/01/77") { print(date1) // 输出 2077-10-01 00:00:00 +0000 } if let date2 = parseCustomDate("02/26/09") { print(date2) // 输出 2009-02-26 00:00:00 +0000 }
注意事项
twoDigitStartDate是iOS 9.0+/macOS 10.11+才支持的API,如果你的项目需要兼容更低版本,建议用方案2。- 不管用哪种方案,都可以设置
formatter.isLenient = false来严格验证日期有效性,避免02/30这种无效日期被自动修正为有效日期。
内容的提问来源于stack exchange,提问作者as diu
相关产品推荐
相关产品推荐

