// // Foundation+TimeAgo.swift // // The MIT License (MIT) // // Copyright (c) 2015-present patrick piemonte (http://patrickpiemonte.com/) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. // extension Date { public var millisecondsSince1970: Int { Int((self.timeIntervalSince1970 * 1000.0).rounded()) } public var yesterday: Date { Calendar.current.date(byAdding: .day, value: -1, to: self)! } public func hoursFromNow() -> Int { let date = Date() return Calendar.current.dateComponents([.hour], from: date, to: self).hour ?? 0 } public func minutesFromNow() -> Int { let date = Date() return Calendar.current.dateComponents([.minute], from: date, to: self).hour ?? 0 } public func hours(from date: Date) -> Int { Calendar.current.dateComponents([.hour], from: date, to: self).hour ?? 0 } public func minutes(from date: Date) -> Int { Calendar.current.dateComponents([.minute], from: date, to: self).minute ?? 0 } private static let shortPrettyDateFormatter = DateFormatter() /// Returns a short pretty date. /// - Returns: Formatted date string. public func shortPrettyDate() -> String { Date.shortPrettyDateFormatter.dateFormat = "M/d/yy" return Date.shortPrettyDateFormatter.string(from: self) } private static let shortPrettyDateAndTimeFormatter = DateFormatter() /// Returns a short pretty date and time. /// - Returns: Formatted date and time string. public func shortPrettyDateTime() -> String { Date.shortPrettyDateAndTimeFormatter.dateFormat = "M/d/yyyy h:mma" return Date.shortPrettyDateAndTimeFormatter.string(from: self) } private static let prettyDateFormatter = DateFormatter() /// Return a short pretty date. /// - Returns: Formatted date string. public func prettyDate() -> String { Date.prettyDateFormatter.dateFormat = "MMMM yyyy" return Date.prettyDateFormatter.string(from: self) } private static let fullPrettyDateFormatter = DateFormatter() /// Return a short pretty date. /// - Returns: Formatted date string. public func fullPrettyDate() -> String { Date.prettyDateFormatter.dateFormat = "MMMM d, yyyy" return Date.prettyDateFormatter.string(from: self) } /// Create a pretty formatted string of time passed based on the date components, ex: "Last month", "2 weeks ago", "Just now" /// - Parameter numericDates: A flag to determine if a numerical string should be used, ex: "An hour ago" vs "1 hour ago". /// - Returns: Formatted string of time passed. public func timeAgo(numericDates: Bool = true) -> String { let calendar = Calendar.current let now = Date() let earliest = self < now ? self : now let latest = self > now ? self : now let unitFlags: Set = [.minute, .hour, .day, .weekOfMonth, .month, .year, .second] let components: DateComponents = calendar.dateComponents(unitFlags, from: earliest, to: latest) let year = components.year ?? 0 let month = components.month ?? 0 let weekOfMonth = components.weekOfMonth ?? 0 let day = components.day ?? 0 let hour = components.hour ?? 0 let minute = components.minute ?? 0 let second = components.second ?? 0 switch (year, month, weekOfMonth, day, hour, minute, second) { case (let year, _, _, _, _, _, _) where year >= 2: return NSLocalizedString("\(year) years ago", comment: "\(year) years ago") case (let year, _, _, _, _, _, _) where year == 1 && numericDates: return NSLocalizedString("1 year ago", comment: "1 year ago") case (let year, _, _, _, _, _, _) where year == 1 && !numericDates: return NSLocalizedString("Last year", comment: "Last year") case (_, let month, _, _, _, _, _) where month >= 2: return NSLocalizedString("\(month) months ago", comment: "\(month) months ago") case (_, let month, _, _, _, _, _) where month == 1 && numericDates: return NSLocalizedString("1 month ago", comment: "1 month ago") case (_, let month, _, _, _, _, _) where month == 1 && !numericDates: return NSLocalizedString("Last month", comment: "Last month") case (_, _, let weekOfMonth, _, _, _, _) where weekOfMonth >= 2: return NSLocalizedString("\(weekOfMonth) weeks ago", comment: "\(weekOfMonth) weeks ago") case (_, _, let weekOfMonth, _, _, _, _) where weekOfMonth == 1 && numericDates: return NSLocalizedString("1 week ago", comment: "1 week ago") case (_, _, let weekOfMonth, _, _, _, _) where weekOfMonth == 1 && !numericDates: return NSLocalizedString("Last week", comment: "Last week") case (_, _, _, let day, _, _, _) where day >= 2: return NSLocalizedString("\(day) days ago", comment: "\(day) days ago") case (_, _, _, let day, _, _, _) where day == 1 && numericDates: return NSLocalizedString("1 day ago", comment: "1 day ago") case (_, _, _, let day, _, _, _) where day == 1 && !numericDates: return NSLocalizedString("Yesterday", comment: "Yesterday") case (_, _, _, _, let hour, _, _) where hour >= 2: return NSLocalizedString("\(hour) hours ago", comment: "\(hour) hours ago") case (_, _, _, _, let hour, _, _) where hour == 1 && numericDates: return NSLocalizedString("1 hour ago", comment: "1 hour ago") case (_, _, _, _, let hour, _, _) where hour == 1 && !numericDates: return NSLocalizedString("An hour ago", comment: "An hour ago") case (_, _, _, _, _, let minute, _) where minute >= 2: return NSLocalizedString("\(minute) minutes ago", comment: "\(minute) minutes ago") case (_, _, _, _, _, let minute, _) where minute == 1 && numericDates: return NSLocalizedString("1 minute ago", comment: "1 minute ago") case (_, _, _, _, _, let minute, _) where minute == 1 && !numericDates: return NSLocalizedString("A minute ago", comment: "A minute ago") case (_, _, _, _, _, _, let second) where second >= 3: return NSLocalizedString("\(second) seconds ago", comment: "\(second) seconds ago") default: return NSLocalizedString("Just now", comment: "Just now") } } /// Create a short pretty formatted string of time passed based on the date components, ex: "2y", "2mo", "now". /// - Returns: Short formatted string of time passed. public func shortTimeAgo() -> String { let calendar = Calendar.current let now = Date() let earliest = self < now ? self : now let latest = self > now ? self : now let unitFlags: Set = [.minute, .hour, .day, .weekOfMonth, .month, .year, .second] let components: DateComponents = calendar.dateComponents(unitFlags, from: earliest, to: latest) let year = components.year ?? 0 let month = components.month ?? 0 let weekOfMonth = components.weekOfMonth ?? 0 let day = components.day ?? 0 let hour = components.hour ?? 0 let minute = components.minute ?? 0 let second = components.second ?? 0 switch (year, month, weekOfMonth, day, hour, minute, second) { case (let year, _, _, _, _, _, _) where year >= 1: return NSLocalizedString("\(year)y", comment: "\(year)y") case (_, let month, _, _, _, _, _) where month >= 1: return NSLocalizedString("\(month)mo", comment: "\(month)mo") case (_, _, let weekOfMonth, _, _, _, _) where weekOfMonth >= 1: return NSLocalizedString("\(weekOfMonth)w", comment: "\(weekOfMonth)w") case (_, _, _, let day, _, _, _) where day >= 1: return NSLocalizedString("\(day)d", comment: "\(day)d") case (_, _, _, _, let hour, _, _) where hour >= 1: return NSLocalizedString("\(hour)h", comment: "\(hour)h") case (_, _, _, _, _, let minute, _) where minute >= 1: return NSLocalizedString("\(minute)m", comment: "\(minute)m") case (_, _, _, _, _, _, let second) where second >= 0: return NSLocalizedString("\(second)s", comment: "\(second)s") default: return NSLocalizedString("now", comment: "now") } } }