引言:为什么你的日期代码“时灵时不灵”?
\n\n想象一下:你正在编写一个日历应用或提醒应用。只需要获取当前日期并为其添加一天。看起来,这能出什么问题呢?你打开 Stack Overflow,找到一个有数千次浏览的问题“How do I add 1 day to an NSDate?”——然后你意识到,即使这样一个简单的操作也可能变成一场噩梦。
\n\n在本文中,我们将分析在 Swift 中向 NSDate 添加一天时的常见错误,学会如何避免它们,并编写正确、可靠的代码。你将了解为什么使用 NSDate 和 timeInterval 的旧方法是一条通往 Bug 的道路,以及现代 Apple API 如何拯救局面。
让我们一劳永逸地搞定日期问题吧!
\n\n错误 #1:使用 timeInterval 添加一天
\n\n灾难性代码
\n新手最容易踩的“坑”:
\n\nlet today = NSDate()\nlet oneDay: TimeInterval = 24 * 60 * 60 // 86,400 秒\nlet tomorrow = today.addingTimeInterval(oneDay)\n\n乍一看,这很合理。一天有 24 小时,一小时有 60 分钟,一分钟有 60 秒。相乘,相加——搞定!
\n\n但并非如此。这仅在 99% 的情况下有效,而在 1% 的情况下,它会破坏用户的整个应用。为什么?
\n\n潜在陷阱
\n- \n
- 夏令时/冬令时切换。 在时钟调整日,一天可能只有 23 或 25 小时。你的 86,400 秒会变成 83,400 或 90,000 秒。 \n
- 闰秒。 虽然这种情况很少见,但官方确实存在。 \n
- 时区。 如果用户旅行,他们的本地时间可能会混乱。 \n
- 精确到秒。 你不仅仅是添加“下一天”,而是精确地添加了 24 小时——这是两码事。 \n
想要一个例子吗?2021 年 3 月 28 日,乌克兰在凌晨 3:00 将时钟拨快了一小时。如果你在凌晨 2:30 添加了 timeInterval,你得到的将不是 3:30,而是... 4:30?或者 2:30?这取决于系统如何处理转换。简而言之,一片混乱。
错误 #2:在同一个项目中混用 NSDate 和 Date
\n\n在 Swift 中有两种日期类型:旧的 NSDate(来自 Objective-C)和现代的 Date(Swift 原生)。许多开发者,尤其是那些阅读旧教程或 2014 年 Stack Overflow 答案的开发者,仍然在使用 NSDate。
问题在于 NSDate 是一个类(引用类型),而 Date 是一个结构体(值类型)。在代码中混用它们会导致:
- \n
- 与可变性相关的难以察觉的 Bug \n
- 不必要的转换(
as Date、as NSDate) \n - API 的混乱 \n
规则:在新的 Swift 代码中,只使用 Date。将 NSDate 留给与 Objective-C 库的兼容性。
错误 #3:忽略 Calendar 和 TimeZone
\n\n当你向日期添加“1 天”时,你是在日历的上下文中进行的。如果不指定日历,系统会使用 Calendar.current——即用户的日历(通常是公历)。
但是,如果用户来自沙特阿拉伯并使用伊斯兰历法呢?或者日本历法?如果不明确指定日历,你可能会得到意想不到的结果。
\n\n错误代码示例
\nvar dateComponents = DateComponents()\ndateComponents.day = 1\nlet tomorrow = Calendar.current.date(byAdding: dateComponents, to: Date())\n\n这段代码几乎是正确的,但它隐式地使用了设备的时区。如果你正在处理 UTC 的服务器日期,而用户位于莫斯科(UTC+3),那么“明天”可能会提前 3 小时到来。
\n\n正确解决方案:Calendar + DateComponents
\n\n添加一天的金标准
\n以下是正确添加 1 天到