Swift 中的日期和时间处理:高级技巧

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

Swift 中的高级日期和时间处理:从基础到优化

\n

日期和时间处理是 iOS/macOS 开发中最常见也最棘手的任务之一。Foundation API(Date、DateFormatter、Calendar)看似简单,却常常导致与时区、本地化或性能相关的错误。本文将深入探讨 Swift 中日期处理的高级技巧:从规范的解析到高性能计算,这些技巧将在生产项目中大有用处。

\n\n

1. DateFormatter:精细配置与缓存

\n

新手最常见的错误是在循环或频繁调用的方法中创建新的 DateFormatter 对象。创建 DateFormatter 是一项昂贵的操作(比重复使用它慢多达 1000 倍)。

\n\n
// ❌ 不好:每次都创建 formatter\nfunc parseDate(from string: String) -> Date? {\n    let formatter = DateFormatter()\n    formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"\n    formatter.locale = Locale(identifier: "ru_RU")\n    formatter.timeZone = TimeZone(secondsFromGMT: 0)\n    return formatter.date(from: string)\n}\n\n// ✅ 好:缓存 formatter\nprivate let isoDateFormatter: DateFormatter = {\n    let f = DateFormatter()\n    f.dateFormat = "yyyy-MM-dd HH:mm:ss"\n    f.locale = Locale(identifier: "ru_RU")\n    f.timeZone = TimeZone(secondsFromGMT: 0)\n    return f\n}()\n\nfunc parseDateFast(from string: String) -> Date? {\n    return isoDateFormatter.date(from: string)\n}
\n\n

高级建议: 对于固定格式(例如 ISO 8601),请使用 ISO8601DateFormatter——它比标准的 DateFormatter 更快。对于需要高性能的自定义格式,请考虑使用带有线程本地存储(thread-local storage)的 DateFormatter:

\n\n
extension DateFormatter {\n    static let threadLocal: ThreadLocal<DateFormatter> = ThreadLocal {\n        let f = DateFormatter()\n        f.dateFormat = "dd.MM.yyyy"\n        f.locale = Locale(identifier: "ru_RU")\n        return f\n    }\n}
\n\n

2. Calendar 和 DateComponents:无差错计算

\n

对于日期运算(例如添加一天、查找月初),请使用 Calendar,而不是手动添加秒数。手动添加 86400 秒(24*60*60)会在夏令时切换时出错。

\n\n
let calendar = Calendar.current\nlet now = Date()\n\n// ✅ 安全地添加 1 天\nif let tomorrow = calendar.date(byAdding: .day, value: 1, to: now) {\n    print("明天:\\(tomorrow)")\n}\n\n// ✅ 查找当前月的第一天\nlet startOfMonth = calendar.date(from: calendar.dateComponents([.year, .month], from: now))!\n\n// ✅ 获取考虑本地化的组件\nlet components = calendar.dateComponents([.weekday, .weekOfYear], from: now)\nprint("星期几:\\(components.weekday ?? 0)") // 1 = 美国周日,2 = 俄罗斯周一
\n\n

高级建议: 对于高负载计算(例如生成日历网格),请缓存 Calendar 和 TimeZone。避免在循环中使用 Calendar.current——它每次都会读取系统设置。

\n\n

3. 面向用户的本地化和格式化

\n

切勿向用户显示原始日期。请使用带有预定义样式(.short、.medium、.long、.full)的 DateFormatter 和用于人类可读相对日期(例如“昨天”、“3 天前”)的 RelativeDateTimeFormatter。

\n\n
// 考虑用户本地化的绝对日期\nlet userFormatter = DateFormatter()\nuserFormatter.dateStyle = .long\nuserFormatter.timeStyle = .short\nprint(userFormatter.string(from: Date())) // "2025年6月15日 14:30"(对于 zh_CN)\n\n// 相对日期(iOS 13+)\nlet relativeFormatter = RelativeDateTimeFormatter()\nrelat                

博客

书籍推荐