设置Date的weekday属性返回错误结果:周一指向下周日期
关于Calendar.date(bySetting:weekday:)的日期偏移问题
问题场景
执行以下Swift代码:
print(Date().description(with: .current)) print("--") print(Calendar.current.date(bySetting: .weekday, value: 2, of: Date())?.description(with: .current)) print(Calendar.current.date(bySetting: .weekday, value: 3, of: Date())?.description(with: .current)) print(Calendar.current.date(bySetting: .weekday, value: 4, of: Date())?.description(with: .current)) print(Calendar.current.date(bySetting: .weekday, value: 5, of: Date())?.description(with: .current)) print(Calendar.current.date(bySetting: .weekday, value: 6, of: Date())?.description(with: .current)) print(Calendar.current.date(bySetting: .weekday, value: 7, of: Date())?.description(with: .current)) print(Calendar.current.date(bySetting: .weekday, value: 1, of: Date())?.description(with: .current))
输出结果:
Tuesday, 3 January 2023 at 02:07:35 Eastern European Standard Time -- Monday, 9 January 2023 at 00:00:00 Eastern European Standard Time Tuesday, 3 January 2023 at 02:07:35 Eastern European Standard Time Wednesday, 4 January 2023 at 00:00:00 Eastern European Standard Time Thursday, 5 January 2023 at 00:00:00 Eastern European Standard Time Friday, 6 January 2023 at 00:00:00 Eastern European Standard Time Saturday, 7 January 2023 at 00:00:00 Eastern European Standard Time Sunday, 8 January 2023 at 00:00:00 Eastern European Standard Time
疑问:为何设置weekday为2时返回的是1月9日(下周)的周一,而非预期的1月2日?另外,若尝试设置weekOfYear属性,其他日期均正常,但周一的日期会变为2024年的日期。
原因分析
这是因为Calendar.current.date(bySetting:of:)的默认行为是从给定日期开始,向后查找第一个匹配指定组件值的日期。如果当前日期的weekday值大于目标值,方法就会跳过当前周期,直接匹配下一个周期的目标日期。
在测试场景中,当前日期是2023年1月3日(周二,weekday为3),目标weekday是2(周一),由于3>2,方法会向后寻找下一个周一,也就是1月9日,而非往前回溯1月2日。
针对weekOfYear的问题,本质也是相同的匹配逻辑:当当前日期的周内已过周一,直接设置weekOfYear配合weekday时,默认策略会向后跳转到下一年的对应周。
解决方案
要获取当前所在周的目标工作日,可通过以下两种方式实现:
方式1:指定匹配策略
使用date(bySetting:value:of:matchingPolicy:)方法,指定matchingPolicy参数来控制查找逻辑:
// 获取当前日期所在周的周一(优先取本周,不存在则向后找) let thisWeekMonday = Calendar.current.date( bySetting: .weekday, value: 2, of: Date(), matchingPolicy: .nextOrSame )
常用的匹配策略:
.nextOrSame:优先匹配当前日期或之后的第一个目标值.previousOrSame:优先匹配当前日期或之前的第一个目标值.strict:仅当当前日期完全匹配时返回,否则返回nil
方式2:构造日期组件
通过提取当前日期的年周信息,再指定weekday来构造目标日期:
var components = Calendar.current.dateComponents([.yearForWeekOfYear, .weekOfYear], from: Date()) components.weekday = 2 // 指定周一 let thisWeekMonday = Calendar.current.date(from: components)
这种方式能确保获取的是当前周的周一,不会跨到其他周。
内容的提问来源于stack exchange,提问作者CristianMoisei
相关产品推荐
相关产品推荐

