Swift计算日期差值返回0?问题排查求助
问题
我写了一个Swift函数用来判断请假申请日期是否符合公司窗口期规则(提前3个月开放申请,不能预约超过3个月后的假期)。函数接收String类型的申请日期,执行步骤如下:
- 获取当前日期(A)
- 将参数日期转为Date类型(B)
- 计算申请日期往前推3个月的窗口期开放日期(C)
- 判断C是否晚于当前日期,返回对应提示信息
代码如下:
import Foundation func requestLeave(requestedDate: String) -> String { // GET CURRENT DATE (A) let currentDate = Date() print("Current Date: \(currentDate.formatted(date: .long, time: .omitted))") // GET REQUESTED DATE (B) // STRING TO DATE let dateFormatter = DateFormatter() dateFormatter.dateFormat = "dd-MM-yyyy" guard let requestedDate = dateFormatter.date(from: requestedDate) else { return ("Return some form of error String") } print("You have requested leave on \(requestedDate.formatted(date: .long, time: .omitted))") // GET APPLICATION WINDOW OPEN DATE (C) // (LEAVE WINDOW OPENS - 3 MONTHS (7890000)) let windowOpenDate = requestedDate - 7890000 print("Applications for leave opens on \(windowOpenDate.formatted(date: .long, time: .omitted))") if windowOpenDate > currentDate { let daysBetween = Calendar.current.dateComponents([.day], from: currentDate, to: windowOpenDate) return ("Your leave window opens in \(daysBetween.day ?? 9999) days") } let daysBetween = Calendar.current.dateComponents([.day], from: windowOpenDate, to: currentDate) return ("Your leave window opened \(daysBetween.day ?? 9999) days ago!") } let request = requestLeave(requestedDate: "10-08-2023") print(request)
测试时发现,当请求日期为"28-07-2023"和"29-07-2023"时,函数返回"Your leave window opens in 0 days"的错误结果,怀疑是日期的时间部分导致的问题,想确认是否需要剥离时间仅比较日期,以及具体解决方法。
解决方案
问题根源
你的判断完全正确,问题确实出在时间部分的比较上:
Date()获取的当前日期包含具体时间(比如当前是2023-04-28 14:30:00)- 通过
DateFormatter转换的requestedDate默认时间是当天的00:00:00,往前推3个月后的windowOpenDate时间也是00:00:00 - 当当前时间晚于
windowOpenDate的00:00:00时,windowOpenDate > currentDate不成立,但计算天数差时,因为当天已经过了0点,会得到0天的结果,导致错误提示。
另外还有个隐藏问题:用固定秒数7890000来减3个月极不严谨,不同月份天数不同(比如2月28天、3月31天),直接减秒数会导致日期计算不准确。
解决步骤
- 剥离时间,仅比较日期部分:用
Calendar把所有日期都调整为当天的起始时间(00:00:00) - 用Calendar计算3个月前的日期:避免固定秒数的误差
修改后的代码
import Foundation func requestLeave(requestedDate: String) -> String { let calendar = Calendar.current // 获取当前日期并转为当天起始时间(A) let currentDate = calendar.startOfDay(for: Date()) print("Current Date: \(currentDate.formatted(date: .long, time: .omitted))") // 将参数日期转为Date类型并转为当天起始时间(B) let dateFormatter = DateFormatter() dateFormatter.dateFormat = "dd-MM-yyyy" guard let requestedDate = dateFormatter.date(from: requestedDate), let requestedStartDate = calendar.date(bySettingHour: 0, minute: 0, second: 0, of: requestedDate) else { return "无效的日期格式,请输入dd-MM-yyyy格式的日期" } print("You have requested leave on \(requestedStartDate.formatted(date: .long, time: .omitted))") // 计算申请日期往前推3个月的窗口期开放日期(C),并转为当天起始时间 guard let windowOpenDate = calendar.date(byAdding: .month, value: -3, to: requestedStartDate), let windowOpenStartDate = calendar.startOfDay(for: windowOpenDate) else { return "日期计算错误" } print("Applications for leave opens on \(windowOpenStartDate.formatted(date: .long, time: .omitted))") // 仅比较日期部分 if windowOpenStartDate > currentDate { let daysBetween = calendar.dateComponents([.day], from: currentDate, to: windowOpenStartDate) return "你的请假申请窗口将在\(daysBetween.day ?? 9999)天后开放" } let daysBetween = calendar.dateComponents([.day], from: windowOpenStartDate, to: currentDate) return "你的请假申请窗口已经开放\(daysBetween.day ?? 9999)天了!" } let request = requestLeave(requestedDate: "28-07-2023") print(request)
关键改进点
- 用
calendar.startOfDay(for:)统一将所有日期转为当天0点,彻底消除时间部分的干扰 - 用
calendar.date(byAdding: .month, value: -3, to:)精确计算3个月前的日期,自动适配不同月份的天数差异 - 增加了更多可选绑定判断,提升代码的健壮性
内容的提问来源于stack exchange,提问作者OxfordSi
相关产品推荐
相关产品推荐

