Foundation — Date

Date.distantPast #

在 iOS/macOS 的开发中,如果需要一个表示遥远过去的日期值(distant past),可以使用 Foundation 框架中提供的 Date 类型的 静态属性 Date.distantPast


Date.distantPast #

  • Date.distantPastDate 的一个静态属性,用于表示一个特别遥远过去的时间点。
  • 它通常用于那些需要一个方法返回一个非常早的日期(例如,起始时间)但又不需要指定具体的日期值的场景。

语法: #

let pastDate = Date.distantPast

值: #

Date.distantPast 的内部表示非常小的时间值,它是早于已知有意义的时间范围的一个时间点。通常在调试或者比较某些时间值时被用作“初始值”。


使用场景 #

Date.distantPast 常用于以下场景:

1. 时间比较中的初始值 #

  • 如果您正在实现一种系统,需要找到一个最早的日期,您可以将 Date.distantPast 作为比较的初始值。
  • 示例:循环一组日期,找出最早的日期。
let dates: [Date] = [
    Date(),                   // 当前日期
    Date.distantPast,         // 远古日期
    Date.distantFuture        // 遥远的未来
]

var earliestDate: Date = Date.distantFuture
for date in dates {
    if date < earliestDate {
        earliestDate = date
    }
}
print("Earliest date: \(earliestDate)")

2. 默认时间的占位值 #

  • 用于初始化某些时间值,使其代表“无限早”的起始时间。例如,用在通过算法动态计算日期时,为变量赋一个默认的早时间值。
var startDate = Date.distantPast
print("Initial startDate: \(startDate)") // 默认值是历史起点

3. 时间范围的边界 #

  • 它可以用作时间范围的下边界,用于在逻辑代码中表示 “任何早于这个时间的内容都算早于范围”。
let earliestAllowedDate = Date.distantPast
let currentDate = Date()
if currentDate >= earliestAllowedDate {
    print("Current date is valid.")
}

4. 表示历史查询 #

  • 在某些需要查询历史数据的情况下,可以使用 Date.distantPast 表示“从有历史记录的最早时间开始查询”。

Date.distantPast 的表示 #

  • 输出值:
    如果您打印 Date.distantPast,它通常会输出 ISO8601 或 yyyy-MM-dd HH:mm:ss 格式的日期时间,这代表一个非常远的历史时间。

  • 示例:

let distantPastDate = Date.distantPast
print(distantPastDate)  // 输出类似于 "0001-01-01 00:00:00 +0000"
  • 底层存储值: Apple 使用时间戳(秒数)来存储日期,Date.distantPast 值可能接近负的浮点数范围限制(非常低的时间戳)。

Date.distantFuture 的对比 #

  • Date.distantPast 相对,Date.distantFuture 表示一个非常遥远未来的日期值。它通常用作时间比较的上界或默认结束时间。

Date.distantFuture 示例: #

let futureDate = Date.distantFuture
print(futureDate)  // 输出类似于 "4001-01-01 00:00:00 +0000"
  • 使用场景:当需要设置一个遥远的上界时间时,例如,定义一个默认的事件结束时间或逻辑边界。

总结 #

  • Date.distantPast 描述:
    它表示一个距离现在非常遥远的过去时间,常用作日期比较的初值、时间范围的下界或占位时间。

  • 常见使用逻辑:

  • 占位值:初始化某些需要代表“非常早”日期的变量。

  • 时间比较:用于与其他日期一起计算最早时间。

  • 时间范围:作为查询或判断范围的极端边界。

  • Date.distantFuture 搭配:
    Date.distantPastDate.distantFuture 一起,用于表示时间范围极端的上下界。

通过使用 Date.distantPast,您可以简化一些需要处理时间逻辑的场景并提高代码的可读性。

API #

以下是 Foundation 框架中 Date 类型的核心 API 分类整理,涵盖初始化方法、计算属性、常用操作及扩展功能。结合 Calendar 和其他工具的使用场景,以下是完整的分类表格:


Foundation Date API 分类整理 #

