Reputation: 527
In a cell I want to display the time ago from the NSDate in the Parse server. Here is the code but its not working. Nothing is changing, and the data isn't being parsed.
if let createdat = (object?["createdAt"] as? String){
let pastDate = Date(timeIntervalSinceNow: TimeInterval(createdat)!)
cell.TimeAgo.text = pastDate.timeAgoDisplay()
}
extension Date {
func timeAgoDisplay() -> String {
let secondsAgo = Int(Date().timeIntervalSince(self))
let minute = 60
let hour = 60 * minute
let day = 24 * hour
let week = 7 * day
if secondsAgo < minute {
return "\(secondsAgo) sec ago"
} else if secondsAgo < hour {
return "\(secondsAgo / minute) min ago"
} else if secondsAgo < day {
return "\(secondsAgo / hour) hrs ago"
} else if secondsAgo < week {
return "\(secondsAgo / day) days ago"
}
return "\(secondsAgo / week) weeks ago"
}
}
Upvotes: 35
Views: 25852
Reputation: 12647
///This example rounds to "one unit", examples "27d" or "3m".
let _agoFormatter: DateComponentsFormatter = {
let f = DateComponentsFormatter()
f.unitsStyle = .abbreviated
f.allowedUnits = [.day, .hour, .minute]
f.maximumUnitCount = 1
return f
}()
Simply play with the various values, eg maximumUnitCount
to get what you want.
// let d ... the Date you are interested in
print( _agoFormatter.string(from: d, to: Date.now )
That's it.
Upvotes: 0
Reputation: 67
You can use timeIntervalSince
to get the difference between two dates in seconds. Then compare secondsAgo to seconds, minutes, hours, days, weeks, months and years to determine the correct String suffix.
You can use this function to return formatted time ago by simply passing it a date and preference for long (3 days ago) or short (3d ago).
See my full guide here: How to display time ago from Date
Full code:
func getTimeSince(date: Date, isShort: Bool = false) -> String {
var formattedString = String()
let now = Date()
let secondsAgo = Int(now.timeIntervalSince(date))
let twoSeconds = 2
let minute = 60
let twoMinutes = minute * 2
let hour = 60 * minute
let twoHours = hour * 2
let day = 24 * hour
let twoDays = day * 2
let week = 7 * day
let twoWeeks = week * 2
let month = 4 * week
let twoMonths = month * 2
let year = 12 * month
let twoYears = year * 2
let secondString = isShort ? "s ago" : " second ago"
let secondsString = isShort ? "s ago" : " seconds ago"
let minuteString = isShort ? "m ago" : " minute ago"
let minutesString = isShort ? "m ago" : " minutes ago"
let hourString = isShort ? "h ago" : " hour ago"
let hoursString = isShort ? "h ago" : " hours ago"
let dayString = isShort ? "d ago" : " day ago"
let daysString = isShort ? "d ago" : " days ago"
let weekString = isShort ? "w ago" : " week ago"
let weeksString = isShort ? "w ago" : " weeks ago"
let monthString = isShort ? "mo ago" : " month ago"
let monthsString = isShort ? "mo ago" : " months ago"
let yearString = isShort ? "y ago" : " year ago"
let yearsString = isShort ? "y ago" : " years ago"
if secondsAgo < twoSeconds {
formattedString = "\(secondsAgo)\(secondString)"
} else if secondsAgo < minute {
formattedString = "\(secondsAgo)\(secondsString)"
} else if secondsAgo < twoMinutes {
formattedString = "\(secondsAgo / minute)\(minuteString)"
} else if secondsAgo < hour {
formattedString = "\(secondsAgo / minute)\(minutesString)"
} else if secondsAgo < twoHours {
formattedString = "\(secondsAgo / hour)\(hourString)"
} else if secondsAgo < day {
formattedString = "\(secondsAgo / hour)\(hoursString)"
} else if secondsAgo < twoDays {
formattedString = "\(secondsAgo / day)\(dayString)"
} else if secondsAgo < week {
formattedString = "\(secondsAgo / day)\(daysString)"
} else if secondsAgo < twoWeeks {
formattedString = "\(secondsAgo / week)\(weekString)"
} else if secondsAgo < month {
formattedString = "\(secondsAgo / week)\(weeksString)"
} else if secondsAgo < twoMonths {
formattedString = "\(secondsAgo / month)\(monthString)"
} else if secondsAgo < year {
formattedString = "\(secondsAgo / month)\(monthsString)"
} else if secondsAgo < twoYears {
formattedString = "\(secondsAgo / year)\(yearString)"
} else {
formattedString = "\(secondsAgo / year)\(yearsString)"
}
return formattedString
}
Usage:
let formattedTimeAgo = self.getTimeSince(date: date, isShort: false)
Upvotes: -1
Reputation: 5479
If you just want a Time Ago extension for Date go to the bottom of the answer 😊
I'll show you an example just to get seconds ago and after I'll show your extension updated.
Note: you can use directly the date from Pase if you want:
if let pastDate = (object?["createdAt"] as? Date) {
cell.TimeAgo.text = pastDate.timeAgoDisplay()
}
Example how to display seconds ago with Swift 5.1:
Since iOS13 Apple introduce a new class RelativeDateTimeFormatter
extension Date {
func timeAgoDisplay() -> String {
let formatter = RelativeDateTimeFormatter()
formatter.unitsStyle = .full
return formatter.localizedString(for: self, relativeTo: Date())
}
}
This class will allow you to get a time ago string based on your language. It automatically select the right unit of time based on your interval, here is an example:
|--------------------------|------------------|
| Time interval in seconds | Display |
|--------------------------|------------------|
| -6 | 6 seconds ago |
| -60 | 1 minute ago |
| -600 | 10 minutes ago |
| -6000 | 1 hour ago |
| -60000 | 16 hours ago |
|--------------------------|------------------|
You'll notice that it handle automatically plurals for you.
Example how to get seconds ago with Swift 3 or Swift 4:
First: To get the number of seconds ago we need to check if we have one minutes or less, to get the current Date minus one minute you can write that:
let minuteAgo = calendar.date(byAdding: .minute, value: -1, to: Date())!
Second: Now compare the 2 dates! (In the case of your extension we replace yourDate by self) and get the difference between this 2 dates.
if (minuteAgo < yourDate) {
let diff = Calendar.current.dateComponents([.second], from: yourDate, to: Date()).second ?? 0
print("\(diff) sec ago")
}
That's all, now you can print the time ago !
So your extension is like this: (This is a simple extension to get the time ago)
extension Date {
func timeAgoDisplay() -> String {
let calendar = Calendar.current
let minuteAgo = calendar.date(byAdding: .minute, value: -1, to: Date())!
let hourAgo = calendar.date(byAdding: .hour, value: -1, to: Date())!
let dayAgo = calendar.date(byAdding: .day, value: -1, to: Date())!
let weekAgo = calendar.date(byAdding: .day, value: -7, to: Date())!
if minuteAgo < self {
let diff = Calendar.current.dateComponents([.second], from: self, to: Date()).second ?? 0
return "\(diff) sec ago"
} else if hourAgo < self {
let diff = Calendar.current.dateComponents([.minute], from: self, to: Date()).minute ?? 0
return "\(diff) min ago"
} else if dayAgo < self {
let diff = Calendar.current.dateComponents([.hour], from: self, to: Date()).hour ?? 0
return "\(diff) hrs ago"
} else if weekAgo < self {
let diff = Calendar.current.dateComponents([.day], from: self, to: Date()).day ?? 0
return "\(diff) days ago"
}
let diff = Calendar.current.dateComponents([.weekOfYear], from: self, to: Date()).weekOfYear ?? 0
return "\(diff) weeks ago"
}
}
To use it, this is very straightforward:
var now = Date()
now.timeAgoDisplay()
Upvotes: 106
Reputation: 562
If you have only timestamp from 1970. You can use this function to return time ago.
private func timestampToStringAgo(timestamp: Int64) -> String{
let actualTime = Int64(Date().timeIntervalSince1970*1000)
var lastSeenTime = actualTime - timestamp
lastSeenTime /= 1000 //seconds
var lastTimeString = ""
if lastSeenTime < 60 {
if lastSeenTime == 1 {
lastTimeString = String(lastSeenTime) + " second ago"
} else {
lastTimeString = String(lastSeenTime) + " seconds ago"
}
} else {
lastSeenTime /= 60
if lastSeenTime < 60 {
if lastSeenTime == 1 {
lastTimeString = String(lastSeenTime) + " minute ago"
} else {
lastTimeString = String(lastSeenTime) + " minutes ago"
}
} else {
lastSeenTime /= 60
if lastSeenTime < 24 {
if lastSeenTime == 1 {
lastTimeString = String(lastSeenTime) + " hour ago"
} else {
lastTimeString = String(lastSeenTime) + " hours ago"
}
} else {
lastSeenTime /= 24
if lastSeenTime == 1 {
lastTimeString = String(lastSeenTime) + " day ago"
} else {
lastTimeString = String(lastSeenTime) + " days ago"
}
}
}
}
return lastTimeString
}
Upvotes: 0
Reputation: 11184
It's a bit tricky)
Basically u need to
iOS provide few ways to do this
DateComponentsFormatter
+: no work with localization and other string-related stuff
-: not very flexible
let formatter = DateComponentsFormatter()
formatter.allowedUnits = [.hour, .minute, .second]
formatter.unitsStyle = .brief
formatter.zeroFormattingBehavior = .dropAll
let result = formatter.string(from: Date().advanced(by: -300), to: Date())
result
Result:
"5min"
RelativeDateTimeFormatter
+: no work with localization and other string-related stuff
-: iOS13+
let formatter = RelativeDateTimeFormatter()
formatter.unitsStyle = .full
return formatter.localizedString(for: self, relativeTo: Date())
Custom way
+: flexible
-: code everything
Sample:
import Foundation
public extension Date {
struct DetailedDateSuffix {
let year: String
let month: String
let week: String
let day: String
let hour: String
let min: String
let second: String
let quotient: String
let suffix: String
public init(year: String,
week: String,
month: String,
day: String,
hour: String,
min: String,
second: String,
quotient: String,
suffix: String = String.empty) {
self.year = year
self.month = month
self.week = week
self.day = day
self.hour = hour
self.min = min
self.second = second
self.quotient = quotient
self.suffix = suffix
}
}
func toDetailedReadableFormat(_ suffix: DetailedDateSuffix) -> String {
if #available(iOS 13.0, *) {
let formatter = RelativeDateTimeFormatter()
formatter.unitsStyle = .full
return formatter.localizedString(for: self, relativeTo: Date())
} else {
let calendar = Calendar.current
let ageComponents = calendar.dateComponents(
[
.year,
.month,
.weekOfYear,
.day,
.hour,
.minute,
.second
],
from: self,
to: Date())
var description: String = String.empty
if let years = ageComponents.year,
let months = ageComponents.month,
let weeks = ageComponents.weekOfYear,
let days = ageComponents.day,
let hours = ageComponents.hour,
let min = ageComponents.minute,
let sec = ageComponents.second {
var requireQuotient = false
if years > 0 {
description = "\(years)" + suffix.year
requireQuotient = years == 1
} else if months > 0 {
description = "\(months)" + suffix.month
requireQuotient = months == 1
} else if weeks > 0 {
description = "\(weeks)" + suffix.week
requireQuotient = weeks == 1
} else if days > 0 {
description = "\(days)" + suffix.day
requireQuotient = days == 1
} else if hours > 0 {
description = "\(hours)" + suffix.hour
requireQuotient = hours == 1
} else if min > 0 {
description = "\(min)" + suffix.min
requireQuotient = min == 1
} else if sec > 0 {
description = "\(sec)" + suffix.second
requireQuotient = sec == 1
}
description = requireQuotient ? "\(description)\(suffix.quotient)" : description
description = "\(description)\(suffix.suffix)"
}
return description
}
}
}
Upvotes: 5
Reputation: 2142
Here is the solution in Swift 5:
extension Date {
func timeAgo() -> String {
let secondsAgo = Int(Date().timeIntervalSince(self))
let minute = 60
let hour = 60 * minute
let day = 24 * hour
let week = 7 * day
let month = 4 * week
let quotient: Int
let unit: String
if secondsAgo < minute {
quotient = secondsAgo
unit = "second"
} else if secondsAgo < hour {
quotient = secondsAgo / minute
unit = "min"
} else if secondsAgo < day {
quotient = secondsAgo / hour
unit = "hour"
} else if secondsAgo < week {
quotient = secondsAgo / day
unit = "day"
} else if secondsAgo < month {
quotient = secondsAgo / week
unit = "week"
} else {
quotient = secondsAgo / month
unit = "month"
}
return "\(quotient) \(unit)\(quotient == 1 ? "" : "s") ago"
}
}
Upvotes: 7
Reputation: 15748
Since iOS 13 you can use Apple's RelativeDateFormatter. The advantage is the resulting string is localized.
let date = Date().addingTimeInterval(-15000)
let formatter = RelativeDateTimeFormatter()
formatter.unitsStyle = .full
let string = formatter.localizedString(for: date, relativeTo: Date())
print(string) // 4 hours ago
See for example this blog post.
Upvotes: 26
Reputation: 47
Finally got a simple solution for me in swift4.2
let start = //Enter Start Date here....
let end = Date()
let formatter = DateComponentsFormatter()
formatter.maximumUnitCount = 2
formatter.unitsStyle = .full
formatter.allowedUnits = [.year, .month, .day]
let timeDifference = form.string(from: start, to: end)
print(timeDifference)
if timeDifference == "0 days"{
print("Today")
}
else if timeDifference == "1 days"{
print("\(timeDifference!)day ago")
}
else{
print("\(timeDifference!)days ago")
}
Upvotes: 1
Reputation: 4377
let now = Date()
let pastDate = Date(timeIntervalSinceNow: -60 * 60 * 24)
enum DisplayTime {
case short
case long
var seconds: String {
switch self {
case .short: return "s"
case .long: return "seconds"
}
}
var minutes: String {
switch self {
case .short: return "m"
case .long: return "minutes"
}
}
var hours: String {
switch self {
case .short: return "h"
case .long: return "hours"
}
}
var days: String {
switch self {
case .short: return "d"
case .long: return "days"
}
}
var weeks: String {
switch self {
case .short: return "w"
case .long: return "weeks"
}
}
}
extension Date {
func timeAgoDisplay(_ display: DisplayTime) -> String {
let secondsAgo = Int(Date().timeIntervalSince(self))
let minute = 60
let hour = 60 * minute
let day = 24 * hour
let week = 7 * day
switch secondsAgo {
case let seconds where seconds < minute : return "\(secondsAgo) \(display.seconds) ago"
case let seconds where seconds < hour: return "\(secondsAgo / minute) \(display.minutes) ago"
case let seconds where seconds < day: return "\(secondsAgo / hour) \(display.hours) ago"
case let seconds where seconds < week: return "\(secondsAgo / day) \(display.days) ago"
default: "\(secondsAgo / week) \(display.weeks) ago"
}
return "\(secondsAgo / week) \(display.weeks) ago"
}
}
pastDate.timeAgoDisplay(.short)
Upvotes: 1
Reputation: 47
Pass time as String in format e.g. 2019-02-25 10:20:21 Pass dateformat in Variable dateFormat
let dateFormat = "yyyy-MM-dd HH:mm:ss"
func timeInterval(timeAgo:String) -> String
{
let df = DateFormatter()
df.dateFormat = dateFormat
let dateWithTime = df.date(from: timeAgo)
let interval = Calendar.current.dateComponents([.year, .month, .day, .hour, .minute, .second], from: dateWithTime!, to: Date())
if let year = interval.year, year > 0 {
return year == 1 ? "\(year)" + " " + "year ago" : "\(year)" + " " + "years ago"
} else if let month = interval.month, month > 0 {
return month == 1 ? "\(month)" + " " + "month ago" : "\(month)" + " " + "months ago"
} else if let day = interval.day, day > 0 {
return day == 1 ? "\(day)" + " " + "day ago" : "\(day)" + " " + "days ago"
}else if let hour = interval.hour, hour > 0 {
return hour == 1 ? "\(hour)" + " " + "hour ago" : "\(hour)" + " " + "hours ago"
}else if let minute = interval.minute, minute > 0 {
return minute == 1 ? "\(minute)" + " " + "minute ago" : "\(minute)" + " " + "minutes ago"
}else if let second = interval.second, second > 0 {
return second == 1 ? "\(second)" + " " + "second ago" : "\(second)" + " " + "seconds ago"
} else {
return "a moment ago"
}
}
Upvotes: 1