Skip to content

Instantly share code, notes, and snippets.

@jinthagerman
Created February 26, 2017 10:26
Show Gist options
  • Star 23 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • 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)
}
}
@hamzauzumcu
Copy link

you just saved me an hour thanks

@ckalbas
Copy link

ckalbas commented Jun 28, 2017

Awesome!

I've made some changes to conform to my project's needs, referencing your work. Check it out: https://gist.github.com/ckalbas/eccdc7db6893001d0811dea7823549a2

@pixeldock
Copy link

Great job, thanks!

@BrunoVillanova
Copy link

Thanks!!!! Awesome job!

@ankit0812
Copy link

I want to get the new string according to the currentTimeZone?
For example : My date is 2019-08-20 21:50:00 UTC
I am in IST
I get "Tomorrow"
But i need to get it according to IST which should be day after tomorrow

@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