Swift 如何使用DateComponents格式将日期显示为;“今天”;或;昨天;?

Swift 如何使用DateComponents格式将日期显示为;“今天”;或;昨天;?,swift,Swift,我在我的项目中使用swift,我想显示这样的具体日期:5天前或5个月前或。。。 我正在使用DateComponents格式,它做得很好,但问题是我想显示1天前的“昨天”或显示3秒钟前的“今天”。我该怎么做?我可以使用DateComponents格式解决此问题吗?这是我的密码: func shortDate(_ local: LocaleIdentifier = .fa) -> String { let now = Date() let date = self

我在我的项目中使用swift,我想显示这样的具体日期:5天前或5个月前或。。。 我正在使用DateComponents格式,它做得很好,但问题是我想显示1天前的“昨天”或显示3秒钟前的“今天”。我该怎么做?我可以使用DateComponents格式解决此问题吗?这是我的密码:

func shortDate(_ local: LocaleIdentifier = .fa) -> String {
    
    let now = Date()
    let date = self

    let formatter = DateComponentsFormatter()
    formatter.calendar?.locale = Locale(identifier: local.rawValue)
    formatter.unitsStyle = .full
    formatter.maximumUnitCount = 1
    formatter.allowedUnits = [.year, .month, .day, .hour, .minute, .second]

    guard let timeString = formatter.string(from: date, to: now) else {
         return ""
    }

    return String(format: "Ago".localized, timeString)
}
var calendar = Calendar.current
calendar.locale = Locale(identifier: local.rawValue)
    
let componentFormatter = DateComponentsFormatter()
componentFormatter.calendar = calendar
componentFormatter.unitsStyle = .full
componentFormatter.maximumUnitCount = 1

let interval = Calendar.current.dateComponents([.year, .month, .day], from: self, to: Date())
    
if let year = interval.year, year > 0 {
    componentFormatter.allowedUnits = .year
} else if let month = interval.month, month > 0 {
    componentFormatter.allowedUnits = .month
} else if let day = interval.day, day > 1 {
    componentFormatter.allowedUnits = .day
} else { // if let day = interval.day, day == 0 || day == 1 for Today or Yesterday

    let formatter = DateFormatter()
    formatter.doesRelativeDateFormatting = true
    formatter.calendar.locale = Locale(identifier: local.rawValue)
    formatter.timeStyle = .none
    formatter.dateStyle = .medium

    return formatter.string(from: self)
}

guard let timeString = componentFormatter.string(from: self, to: Date()) else {
        return ""
}
return String(format: "Ago".localized, timeString)

您正在查找DateFormatter的
doesRelativeDateFormatting
属性。

对于iOS 13或更高版本,您可以使用
RelativeDateFormatter

let relativeDateTimeFormatter = RelativeDateTimeFormatter()
relativeDateTimeFormatter.dateTimeStyle = .named
relativeDateTimeFormatter.unitsStyle = .full
let date = Date.init(timeIntervalSinceNow: -60*60*24)
relativeDateTimeFormatter.string(for: date)  // "yesterday"
编辑/更新:

如果您想支持iOS 11,您需要实现自己的相对日期格式化程序。您可以使用日历方法isDateInToday和IsDateInDayed将相对日期格式化程序与日期组件格式化程序组合起来。请注意,无需检查在日期组件格式化程序中设置单个单位的时间间隔。您可以设置日期组件格式化程序中允许的单位,只需确保根据要显示的所需优先级设置它们:

//这将避免每次调用RelativeDataFormatted属性时都创建格式化程序

extension Formatter {
    static let dateComponents: DateComponentsFormatter = {
        let dateComponentsFormatter = DateComponentsFormatter()
        dateComponentsFormatter.allowedUnits = [.day, .month, .year]  // check the order of the units it does matter when allowing only 1 unit to be displayed
        dateComponentsFormatter.maximumUnitCount = 1
        dateComponentsFormatter.unitsStyle = .full
        return dateComponentsFormatter
    }()
    static let relativeDate: DateFormatter = {
        let dateFormatter = DateFormatter()
        dateFormatter.doesRelativeDateFormatting = true
        dateFormatter.timeStyle = .none
        dateFormatter.dateStyle = .medium
        return dateFormatter
    }()
}


操场测试:

let date1 = DateComponents(calendar: .current, year: 2020, month: 9, day: 4, hour: 5).date!
let date2 = DateComponents(calendar: .current, year: 2020, month: 9, day: 3, hour: 23, minute: 50).date!
let date3 = DateComponents(calendar: .current, year: 2020, month: 8, day: 25, hour: 10).date!
let date4 = DateComponents(calendar: .current, year: 2020, month: 8, day: 3).date!
let date5 = DateComponents(calendar: .current, year: 2019, month: 8, day: 27).date!

date1.relativeDateFormatted  // "Today"
date2.relativeDateFormatted  // "Yesterday"
date3.relativeDateFormatted  // "10 days"
date4.relativeDateFormatted  // "1 month"
date5.relativeDateFormatted  // "1 year"

我想,我必须使用DateComponentFormatter来处理1天以上的问题,并使用DateFormatter来显示今天(day=0)和昨天(day=1)来解决我的问题。 我找到了答案

但我把代码做得更好,这是我的代码:

func shortDate(_ local: LocaleIdentifier = .fa) -> String {
    
    let now = Date()
    let date = self

    let formatter = DateComponentsFormatter()
    formatter.calendar?.locale = Locale(identifier: local.rawValue)
    formatter.unitsStyle = .full
    formatter.maximumUnitCount = 1
    formatter.allowedUnits = [.year, .month, .day, .hour, .minute, .second]

    guard let timeString = formatter.string(from: date, to: now) else {
         return ""
    }

    return String(format: "Ago".localized, timeString)
}
var calendar = Calendar.current
calendar.locale = Locale(identifier: local.rawValue)
    
let componentFormatter = DateComponentsFormatter()
componentFormatter.calendar = calendar
componentFormatter.unitsStyle = .full
componentFormatter.maximumUnitCount = 1

let interval = Calendar.current.dateComponents([.year, .month, .day], from: self, to: Date())
    
if let year = interval.year, year > 0 {
    componentFormatter.allowedUnits = .year
} else if let month = interval.month, month > 0 {
    componentFormatter.allowedUnits = .month
} else if let day = interval.day, day > 1 {
    componentFormatter.allowedUnits = .day
} else { // if let day = interval.day, day == 0 || day == 1 for Today or Yesterday

    let formatter = DateFormatter()
    formatter.doesRelativeDateFormatting = true
    formatter.calendar.locale = Locale(identifier: local.rawValue)
    formatter.timeStyle = .none
    formatter.dateStyle = .medium

    return formatter.string(from: self)
}

guard let timeString = componentFormatter.string(from: self, to: Date()) else {
        return ""
}
return String(format: "Ago".localized, timeString)

对在这种情况下,我可以使用DateComponents格式吗?在这种情况下,您需要实现自己的相对日期-时间格式设置程序。这可能会有帮助。您还可以使用日历方法isDateInToday和IsDateInYesterDay。这很好,但我发现我的问题解决得更好、更干净。这不会像预期的那样工作。它将在任何时间返回第0天24小时内的时间间隔和24小时和48小时之间的任何时间间隔的第1天(如果没有夏令时转换)。同样,您应该使用上面提到的日历方法isDateInToday和IsDateInDayed。恢复时,首先检查isDateInToday或IsDateInDayed,然后使用DateFormatter,否则使用DateComponents Formatter这就是我想要的,24小时内的任何时间间隔都应该返回到今天,24到48小时之间的任何时间间隔都应该返回到昨天。但是使用IsDateInDay或IsDateInDayed是解决我问题的另一种方法,当我想显示今天或昨天的其他标题时,甚至比我的答案更好,比如说“现在”而不是“今天”当IsDateToDay返回true时。您的答案比我的:)更好