はじめに
SNSなどでよくみる「〇日前」のような表示をSwiftで作成してみようと思います。
実装
extension Date {
static let dateFormatter: DateFormatter = {
let dateFormatter = DateFormatter()
dateFormatter.dateStyle = .short
dateFormatter.timeStyle = .none
dateFormatter.locale = Locale(identifier: "ja_JP")
return dateFormatter
}()
var elapsedTimeText: String {
let components = Calendar.current.dateComponents([.year, .month, .weekOfYear, .day, .hour, .minute, .second], from: self, to: Date())
if let year = components.year, year > 0 {
return Date.dateFormatter.string(from: self)
} else if let month = components.month, month > 0 {
return "\(month)ヶ月前"
} else if let week = components.weekOfYear, week > 0 {
return "\(week)週間前"
} else if let day = components.day, day > 0 {
return "\(day)日前"
} else if let hour = components.hour, hour > 0 {
return "\(hour)時間前"
} else if let minute = components.minute, minute > 0 {
return "\(minute)分前"
} else if let second = components.second, second > 0 {
return "\(second)秒前"
} else {
return "たった今"
}
}
}
テストコード
func testElapsedTimeText() {
let now = Date()
// 1年以上前の場合
let oneYearAgo = Calendar.current.date(byAdding: .year, value: -1, to: now)!
XCTAssertEqual(oneYearAgo.elapsedTimeText, Date.dateFormatter.string(from: oneYearAgo))
// 11ヶ月前の場合
let elevenMonthsAgo = Calendar.current.date(byAdding: .month, value: -11, to: now)!
XCTAssertEqual(elevenMonthsAgo.elapsedTimeText, "11ヶ月前")
// 1ヶ月前の場合
let oneMonthAgo = Calendar.current.date(byAdding: .month, value: -1, to: now)!
XCTAssertEqual(oneMonthAgo.elapsedTimeText, "1ヶ月前")
// 2週間前の場合
let twoWeeksAgo = Calendar.current.date(byAdding: .day, value: -14, to: now)!
XCTAssertEqual(twoWeeksAgo.elapsedTimeText, "2週間前")
// 1日前の場合
let oneDayAgo = Calendar.current.date(byAdding: .day, value: -1, to: now)!
XCTAssertEqual(oneDayAgo.elapsedTimeText, "1日前")
// 2時間前の場合
let twoHoursAgo = Calendar.current.date(byAdding: .hour, value: -2, to: now)!
XCTAssertEqual(twoHoursAgo.elapsedTimeText, "2時間前")
// 30分前の場合
let thirtyMinutesAgo = Calendar.current.date(byAdding: .minute, value: -30, to: now)!
XCTAssertEqual(thirtyMinutesAgo.elapsedTimeText, "30分前")
// 10秒前の場合
let tenSecondsAgo = Calendar.current.date(byAdding: .second, value: -10, to: now)!
XCTAssertEqual(tenSecondsAgo.elapsedTimeText, "10秒前")
// たった今の場合
XCTAssertEqual(now.elapsedTimeText, "たった今")
}
おわり
Dateの扱いは難しいです。
もっとこうしたほうがいいとかありましたらコメントください。。
参考記事