A couple options to consider:
Modify the output of a RelativeDateTimeFormatter
Following the suggestion of @vadian, you might consider using RelativeDateTimeFormatter to start, but will need to change its output.
For example, consider this code:
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
}
}
i.e. implemented as an Extension of the Date class, then consider this:
let anotherDate = Date(timeIntervalSinceNow: -2000000)
print ("\(anotherDate.relativeDateAsString())")
This above example returns "3w" instead of "3 weeks ago".
The RelativeDateTimeFormatter will return a string like "3 weeks ago", or "2 hours ago". Then use simple String substitutions to modify the text, replacing "weeks" with "w", removing "ago" and all spaces. Hopefully you get the idea...
This example doesn't consider a few things:
- timespans greater than months or less than minutes
- localization/other languages
Lastly, be aware that RelativeDateTimeFormatter requires iOS13+.
Use DateComponentsFormatter
Please also consider DateComponentsFormatter, which appears to come close to what you want without the string substitutions.
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())
}
}
This doesn't seem to handle the concept of "weeks" though, but from my experimentation does exactly what you want for the other units. For the previous example, this outputs "23d" and not "3w".
DateComponentsFormatter is supported since iOS 8.