Swift iOS doesRelativeDateFormatting имеет разные значения, кроме "Сегодня" и "Вчера"?

У меня есть несколько дат, которые я пытаюсь представить, используя относительную дату, такую ​​как "Сегодня, вчера, 1 неделя назад, 1 месяц назад" и т.д.

Это код Swift, который я использую:

let dateFormatter = NSDateFormatter()
dateFormatter.dateStyle = .MediumStyle
dateFormatter.doesRelativeDateFormatting = true
let uploadDate = dateFormatter.stringFromDate(date)

Представлены только "Сегодня" и "Вчера", а остальные даты выглядят следующим образом: 24 ноября 2014 г. 17 ноября 2014 г. и т.д...

Есть ли другой способ представить все даты, используя относительную дату, вместо фактических дат?

Ответ 1

Редактирование/обновление: Xcode 8.3.2 • Swift 3.1

Это действительно легко, если вы используете расширения и методы календаря, чтобы помочь вам с вашими календарными вычислениями:

extension Date {
    var yearsFromNow: Int {
        return Calendar.current.dateComponents([.year], from: self, to: Date()).year!
    }
    var monthsFromNow: Int {
        return Calendar.current.dateComponents([.month], from: self, to: Date()).month!
    }
    var weeksFromNow: Int {
        return Calendar.current.dateComponents([.weekOfYear], from: self, to: Date()).weekOfYear!
    }
    var daysFromNow: Int {
        return Calendar.current.dateComponents([.day], from: self, to: Date()).day!
    }
    var isInYesterday: Bool {
        return Calendar.current.isDateInYesterday(self)
    }
    var hoursFromNow: Int {
        return Calendar.current.dateComponents([.hour], from: self, to: Date()).hour!
    }
    var minutesFromNow: Int {
        return Calendar.current.dateComponents([.minute], from: self, to: Date()).minute!
    }
    var secondsFromNow: Int {
        return Calendar.current.dateComponents([.second], from: self, to: Date()).second!
    }
    var relativeTime: String {
        if yearsFromNow > 0 { return "\(yearsFromNow) year" + (yearsFromNow > 1 ? "s" : "") + " ago" }
        if monthsFromNow > 0 { return "\(monthsFromNow) month" + (monthsFromNow > 1 ? "s" : "") + " ago" }
        if weeksFromNow > 0 { return "\(weeksFromNow) week" + (weeksFromNow > 1 ? "s" : "") + " ago" }
        if isInYesterday { return "Yesterday" }
        if daysFromNow > 0 { return "\(daysFromNow) day" + (daysFromNow > 1 ? "s" : "") + " ago" }
        if hoursFromNow > 0 { return "\(hoursFromNow) hour" + (hoursFromNow > 1 ? "s" : "") + " ago" }
        if minutesFromNow > 0 { return "\(minutesFromNow) minute" + (minutesFromNow > 1 ? "s" : "") + " ago" }
        if secondsFromNow > 0 { return secondsFromNow < 15 ? "Just now"
            : "\(secondsFromNow) second" + (secondsFromNow > 1 ? "s" : "") + " ago" }
        return ""
    }
}

тестирование

let calendar =  Calendar.current

let date1 = DateComponents(calendar: calendar, year: 2016, month:  3, day: 14, hour: 22, minute: 39).date!
let date2 = DateComponents(calendar: calendar, year: 2019, month:  4, day: 18, hour: 22, minute: 39).date!
let date3 = DateComponents(calendar: calendar, year: 2019, month: 6, day:  2, hour: 12, minute: 38).date!
let date4 = DateComponents(calendar: calendar, year: 2019, month: 6, day:  14, hour: 3, minute: 0).date!
let date5 = DateComponents(calendar: calendar, year: 2019, month: 6, day:  17, hour: 23, minute: 45).date!
let date6 = DateComponents(calendar: calendar, year: 2019, month: 6, day:  18, hour: 19, minute:  17).date!
let timeOffset1 = date1.relativeTime // "3 years ago"
let timeOffset2 = date2.relativeTime // "1 month ago"
let timeOffset3 = date3.relativeTime // "2 weeks ago"
let timeOffset4 = date4.relativeTime // "4 days ago"
let timeOffset5 = date5.relativeTime // "Yesterday"
let timeOffset6 = date6.relativeTime // "Just now"

Ответ 2

Вам следует взглянуть на сообщение блога Mattt Thompsons о NSDateComponentsFormatter

http://nshipster.com/nsdatecomponents/ а также http://nshipster.com/nsformatter/

let formatter = NSDateComponentsFormatter()
formatter.unitsStyle = .Full

let components = NSDateComponents()
components.day = 1
components.hour = 2

let string = formatter.stringFromDateComponents(components)
// 1 day, 2 hours

Пример (по Матту Томпсону)

Ответ 3

var relativeTime: String {
    // don't forget spacing on these constants.
    let futurePrefix = "" // " in" is a viable choice here...
    let pastSuffix = " ago" // " ago" is a viable choice here...
    let now = NSDate()
    for (method, unitName) in [
        (now.years, "year"),
        (now.months, "month"),
        (now.weeks, "week"),
        (now.days, "day"),
        (now.hours, "hour"),
        (now.minutes, "minute"),
        (now.seconds, "second")
    ] {
        let qty = method(self)
        let absQty = abs(method(self))
        if absQty > 0 {
            return (qty < 0 ? futurePrefix : "") +
                String(absQty) + " " +
                unitName +
                (absQty == 1 ? "": "s") +
                (qty > 0 ? pastSuffix : "")
        }
    }
    return ""
}

Альтернативная реализация Leo Dabus реализации relativeTime, которая делает как будущее, так и прошлое и более кратким. (Swift2.3)