Ios 以(int)(单位)格式显示相对时差,例如1w、4d、2h

Ios 以(int)(单位)格式显示相对时差,例如1w、4d、2h,ios,swift,swiftui,Ios,Swift,Swiftui,我试图用速记的方式显示某个日期和现在之间的相对差异 格式 从昨天开始,将返回1d 4天前给出,将返回4d 2小时前给出,将返回2h 3周前给出,将返回3w 我曾尝试使用DateFormatter内置的相对日期格式,但这会产生更长的结果,例如昨天或一周前。我的代码如下所示: let timeFormatter = DateFormatter() timeFormatter.doesRelativeDateFormatting = true timeFormatter.timeStyle = .sh

我试图用速记的方式显示某个日期和现在之间的相对差异

格式

从昨天开始,将返回1d

4天前给出,将返回4d

2小时前给出,将返回2h

3周前给出,将返回3w

我曾尝试使用DateFormatter内置的相对日期格式,但这会产生更长的结果,例如昨天或一周前。我的代码如下所示:

let timeFormatter = DateFormatter()
timeFormatter.doesRelativeDateFormatting = true
timeFormatter.timeStyle = .short
timeFormatter.dateStyle = .short
这将产生上面解释的输出


我在DateFormatter中看不到任何可以缩短此时间的参数。有没有办法在DateFormatter中实现这一点,或者我需要构建自己的函数来实现这一点?

据我所知,这并不存在。不久前,我也尝试将其与口袋妖怪显示日期的方式(“1天前”、“2天前”、“不足1天前”)相似,结果发现,对于显示此类日期,不存在内置解决方案。

需要考虑的几个选项:

修改
相对数据时间格式化程序的输出

根据@ VADEN的建议,您可以考虑使用<代码> RelativeDateTimeFormatter <代码>启动,但需要更改其输出。

例如,考虑这个代码:

extension Date
{
    func relativeDateAsString() -> String
    {
        let df: RelativeDateTimeFormatter = RelativeDateTimeFormatter()
        var dateString: String = df.localizedString(for: self, relativeTo: Date())
        dateString = dateString.replacingOccurrences(of: "months", with: "M")
                               .replacingOccurrences(of: "month", with: "M")
                               .replacingOccurrences(of: "weeks", with: "w")
                               .replacingOccurrences(of: "week", with: "w")
                               .replacingOccurrences(of: "days", with: "d")
                               .replacingOccurrences(of: "day", with: "d")
                               .replacingOccurrences(of: "minutes", with: "m")
                               .replacingOccurrences(of: "minute", with: "m")
                               .replacingOccurrences(of: "hours", with: "h")
                               .replacingOccurrences(of: "hour", with: "h")
                               .replacingOccurrences(of: " ", with: "")
                               .replacingOccurrences(of: "ago", with: "")
                
        return dateString
    }
}

即作为<代码>日期<代码>类的扩展实现,然后考虑如下:

let anotherDate = Date(timeIntervalSinceNow: -2000000)
print ("\(anotherDate.relativeDateAsString())")
上面的示例返回“3w”,而不是“3周前”

relativeDataTimeFormatter
将返回类似“3周前”或“2小时前”的字符串。然后使用简单的字符串替换来修改文本,将“weeks”替换为“w”,删除“ago”和所有空格。希望你能明白

这个例子没有考虑一些事情:

  • 时间跨度大于个月或小于分钟
  • 本地化/其他语言
最后,请注意,
relativeDataTimeFormatter
需要iOS13+

使用
日期组件格式

也请考虑<代码> DateComponentsFormatter <代码>,它在没有字符串替换的情况下接近您想要的。

extension Date
{
    func relativeDateAsString() -> String
    {
        let dcf: DateComponentsFormatter = DateComponentsFormatter()
        dcf.includesApproximationPhrase = false
        dcf.includesTimeRemainingPhrase = false
        dcf.allowsFractionalUnits = false
        dcf.collapseLargestUnit = true
        dcf.maximumUnitCount = 1
        dcf.unitsStyle = .abbreviated
        dcf.allowedUnits = [.second, .minute, .hour, .day, .month, .year]
        return dcf.string(from: self, to: Date())
    }
}
虽然这似乎不能处理“周”的概念,但从我的实验来看,它确实能满足其他单位的需求。对于上一个示例,这将输出“23d”而不是“3w”


DateComponents格式从iOS 8开始就受支持。

您谈论的是两件不同的事情
doesRelativeDateFormatting
只考虑全天。因此,如果现在是凌晨1点,确定的日期是昨天的前一天晚上11点,但不是2小时或1天。另一方面,
datecomponentsformter
只考虑绝对差异。如果某个日期早于昨天凌晨1点,则获得1d。也许您正在寻找的是
RelativeDateTimeFormatter
。第一个解决方案效果很好。我必须在某些时候考虑本地化,但现在它是一个很好的解决方案。谢谢
extension Date
{
    func relativeDateAsString() -> String
    {
        let dcf: DateComponentsFormatter = DateComponentsFormatter()
        dcf.includesApproximationPhrase = false
        dcf.includesTimeRemainingPhrase = false
        dcf.allowsFractionalUnits = false
        dcf.collapseLargestUnit = true
        dcf.maximumUnitCount = 1
        dcf.unitsStyle = .abbreviated
        dcf.allowedUnits = [.second, .minute, .hour, .day, .month, .year]
        return dcf.string(from: self, to: Date())
    }
}