Created
January 18, 2017 05:21
-
-
Save kunikullaya/6474fc6537ed616b1c617646d263555d to your computer and use it in GitHub Desktop.
Date Extension for Swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
extension Date { | |
func toString(format: String = "yyyy-MM-dd") -> String { | |
let formatter = DateFormatter() | |
formatter.dateStyle = .short | |
formatter.dateFormat = format | |
return formatter.string(from: self) | |
} | |
func dateAndTimetoString(format: String = "yyyy-MM-dd HH:mm") -> String { | |
let formatter = DateFormatter() | |
formatter.dateStyle = .short | |
formatter.dateFormat = format | |
return formatter.string(from: self) | |
} | |
func timeIn24HourFormat() -> String { | |
let formatter = DateFormatter() | |
formatter.dateStyle = .none | |
formatter.dateFormat = "HH:mm" | |
return formatter.string(from: self) | |
} | |
func startOfMonth() -> Date { | |
var components = Calendar.current.dateComponents([.year,.month], from: self) | |
components.day = 1 | |
let firstDateOfMonth: Date = Calendar.current.date(from: components)! | |
return firstDateOfMonth | |
} | |
func endOfMonth() -> Date { | |
return Calendar.current.date(byAdding: DateComponents(month: 1, day: -1), to: self.startOfMonth())! | |
} | |
func nextDate() -> Date { | |
let nextDate = Calendar.current.date(byAdding: .day, value: 1, to: self) | |
return nextDate ?? Date() | |
} | |
func previousDate() -> Date { | |
let previousDate = Calendar.current.date(byAdding: .day, value: -1, to: self) | |
return previousDate ?? Date() | |
} | |
func addMonths(numberOfMonths: Int) -> Date { | |
let endDate = Calendar.current.date(byAdding: .month, value: numberOfMonths, to: self) | |
return endDate ?? Date() | |
} | |
func removeMonths(numberOfMonths: Int) -> Date { | |
let endDate = Calendar.current.date(byAdding: .month, value: -numberOfMonths, to: self) | |
return endDate ?? Date() | |
} | |
func removeYears(numberOfYears: Int) -> Date { | |
let endDate = Calendar.current.date(byAdding: .year, value: -numberOfYears, to: self) | |
return endDate ?? Date() | |
} | |
func getHumanReadableDayString() -> String { | |
let weekdays = [ | |
"Sunday", | |
"Monday", | |
"Tuesday", | |
"Wednesday", | |
"Thursday", | |
"Friday", | |
"Saturday" | |
] | |
let calendar = Calendar.current.component(.weekday, from: self) | |
return weekdays[calendar - 1] | |
} | |
func timeSinceDate(fromDate: Date) -> String { | |
let earliest = self < fromDate ? self : fromDate | |
let latest = (earliest == self) ? fromDate : self | |
let components:DateComponents = Calendar.current.dateComponents([.minute,.hour,.day,.weekOfYear,.month,.year,.second], from: earliest, to: latest) | |
let year = components.year ?? 0 | |
let month = components.month ?? 0 | |
let week = components.weekOfYear ?? 0 | |
let day = components.day ?? 0 | |
let hours = components.hour ?? 0 | |
let minutes = components.minute ?? 0 | |
let seconds = components.second ?? 0 | |
if year >= 2{ | |
return "\(year) years ago" | |
}else if (year >= 1){ | |
return "1 year ago" | |
}else if (month >= 2) { | |
return "\(month) months ago" | |
}else if (month >= 1) { | |
return "1 month ago" | |
}else if (week >= 2) { | |
return "\(week) weeks ago" | |
} else if (week >= 1){ | |
return "1 week ago" | |
} else if (day >= 2) { | |
return "\(day) days ago" | |
} else if (day >= 1){ | |
return "1 day ago" | |
} else if (hours >= 2) { | |
return "\(hours) hours ago" | |
} else if (hours >= 1){ | |
return "1 hour ago" | |
} else if (minutes >= 2) { | |
return "\(minutes) minutes ago" | |
} else if (minutes >= 1){ | |
return "1 minute ago" | |
} else if (seconds >= 3) { | |
return "\(seconds) seconds ago" | |
} else { | |
return "Just now" | |
} | |
} | |
} |
Swift's Dictionaries are not ordered - hey hey
class DateTests: XCTestCase {
func testBackToTheFuture() {
let date = Date(timeIntervalSinceNow: 1)
XCTAssertEqual(Date.time(since: date), "Back to the future", "Wrong time ago")
}
func testTimeSinceSeconds() {
let expectations: [(Int, String)] = [
(3, "3 seconds ago"),
(3 * 60, "3 minutes ago"),
(3 * 60 * 60, "3 hours ago"),
(3 * 60 * 60 * 24, "3 days ago"),
(3 * 60 * 60 * 24 * 7, "3 weeks ago"),
(3 * 60 * 60 * 24 * 31, "3 months ago"),
(3 * 60 * 60 * 24 * 366, "3 years ago"),
]
for expectation in expectations {
let (seconds, expected) = expectation
let date = Date(timeIntervalSinceNow: Double(-seconds))
XCTAssertEqual(Date.time(since: date), expected, "Wrong time ago")
}
}
}
extension Date {
static func time(since fromDate: Date) -> String {
guard fromDate < Date() else { return "Back to the future" }
let allComponents: Set<Calendar.Component> = [.second, .minute, .hour, .day, .weekOfYear, .month, .year]
let components:DateComponents = Calendar.current.dateComponents(allComponents, from: fromDate, to: Date())
for (period, timeAgo) in [
("year", components.year ?? 0),
("month", components.month ?? 0),
("week", components.weekOfYear ?? 0),
("day", components.day ?? 0),
("hour", components.hour ?? 0),
("minute", components.minute ?? 0),
("second", components.second ?? 0),
] {
if timeAgo > 0 {
return "\(timeAgo.of(period)) ago"
}
}
return "Just now"
}
}
Swift's Dictionaries are not ordered - hey hey
A little swiftier:
var nextDay: Date {
let nextDate = Calendar.current.date(byAdding: .day, value: 1, to: self)
return nextDate ?? Date()
}
var previousDay: Date {
let previousDate = Calendar.current.date(byAdding: .day, value: -1, to: self)
return previousDate ?? Date()
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks for posting this here! I used the
timeSinceDate
function. Here is my refactored version: