Skip to content

Instantly share code, notes, and snippets.

@jinthagerman
Created February 26, 2017 10:26
Show Gist options
  • Save jinthagerman/009c85b7bbd0a40dcbba747e89a501bf to your computer and use it in GitHub Desktop.
Save jinthagerman/009c85b7bbd0a40dcbba747e89a501bf to your computer and use it in GitHub Desktop.
Time ago/ahead in Swift
import Foundation
struct DateComponentUnitFormatter {
private struct DateComponentUnitFormat {
let unit: Calendar.Component
let singularUnit: String
let pluralUnit: String
let futureSingular: String
let pastSingular: String
}
private let formats: [DateComponentUnitFormat] = [
DateComponentUnitFormat(unit: .year,
singularUnit: "year",
pluralUnit: "years",
futureSingular: "Next year",
pastSingular: "Last year"),
DateComponentUnitFormat(unit: .month,
singularUnit: "month",
pluralUnit: "months",
futureSingular: "Next month",
pastSingular: "Last month"),
DateComponentUnitFormat(unit: .weekOfYear,
singularUnit: "week",
pluralUnit: "weeks",
futureSingular: "Next week",
pastSingular: "Last week"),
DateComponentUnitFormat(unit: .day,
singularUnit: "day",
pluralUnit: "days",
futureSingular: "Tomorrow",
pastSingular: "Yesterday"),
DateComponentUnitFormat(unit: .hour,
singularUnit: "hour",
pluralUnit: "hours",
futureSingular: "In an hour",
pastSingular: "An hour ago"),
DateComponentUnitFormat(unit: .minute,
singularUnit: "minute",
pluralUnit: "minutes",
futureSingular: "In a minute",
pastSingular: "A minute ago"),
DateComponentUnitFormat(unit: .second,
singularUnit: "second",
pluralUnit: "seconds",
futureSingular: "Just now",
pastSingular: "Just now"),
]
func string(forDateComponents dateComponents: DateComponents, useNumericDates: Bool) -> String {
for format in self.formats {
let unitValue: Int
switch format.unit {
case .year:
unitValue = dateComponents.year ?? 0
case .month:
unitValue = dateComponents.month ?? 0
case .weekOfYear:
unitValue = dateComponents.weekOfYear ?? 0
case .day:
unitValue = dateComponents.day ?? 0
case .hour:
unitValue = dateComponents.hour ?? 0
case .minute:
unitValue = dateComponents.minute ?? 0
case .second:
unitValue = dateComponents.second ?? 0
default:
assertionFailure("Date does not have requried components")
return ""
}
switch unitValue {
case 2 ..< Int.max:
return "\(unitValue) \(format.pluralUnit) ago"
case 1:
return useNumericDates ? "\(unitValue) \(format.singularUnit) ago" : format.pastSingular
case -1:
return useNumericDates ? "In \(-unitValue) \(format.singularUnit)" : format.futureSingular
case Int.min ..< -1:
return "In \(-unitValue) \(format.pluralUnit)"
default:
break
}
}
return "Just now"
}
}
extension Date {
func timeAgoSinceNow(useNumericDates: Bool = false) -> String {
let calendar = Calendar.current
let unitFlags: Set<Calendar.Component> = [.minute, .hour, .day, .weekOfYear, .month, .year, .second]
let now = Date()
let components = calendar.dateComponents(unitFlags, from: self, to: now)
let formatter = DateComponentUnitFormatter()
return formatter.string(forDateComponents: components, useNumericDates: useNumericDates)
}
}
@jinthagerman
Copy link
Author

Sounds like your date might be deserializing incorrectly? If you convert it to a string using DateFormatter, is it in the correct time zone?

@ankit0812
Copy link

Sounds like your date might be deserializing incorrectly? If you convert it to a string using DateFormatter, is it in the correct time zone?

No, my serailizing is fine. But the relative time that is being returned is according to UTC which is not my timezone

@jinthagerman
Copy link
Author

That doesn't make sense. There's no presumption of time zone in this code and Date is time zone independent ("A specific point in time, independent of any calendar or time zone." - Apple Docs).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment