枚举2018年每月第29日返回结果异常的技术问询
解决Calendar枚举每月指定日期的异常问题
我太懂这个坑了!你遇到的问题其实是Calendar默认的日期滚动逻辑导致的:当你从1月29日调用date(byAdding: .month, value: 1, to: date)时,2018年2月没有29日,Calendar会自动回滚到当月最后一天也就是2月28日。之后再每次加一个月,就会基于2月28日得到3月28日、4月28日……自然再也拿不到29日了,所以最终只有1月29日符合预期。
解决方案1:基于当月1日计算目标日期
这种方法更可靠,先定位到当月1日,再添加28天(每个月至少有28天),然后检查这个日期是否属于当月的29日——如果是就保留,否则跳过(比如2018年2月)。
let calendar = Calendar(identifier: .gregorian) calendar.locale = Locale(identifier: "en_US") calendar.timeZone = TimeZone(identifier: "America/Chicago")! var currentDateComponents = DateComponents(year: 2018, month: 1, day: 1) var validDates: [Date] = [] for month in 1...12 { currentDateComponents.month = month // 先拿到当月1日 guard let firstOfMonth = calendar.date(from: currentDateComponents) else { continue } // 添加28天,得到当月29日(如果存在的话) guard let targetDate = calendar.date(byAdding: .day, value: 28, to: firstOfMonth) else { continue } // 验证这个日期的月份是否和当前循环的月份一致(避免2月的情况) let targetMonth = calendar.component(.month, from: targetDate) if targetMonth == month { validDates.append(targetDate) } } print(validDates.count) // 输出11,符合预期
解决方案2:直接用DateComponents构建日期并验证
另一种思路是直接构建每个月29日的DateComponents,然后尝试转换成Date——如果转换成功,说明当月存在29日,就保留这个日期。
let calendar = Calendar(identifier: .gregorian) calendar.locale = Locale(identifier: "en_US") calendar.timeZone = TimeZone(identifier: "America/Chicago")! var validDates: [Date] = [] for month in 1...12 { let components = DateComponents( year: 2018, month: month, day: 29, timeZone: calendar.timeZone, calendar: calendar ) if let date = calendar.date(from: components) { validDates.append(date) } } print(validDates.count) // 输出11,符合预期
这两种方法都能避开Calendar自动回滚的坑,准确筛选出存在29日的月份对应的日期。
内容的提问来源于stack exchange,提问作者Jon
相关产品推荐
相关产品推荐

