相對於現在時間的 RelativeDateTimeFormatter & relative(presentation:unitsStyle:)
Published in
6 min readMay 17, 2022
在 iOS App 上我們時常看到時間以相對於現在時間的格式顯示,比方 IG App 的動態會顯示 po 文時間是 5 hours ago,5 days ago,1 week ago。
這樣的功能從前我們要自己手動計算,不過在 iOS 13 & 15 我們有更簡單的方法可以實現。
- iOS 13 的 RelativeDateTimeFormatter。
- iOS 15 的 relative(presentation:unitsStyle:)。
iOS 13 的 RelativeDateTimeFormatter
let time = Date.now.advanced(by: -70)
let formatter = RelativeDateTimeFormatter()
let dateString = formatter.string(for: time)
結果
1 minute ago
RelativeDateTimeFormatter 十分聰明,它得到的字串將和 iOS 設定的語言一致。比方當 iOS 語言設為繁體中文時,剛剛程式得到的文字將變成 1分鐘前。
1分鐘前
其它例子
- 8 天前
let time = Calendar.current.date(byAdding: .day, value: -8, to: .now)
let formatter = RelativeDateTimeFormatter()
let dateString = formatter.string(for: time)
結果
1 week ago
- 32 天前
let time = Calendar.current.date(byAdding: .day, value: -32, to: .now)
let formatter = RelativeDateTimeFormatter()
let dateString = formatter.string(for: time)
結果
1 month ago
- 380 天前
let time = Calendar.current.date(byAdding: .day, value: -380, to: .now)
let formatter = RelativeDateTimeFormatter()
let dateString = formatter.string(for: time)
結果
1 year ago
太久以前的時間顯示完整的日期
有時我們並不想所有的時間都顯示相對時間。比方 IG 最多顯示一星期前,超過一星期的時間會顯示完整日期。
此時我們可先判斷時間距離現在是否超過一星期,一星期內顯示相對時間,超過一星期則顯示完整日期,例如以下例子。
let time = Calendar.current.date(byAdding: .day, value: -8, to: .now)!
let components = Calendar.current.dateComponents([.day], from: time, to: .now)
if let day = components.day,
day > 7{
let formatter = DateFormatter()
formatter.dateStyle = .medium
formatter.timeZone = .none
let dateString = formatter.string(for: time)
} else {
let formatter = RelativeDateTimeFormatter()
let dateString = formatter.string(for: time)
}
結果
May 9, 2022
iOS 15 的 relative(presentation:unitsStyle:)
iOS 15 的 Date 可以直接呼叫 formatted 產生字串,因此我們有更簡單的方法產生相對時間的字串,只要在 formatted 的參數傳入 relative(presentation:unitsStyle:)。
let time = Calendar.current.date(byAdding: .day, value: -1, to: .now)
let dateString = time?.formatted(.relative(presentation: .numeric))
結果
1 day ago
參數 presentation 可控制相對時間的格式,剛剛的 .numeric 會得到 1 day ago,若改成 .name 可得到 yesterday。
let dateString = time?.formatted(.relative(presentation: .named))