这是我在 Swift 2 中的解决方案,它通过将两个日期与零时间进行比较来避免 24 小时问题。
extension NSDate {
private func dateWithZeroTime(date: NSDate) -> NSDate? {
let calendar = NSCalendar.currentCalendar()
let units: NSCalendarUnit = [.Day, .WeekOfYear, .Month, .Year]
let components = calendar.components(units, fromDate: date)
return calendar.dateFromComponents(components)
}
private func thisDay() -> NSDate? {
return self.dateWithZeroTime(self)
}
private func today() -> NSDate? {
return self.dateWithZeroTime(NSDate())
}
var relativeFormat: String? {
let today = self.today()
let thisDay = self.thisDay()
let formatter = NSDateFormatter()
formatter.dateStyle = NSDateFormatterStyle.LongStyle
let dateString = formatter.stringFromDate(self)
if nil != thisDay && nil != today {
let units: NSCalendarUnit = [.Day, .WeekOfYear, .Month, .Year]
let components = NSCalendar.currentCalendar().components(units, fromDate: thisDay!, toDate: today!, options: [])
if (components.year > 0) {
return components.year == 1 ? "A year ago, \(dateString)" : "\(components.year) years ago, \(dateString)"
} else if (components.month > 0) {
return components.month == 1 ? "A month ago, \(dateString)" : "\(components.month) months ago, \(dateString)"
} else if (components.weekOfYear > 0) {
return components.weekOfYear == 1 ? "A week ago, \(dateString)" : "\(components.weekOfYear) weeks ago, \(dateString)"
} else if (components.day > 0) {
return components.day == 1 ? "Yesterday, \(dateString)" : "\(self.dayOfTheWeek()), \(dateString)"
} else {
return "Today"
}
}
return nil
}
func dayOfTheWeek() -> String {
let weekdays = [
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday"
]
let calendar: NSCalendar = NSCalendar.currentCalendar()
let components: NSDateComponents = calendar.components(.Weekday, fromDate: self)
return weekdays[components.weekday - 1]
}
}
Swift 5 解决方案:
public extension Date {
private func dateWithZeroTime(_ date: Date) -> Date? {
let calendar = Calendar.current
let units: Set<Calendar.Component> = Set( [.day, .weekOfYear, .month, .year])
let components = calendar.dateComponents(units, from: date)
return calendar.date(from: components)
}
private func thisDay() -> Date? {
return self.dateWithZeroTime(self)
}
private func today() -> Date? {
return self.dateWithZeroTime(Date())
}
var relativeFormat: String? {
let formatter = DateFormatter()
formatter.dateStyle = DateFormatter.Style.long
let dateString = formatter.string(from: self)
if let thisDay = self.thisDay(),
let today = self.today() {
let units: Set<Calendar.Component> = Set([.day, .weekOfYear, .month, .year])
let components = Calendar.current.dateComponents(units, from: thisDay, to: today)
if let year = components.year,
year > 0 {
return year == 1 ? "A year ago, \(dateString)" : "\(year) years ago, \(dateString)"
} else if let month = components.month,
month > 0 {
return month == 1 ? "A month ago, \(dateString)" : "\(month) months ago, \(dateString)"
} else if let weekOfYear = components.weekOfYear,
weekOfYear > 0 {
return weekOfYear == 1 ? "A week ago, \(dateString)" : "\(weekOfYear) weeks ago, \(dateString)"
} else if let day = components.day,
day > 0 {
return day == 1 ? "Yesterday, \(dateString)" : dayOfWeekWithDateString(dateString)
} else {
return "Today"
}
}
return nil
}
func dayOfTheWeek() -> String? {
let weekdays = [
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday"
]
let calendar = Calendar.current
let components: DateComponents = calendar.dateComponents(Set([.weekday]), from: self)
guard let weekday = components.weekday else { return nil }
return weekdays[weekday - 1]
}
func dayOfWeekWithDateString(_ dateString: String) -> String {
if let dayOfWeek = dayOfTheWeek() {
return "\(dayOfWeek), \(dateString)"
} else {
return dateString
}
}
}