分类API / 方法说明示例
初始化方法init()创建当前时间的 Date 对象let now = Date()
init(timeIntervalSinceNow:)基于当前时间的偏移量创建日期let futureDate = Date(timeIntervalSinceNow: 3600) // 1小时后
init(timeIntervalSince1970:)基于 1970-01-01 00:00:00 UTC 的秒数创建日期let date = Date(timeIntervalSince1970: 1_000_000)
init(timeIntervalSinceReferenceDate:)基于 2001-01-01 00:00:00 UTC 的秒数创建日期let date = Date(timeIntervalSinceReferenceDate: 3600)
计算属性timeIntervalSince1970 (属性)返回日期距离 1970-01-01 00:00:00 UTC 的秒数let timestamp = date.timeIntervalSince1970
timeIntervalSinceReferenceDate (属性)返回日期距离 2001-01-01 00:00:00 UTC 的秒数let refTime = date.timeIntervalSinceReferenceDate
比较与计算timeIntervalSince(_:)计算两个日期之间的时间间隔(秒)let interval = date1.timeIntervalSince(date2)
distance(to:)timeIntervalSince 等价,返回日期差值(兼容 Comparable 协议)let diff = date1.distance(to: date2)
数学运算addingTimeInterval(_:)返回当前日期加上指定秒数的新日期let newDate = date.addingTimeInterval(3600) // 加1小时
advanced(by:)addingTimeInterval 等价(支持 Strideable 协议)let newDate = date.advanced(by: 3600)
比较操作符==, >, <, >=, <=直接比较两个日期的先后顺序if date1 > date2 { ... }
描述与转换description (属性)返回日期字符串(UTC 格式)print(date.description) // “2023-09-15 07:30:45 +0000”
description(with:)返回指定时区的本地化日期字符串date.description(with: TimeZone(identifier: "Asia/Tokyo"))
扩展功能ISO8601Format()返回 ISO 8601 格式的字符串(Swift 5.7+)let isoString = date.ISO8601Format() // “2023-09-15T07:30:45Z”
formatted()返回本地化的简洁日期字符串(依赖 FormatStyle,Swift 5.5+)date.formatted() // “9/15/23, 3:30 PM”
formatted(_:)自定义格式化(需结合 Date.FormatStyledate.formatted(.dateTime.year().month().day()) // “Sep 15, 2023”

结合 Calendar 的常用操作 #

Date 本身不直接处理日历逻辑,需通过 Calendar 实现更复杂的操作:

分类API / 方法示例
获取日期组件Calendar.component(_:from:)let year = Calendar.current.component(.year, from: date)
日期计算Calendar.date(byAdding:value:to:)let nextMonth = Calendar.current.date(byAdding: .month, value: 1, to: date)
日期范围Calendar.startOfDay(for:)let start = Calendar.current.startOfDay(for: date)
日期比较Calendar.isDate(_:inSameDayAs:)Calendar.current.isDate(date1, inSameDayAs: date2)

关键说明 #

  1. Date 的局限性
    Date 仅表示时间点,不包含日历、时区信息。具体年/月/日等需通过 CalendarDateComponents 解析。

  2. 时区处理
    Date 存储的时间是 UTC 时间,转换为本地时间需结合 TimeZoneCalendar

    let formatter = DateFormatter()
    formatter.timeZone = TimeZone(identifier: "Asia/Shanghai")
    formatter.dateFormat = "yyyy-MM-dd HH:mm"
    let localTime = formatter.string(from: date)
    
  3. SwiftUI 扩展
    SwiftUI 提供 Text(date, style: .time) 等便捷方式显示日期,底层仍依赖 DateFormatter


完整示例 #

// 初始化与计算
let now = Date()
let tomorrow = now.addingTimeInterval(86400)
let interval = tomorrow.timeIntervalSince(now) // 86400 秒

// 使用 Calendar 处理
let calendar = Calendar.current
let components = calendar.dateComponents([.year, .month], from: now)
let startOfDay = calendar.startOfDay(for: now)

// 格式化输出
let isoString = now.ISO8601Format() // Swift 5.7+
let customFormat = now.formatted(.dateTime.day().month(.wide).year()) // "September 15, 2023"

总结 #

  • 核心功能Date 负责时间点的存储和基本运算,复杂日历逻辑需依赖 Calendar
  • 现代化扩展:Swift 5.5+ 的 formatted(_:)FormatStyle 提供了更简洁的本地化格式控制。

Formatter #

以下是 Foundation 框架中 Date Formatter 的详细说明,涵盖内置格式化工具、自定义方法及代码示例:


一、内置日期格式化工具 #

1. DateFormatter #

用于将 Date 对象格式化为本地化的字符串,或解析字符串为 Date 对象。

预设样式 (通过 .dateStyle.timeStyle) #
样式类型示例(en_US)说明
.none不显示日期/时间
.short“6/15/23” / “3:30 PM”最短格式(数字为主)
.medium“Jun 15, 2023” / “3:30:45 PM”中等详细度
.long“June 15, 2023” / “3:30:45 PM PDT”包含更多文本信息
.full“Thursday, June 15, 2023” / “3:30:45 PM Pacific Daylight Time”完整格式(含时区)

代码示例

let formatter = DateFormatter()
formatter.dateStyle = .medium
formatter.timeStyle = .short
let dateString = formatter.string(from: Date()) // "Jun 15, 2023 at 3:30 PM"
自定义格式符号 #

使用 dateFormat 属性定义完全自定义的格式:

符号含义示例
yyyy四位数年份2023
MM两位数月份06
dd两位数日期15
HH24小时制小时15
hh12小时制小时03
mm分钟30
ss45
aAM/PMAM 或 PM
EEEE完整星期名称Thursday
MMMM完整月份名称June

代码示例

formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let dateString = formatter.string(from: Date()) // "2023-06-15 15:30:45"

2. ISO8601DateFormatter #

专用于处理 ISO 8601 标准日期格式(如 2023-06-15T15:30:45Z)。

常用选项#
let isoFormatter = ISO8601DateFormatter()
isoFormatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
let dateString = isoFormatter.string(from: Date()) // "2023-06-15T15:30:45.123Z"
选项说明
.withInternetDateTime标准格式(不含毫秒)
.withFractionalSeconds包含毫秒(需与其他选项组合)
.withTimeZone包含时区偏移(如 +08:00)

3. RelativeDateTimeFormatter (iOS 13+) #

生成相对时间描述(如 “2 hours ago”, “tomorrow”)。

代码示例

let relativeFormatter = RelativeDateTimeFormatter()
relativeFormatter.unitsStyle = .full
let relativeString = relativeFormatter.localizedString(for: Date(), relativeTo: Date().addingTimeInterval(-3600)) // "1 hour ago"

4. DateComponentsFormatter #

将时间间隔(TimeInterval)格式化为易读字符串(如 “2h 30m”)。

代码示例

let componentsFormatter = DateComponentsFormatter()
componentsFormatter.unitsStyle = .abbreviated
componentsFormatter.allowedUnits = [.hour, .minute]
let intervalString = componentsFormatter.string(from: 9000) // "2h 30m"

二、自定义 Formatter 的完整方法 #

1. 固定格式(忽略用户区域设置) #

let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX") // 强制使用固定区域
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"

2. 动态本地化格式 #

formatter.locale = Locale.current // 跟随用户设置
formatter.setLocalizedDateFormatFromTemplate("ddMMyyyy") // 自动适配区域格式
// 在 en_US 显示 "MM/dd/yyyy",在 de_DE 显示 "dd.MM.yyyy"

3. 高级自定义 #

// 组合符号和文本
formatter.dateFormat = "'Created on' EEEE, MMMM d 'at' h:mm a"
// 输出:"Created on Thursday, June 15 at 3:30 PM"

// 处理时区
formatter.timeZone = TimeZone(identifier: "Asia/Tokyo")
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
// 输出:"2023-06-16 07:30:45 +0900"

三、关键注意事项 #

  1. 性能优化

    • DateFormatter 的创建成本较高,建议缓存实例(尤其是频繁使用时)。
    • 避免在列表单元格中重复创建 Formatter。
  2. 线程安全

    • DateFormatter 不是线程安全的,需确保在同一线程使用。
  3. 错误处理

    • 解析字符串时使用 date(from:) 可能返回 nil,需做空值检查:
      if let date = formatter.date(from: "2023-06-15") {
          // 解析成功
      }
      

四、不同 Formatter 的适用场景 #

场景推荐工具
显示用户本地化日期DateFormatter + 预设样式
处理 API 的 ISO 日期ISO8601DateFormatter
显示“XX 分钟前”RelativeDateTimeFormatter
格式化时间间隔DateComponentsFormatter
完全自定义格式DateFormatter.dateFormat

五、完整自定义示例 #

// 自定义带时区的格式化
let customFormatter: DateFormatter = {
    let formatter = DateFormatter()
    formatter.locale = Locale(identifier: "ja_JP")
    formatter.timeZone = TimeZone(identifier: "Asia/Tokyo")
    formatter.dateFormat = "yyyy年M月d日 (EEE) HH時mm分"
    return formatter
}()

let dateString = customFormatter.string(from: Date())
// 输出:"2023年6月15日 (木) 23時30分"

通过灵活组合这些工具,可以满足从简单日期显示到复杂国际化的所有需求。

Style #

以下是 Foundation 框架中 DateFormatterdateStyletimeStylebehavior 属性的详细说明,包括它们的可选类型、作用区别及代码示例:


一、dateStyletimeStyle 属性 #

这两个属性控制日期和时间的预设格式化样式,属于 DateFormatter.Style 枚举类型。它们会根据用户设备的区域设置自动适配本地化格式。

1. 可选值及效果 #

枚举值日期示例 (en_US)时间示例 (en_US)说明
.none不显示日期/时间部分
.short6/15/233:30 PM最简格式(数字为主)
.mediumJun 15, 20233:30:45 PM中等详细度
.longJune 15, 20233:30:45 PM PDT包含更多文本信息(如时区缩写)
.fullThursday, June 15, 20233:30:45 PM Pacific Daylight Time完整格式(含完整时区名称)

2. 代码示例 #

let formatter = DateFormatter()

// 设置日期样式
formatter.dateStyle = .medium  // 输出日期如 "Jun 15, 2023"
formatter.timeStyle = .short   // 输出时间如 "3:30 PM"

let dateString = formatter.string(from: Date()) // "Jun 15, 2023 at 3:30 PM"

3. 关键规则 #

  • 若同时设置 dateStyletimeStyle,输出会合并日期和时间(如 "Jun 15, 2023 at 3:30 PM")。
  • 若只设置其中一个,另一个默认为 .none
  • 优先级:如果同时设置了 dateFormatdateStyle/timeStyledateFormat 会覆盖样式设置。

二、behavior 属性(已废弃) #

behavior 属性原本属于 NSDateFormatterBehavior 枚举类型,用于控制解析和格式化的严格性,但在 Swift 的现代版本中已标记为废弃。其原始可选值为:

枚举值说明
.default默认行为(宽松解析,允许不完整日期)
.behavior10_0兼容 macOS 10.0 的旧解析逻辑
.behavior10_4兼容 macOS 10.4 的行为(更严格的解析)

⚠️ 注意 #

  • Swift 中不再推荐使用:Apple 官方建议直接使用 DateFormatter 的默认行为,不再需要手动设置 behavior
  • 替代方案:若需控制解析严格性,可使用 dateFormatisLenient 属性。

三、替代 behavior 的现代属性 #

1. isLenient #

控制解析时是否允许宽松处理(如将 “2023-13-01” 解析为 2024-01-01)。

formatter.isLenient = true // 默认值为 true(允许宽松解析)

2. dateFormat #

直接定义严格的格式模板,替代旧的 behavior 控制方式。

formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
formatter.isLenient = false // 严格模式(格式不匹配则返回 nil)

四、不同属性的优先级与冲突 #

属性组合结果
同时设置 dateStyledateFormatdateFormat 覆盖 dateStyletimeStyle
设置 isLenient = false解析时严格匹配 dateFormat,否则返回 nil
设置 locale覆盖本地化规则(影响星期/月份名称和顺序)

五、完整示例 #

// 创建 Formatter
let formatter = DateFormatter()

// 设置样式(优先于 dateFormat)
formatter.dateStyle = .long
formatter.timeStyle = .short

// 设置区域和严格性
formatter.locale = Locale(identifier: "fr_FR") // 法文格式
formatter.isLenient = false

// 输出结果
let date = Date()
print(formatter.string(from: date)) // "15 juin 2023 à 15:30"

六、总结 #

  • dateStyletimeStyle:快速生成本地化友好的日期时间格式。
  • behavior:已废弃,不再建议使用。
  • 替代方案:用 isLenient 控制解析宽松性,用 dateFormat 精确控制格式。

Date Style #

在 Swift 中,Date 类型的格式化功能非常强大,主要通过 FormatStyle 及其子类型实现。除了 RelativeFormatStyle,还有多种 FormatStyle 可用于不同场景。以下是完整的分类介绍和代码示例:


1. 标准日期时间格式(Date.FormatStyle #

最常用的格式化方式,支持高度自定义日期和时间的各个组成部分。

核心方法 #

  • dateTime:组合日期和时间
  • date:仅日期
  • time:仅时间
  • 可配置年、月、日、时区等细节

代码示例 #

import Foundation

let date = Date() // 当前时间

// 基础格式化
let formatted1 = date.formatted() // 默认格式,如 "2024年3月18日 下午3:45"

// 自定义日期和时间组件
let formatted2 = date.formatted(
    .dateTime
        .year(.defaultDigits)    // 年(如 "2024")
        .month(.abbreviated)     // 缩写月份(如 "Mar")
        .day(.twoDigits)         // 两位日期(如 "18")
        .hour(.conversationalDefaultDigits(amPM: .abbreviated)) // 12小时制带AM/PM
        .minute(.twoDigits)      // 两位分钟
)

// 输出结果示例:"Mar 18, 2024 at 3:45 PM"

配置选项 #

组件配置方法示例效果示例
年份.year(.twoDigits)“24”(两位年份)
月份.month(.wide)“March”(完整月份名)
星期.weekday(.short)“Mon”(缩写星期)
.day(.ordinalOfDayInMonth)“18th”(序数后缀)
小时.hour(.conversationalDefaultDigits(amPM: .omitted))“15”(24小时制)
时区.timeZone(.identifier(.short))“CST”(时区缩写)

2. 纯字符串自定义格式(VerbatimFormatStyle #

完全自定义格式字符串,类似传统 DateFormatter 的样式。

代码示例 #

let verbatimStyle = Date.VerbatimFormatStyle(
    format: "yyyy-MM-dd HH:mm:ss",
    locale: Locale(identifier: "en_US"),
    timeZone: TimeZone.current,
    calendar: Calendar.current
)

let formatted = date.formatted(verbatimStyle) // "2024-03-18 15:45:00"

常用格式符号 #

符号含义示例
y年份“2024”
M月份“03” 或 “3”
d日期“18”
H小时(24小时制)“15”
h小时(12小时制)“3”
m分钟“45”
s“00”
E星期缩写“Mon”

3. 日期区间格式(Date.IntervalFormatStyle #

用于格式化两个日期之间的间隔(如事件时间段)。

代码示例 #

let startDate = Calendar.current.date(from: DateComponents(year: 2024, month: 3, day: 18))!
let endDate = Calendar.current.date(from: DateComponents(year: 2024, month: 3, day: 20))!

let intervalStyle = Date.IntervalFormatStyle(
    date: .numeric,  // 日期格式
    time: .shortened // 时间格式
)

let formatted = intervalStyle.format(startDate...endDate)
// 输出:"3/18/2024 – 3/20/2024"

配置选项 #

// 更详细的配置
let customIntervalStyle = Date.IntervalFormatStyle(
    date: .abbreviated,  // 如 "Mar 18"
    time: .omitted,      // 不显示时间
    locale: Locale(identifier: "zh_CN")
)

let formattedCN = customIntervalStyle.format(startDate...endDate)
// 输出:"3月18日 – 3月20日"

4. ISO 8601 格式(ISO8601FormatStyle #

生成符合 ISO 8601 标准的字符串,适合网络传输或日志记录。

代码示例 #

let isoStyle = Date.ISO8601FormatStyle(
    timeZone: TimeZone(identifier: "Asia/Shanghai")!,
    includingFractionalSeconds: true, // 包含毫秒
    dateSeparator: .dash              // 日期分隔符
).year().month().day().dateTimeSeparator(.space).time()

let formatted = date.formatted(isoStyle)
// 输出示例:"2024-03-18 07:45:00.000+08:00"

配置选项 #

// 精简配置(仅日期)
let dateOnly = Date.ISO8601FormatStyle(dateSeparator: .dash).year().month().day()
let formattedDate = date.formatted(dateOnly) // "2024-03-18"

5. 本地化格式(Locale 适配) #

通过 locale 自动适配不同地区的日期格式。

代码示例 #

let date = Date()

// 美式格式
let usStyle = date.formatted(.dateTime.locale(Locale(identifier: "en_US")))
// "Mar 18, 2024 at 3:45 PM"

// 中文格式
let cnStyle = date.formatted(.dateTime.locale(Locale(identifier: "zh_CN")))
// "2024年3月18日 下午3:45"

// 日式格式
let jpStyle = date.formatted(.dateTime.locale(Locale(identifier: "ja_JP")))
// "2024/03/18 15:45"

6. 快捷样式(预定义样式) #

Swift 提供了一些预定义的快捷样式,适用于常见场景。

代码示例 #

let date = Date()

// 仅日期(完整格式)
let dateFull = date.formatted(date: .complete, time: .omitted)
// "Monday, March 18, 2024"

// 仅时间(短格式)
let timeShort = date.formatted(date: .omitted, time: .shortened)
// "3:45 PM"

// 组合样式
let combined = date.formatted(date: .abbreviated, time: .standard)
// "Mar 18, 2024, 3:45:00 PM"

总结:不同场景的推荐选择 #

场景推荐样式示例 API
标准日期时间显示Date.FormatStyle.dateTime.year().month()
完全自定义格式VerbatimFormatStyle"yyyy-MM-dd HH:mm:ss"
日期区间IntervalFormatStyle.format(startDate...endDate)
网络传输/日志记录ISO8601FormatStyle.iso8601
国际化适配结合 Locale 的格式化.locale(Locale(identifier:))

通过灵活组合这些 FormatStyle,你可以轻松实现从简单到复杂的日期时间格式化需求!

本文共 5302 字,创建于 Jan 4, 2025
相关标签: Xcode, Foundation