相對於現在時間的 RelativeDateTimeFormatter & relative(presentation:unitsStyle:)

在 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))

參考連結

--

--

彼得潘的 iOS App Neverland
彼得潘的 Swift iOS App 開發問題解答集

彼得潘的iOS App程式設計入門,文組生的iOS App程式設計入門講師,彼得潘的 Swift 程式設計入門,App程式設計入門作者,http://apppeterpan.strikingly.com