Swift 转换时间到时间之前
Swift convert time to time ago
在 Swift5 中,我们有 RelativeDateTimeFormatter
Swift5 之前的版本:
我正在尝试将时间转换为以前的时间,我想做的是:
从 1 到 15 秒它会说“刚刚”
从 60 分钟到 119 分钟,它会说“一个小时前”
从 24 小时到 47 小时它会说“昨天”
从 7 天到 7 天 23 小时它会说“一周前”
我不确定我的计数是否错误,请随时为我修正
这是代码
extension NSDate {
struct Date {
static let timeFormatter: NSDateFormatter = {
let df = NSDateFormatter()
df.calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)
df.dateFormat = "h:mm a"
return df
}()
}
var time: String { return Date.timeFormatter.stringFromDate(self) }
var year: Int { return NSCalendar.autoupdatingCurrentCalendar().component(.Year, fromDate: self) }
var month: Int { return NSCalendar.autoupdatingCurrentCalendar().component(.Month, fromDate: self) }
var day: Int { return NSCalendar.autoupdatingCurrentCalendar().component(.Day, fromDate: self) }
var hour: Int { return NSCalendar.autoupdatingCurrentCalendar().component(.Hour, fromDate: self) }
var minute: Int { return NSCalendar.autoupdatingCurrentCalendar().component(.Minute, fromDate: self) }
var second: Int { return NSCalendar.autoupdatingCurrentCalendar().component(.Second, fromDate: self) }
struct DateComponents {
static let formatter: NSDateComponentsFormatter = {
let dcFormatter = NSDateComponentsFormatter()
dcFormatter.calendar = NSCalendar(identifier: NSCalendarIdentifierISO8601)!
dcFormatter.unitsStyle = .Full
dcFormatter.maximumUnitCount = 1
dcFormatter.zeroFormattingBehavior = .Default
dcFormatter.allowsFractionalUnits = false
dcFormatter.allowedUnits = [.Year, .Month, .Weekday, .Day, .Hour, .Minute, .Second]
return dcFormatter
}()
}
var elapsedTime: String {
if isecond(NSDate()) {
return "Just now"
}
if ishour(NSDate()) {
return "an hour ago"
}
if isyesterday(NSDate()) {
return "Yesterday"
}
if isweek(NSDate()) {
return "a week ago"
}
return (DateComponents.formatter.stringFromTimeInterval(NSDate().timeIntervalSinceDate(self)) ?? "") + " ago"
}
func isyesterday(date: NSDate) -> Bool {
return NSCalendar.autoupdatingCurrentCalendar().isDate(self, inSameDayAsDate: date.yesterday)
}
var yesterday: NSDate {
return NSCalendar.autoupdatingCurrentCalendar().dateWithEra(1, year: year, month: month, day: day-1, hour: 0, minute: 0, second: 0, nanosecond: 0)!
}
func isweek(date: NSDate) -> Bool {
return NSCalendar.autoupdatingCurrentCalendar().isDate(self, inSameDayAsDate: date.weekago)
}
var weekago: NSDate {
return NSCalendar.autoupdatingCurrentCalendar().dateWithEra(1, year: year, month: month, day: day-7, hour: 0, minute: 0, second: 0, nanosecond: 0)!
}
func isecond(date: NSDate) -> Bool {
return NSCalendar.autoupdatingCurrentCalendar().isDate(self, inSameDayAsDate: date.secondsago)
}
var secondsago: NSDate {
return NSCalendar.autoupdatingCurrentCalendar().dateWithEra(1, year: year, month: month, day: 0, hour: 0, minute: 0, second: second-15, nanosecond: 0)!
}
func ishour(date: NSDate) -> Bool {
return NSCalendar.autoupdatingCurrentCalendar().isDate(self, inSameDayAsDate: date.hourago)
}
var hourago: NSDate {
return NSCalendar.autoupdatingCurrentCalendar().dateWithEra(1, year: year, month: month, day: 0, hour: hour-1, minute: minute-1, second: 0, nanosecond: 0)!
}
}
这是我在我的应用程序中得到的:
"an hour ago"、“刚才”等引号没有显示,只显示“昨天”,我不确定是否只有 7 天到 23 小时!
这是我的第一个问题 link:
请帮我修改代码,
感谢@Leo Dabus 提供的代码。
根据需要更改文本。
extension NSDate {
func getElapsedInterval() -> String {
var interval = NSCalendar.currentCalendar().components(.Year, fromDate: self, toDate: NSDate(), options: []).year
if interval > 0 {
return interval == 1 ? "\(interval)" + " " + "year" :
"\(interval)" + " " + "years"
}
interval = NSCalendar.currentCalendar().components(.Month, fromDate: self, toDate: NSDate(), options: []).month
if interval > 0 {
return interval == 1 ? "\(interval)" + " " + "month" :
"\(interval)" + " " + "months"
}
interval = NSCalendar.currentCalendar().components(.Day, fromDate: self, toDate: NSDate(), options: []).day
if interval > 0 {
return interval == 1 ? "\(interval)" + " " + "day" :
"\(interval)" + " " + "days"
}
interval = NSCalendar.currentCalendar().components(.Hour, fromDate: self, toDate: NSDate(), options: []).hour
if interval > 0 {
return interval == 1 ? "\(interval)" + " " + "hour" :
"\(interval)" + " " + "hours"
}
interval = NSCalendar.currentCalendar().components(.Minute, fromDate: self, toDate: NSDate(), options: []).minute
if interval > 0 {
return interval == 1 ? "\(interval)" + " " + "minute" :
"\(interval)" + " " + "minutes"
}
return "a moment ago"
}
}
我将更新 Truongky 对 Swif 3 的回答:
extension Date {
func getElapsedInterval() -> String {
let interval = Calendar.current.dateComponents([.year, .month, .day], from: self, 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 {
return "a moment ago"
}
}
}
如果您更喜欢可本地化的响应而不是仅使用英语,则此代码可以完成工作
extension Date {
func getElapsedInterval() -> String {
var calendar = Calendar.current
calendar.locale = Locale(identifier: Bundle.main.preferredLocalizations[0])
// IF THE USER HAVE THE PHONE IN SPANISH BUT YOUR APP ONLY SUPPORTS I.E. ENGLISH AND GERMAN
// WE SHOULD CHANGE THE LOCALE OF THE FORMATTER TO THE PREFERRED ONE
// (IS THE LOCALE THAT THE USER IS SEEING THE APP), IF NOT, THIS ELAPSED TIME
// IS GOING TO APPEAR IN SPANISH
let formatter = DateComponentsFormatter()
formatter.unitsStyle = .full
formatter.maximumUnitCount = 1
formatter.calendar = calendar
var dateString: String?
let interval = calendar.dateComponents([.year, .month, .weekOfYear, .day], from: self, to: Date())
if let year = interval.year, year > 0 {
formatter.allowedUnits = [.year] //2 years
} else if let month = interval.month, month > 0 {
formatter.allowedUnits = [.month] //1 month
} else if let week = interval.weekOfYear, week > 0 {
formatter.allowedUnits = [.weekOfMonth] //3 weeks
} else if let day = interval.day, day > 0 {
formatter.allowedUnits = [.day] // 6 days
} else {
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: Bundle.main.preferredLocalizations[0]) //--> IF THE USER HAVE THE PHONE IN SPANISH BUT YOUR APP ONLY SUPPORTS I.E. ENGLISH AND GERMAN WE SHOULD CHANGE THE LOCALE OF THE FORMATTER TO THE PREFERRED ONE (IS THE LOCALE THAT THE USER IS SEEING THE APP), IF NOT, THIS ELAPSED TIME IS GOING TO APPEAR IN SPANISH
dateFormatter.dateStyle = .medium
dateFormatter.doesRelativeDateFormatting = true
dateString = dateFormatter.string(from: self) // IS GOING TO SHOW 'TODAY'
}
if dateString == nil {
dateString = formatter.string(from: self, to: Date())
}
return dateString!
}
Swift 3 版本 :
extension Date {
var timeAgoSinceNow: String {
return getTimeAgoSinceNow()
}
private func getTimeAgoSinceNow() -> String {
var interval = Calendar.current.dateComponents([.year], from: self, to: Date()).year!
if interval > 0 {
return interval == 1 ? "\(interval)" + " year" : "\(interval)" + " years"
}
interval = Calendar.current.dateComponents([.month], from: self, to: Date()).month!
if interval > 0 {
return interval == 1 ? "\(interval)" + " month" : "\(interval)" + " months"
}
interval = Calendar.current.dateComponents([.day], from: self, to: Date()).day!
if interval > 0 {
return interval == 1 ? "\(interval)" + " day" : "\(interval)" + " days"
}
interval = Calendar.current.dateComponents([.hour], from: self, to: Date()).hour!
if interval > 0 {
return interval == 1 ? "\(interval)" + " hour" : "\(interval)" + " hours"
}
interval = Calendar.current.dateComponents([.minute], from: self, to: Date()).minute!
if interval > 0 {
return interval == 1 ? "\(interval)" + " minute" : "\(interval)" + " minutes"
}
return "a moment ago"
}
}
使用 Date 而不是 NSDate:Answer taking from:
func timeAgoSinceDate(_ date:Date, numericDates:Bool = false) -> String {
let calendar = NSCalendar.current
let unitFlags: Set<Calendar.Component> = [.minute, .hour, .day, .weekOfYear, .month, .year, .second]
let now = Date()
let earliest = now < date ? now : date
let latest = (earliest == now) ? date : now
let components = calendar.dateComponents(unitFlags, from: earliest, to: latest)
if (components.year! >= 2) {
return "\(components.year!) years ago"
} else if (components.year! >= 1){
if (numericDates){
return "1 year ago"
} else {
return "Last year"
}
} else if (components.month! >= 2) {
return "\(components.month!) months ago"
} else if (components.month! >= 1){
if (numericDates){
return "1 month ago"
} else {
return "Last month"
}
} else if (components.weekOfYear! >= 2) {
return "\(components.weekOfYear!) weeks ago"
} else if (components.weekOfYear! >= 1){
if (numericDates){
return "1 week ago"
} else {
return "Last week"
}
} else if (components.day! >= 2) {
return "\(components.day!) days ago"
} else if (components.day! >= 1){
if (numericDates){
return "1 day ago"
} else {
return "Yesterday"
}
} else if (components.hour! >= 2) {
return "\(components.hour!) hours ago"
} else if (components.hour! >= 1){
if (numericDates){
return "1 hour ago"
} else {
return "An hour ago"
}
} else if (components.minute! >= 2) {
return "\(components.minute!) minutes ago"
} else if (components.minute! >= 1){
if (numericDates){
return "1 minute ago"
} else {
return "A minute ago"
}
} else if (components.second! >= 3) {
return "\(components.second!) seconds ago"
} else {
return "Just now"
}
}
使用方法
var createdDate : String = "123232323" //time stamp
var createdDataDisplayString: String {
let date = Date(timeIntervalSince1970: Double(self.createdDate)!).timeAgoSinceDate(numericDates: true)
return "\(date)"
}
print(self.createdDataDisplayString)
Swift 4.1。在函数参数中传递日期,函数将 return 过去。
func getPastTime(for date : Date) -> String {
var secondsAgo = Int(Date().timeIntervalSince(date))
if secondsAgo < 0 {
secondsAgo = secondsAgo * (-1)
}
let minute = 60
let hour = 60 * minute
let day = 24 * hour
let week = 7 * day
if secondsAgo < minute {
if secondsAgo < 2{
return "just now"
}else{
return "\(secondsAgo) secs ago"
}
} else if secondsAgo < hour {
let min = secondsAgo/minute
if min == 1{
return "\(min) min ago"
}else{
return "\(min) mins ago"
}
} else if secondsAgo < day {
let hr = secondsAgo/hour
if hr == 1{
return "\(hr) hr ago"
} else {
return "\(hr) hrs ago"
}
} else if secondsAgo < week {
let day = secondsAgo/day
if day == 1{
return "\(day) day ago"
}else{
return "\(day) days ago"
}
} else {
let formatter = DateFormatter()
formatter.dateFormat = "MMM dd, hh:mm a"
formatter.locale = Locale(identifier: "en_US")
let strDate: String = formatter.string(from: date)
return strDate
}
}
Swift 4+ 版本
extension Date {
func timeAgoSinceDate() -> String {
// From Time
let fromDate = self
// To Time
let toDate = Date()
// Estimation
// Year
if let interval = Calendar.current.dateComponents([.year], from: fromDate, to: toDate).year, interval > 0 {
return interval == 1 ? "\(interval)" + " " + "year ago" : "\(interval)" + " " + "years ago"
}
// Month
if let interval = Calendar.current.dateComponents([.month], from: fromDate, to: toDate).month, interval > 0 {
return interval == 1 ? "\(interval)" + " " + "month ago" : "\(interval)" + " " + "months ago"
}
// Day
if let interval = Calendar.current.dateComponents([.day], from: fromDate, to: toDate).day, interval > 0 {
return interval == 1 ? "\(interval)" + " " + "day ago" : "\(interval)" + " " + "days ago"
}
// Hours
if let interval = Calendar.current.dateComponents([.hour], from: fromDate, to: toDate).hour, interval > 0 {
return interval == 1 ? "\(interval)" + " " + "hour ago" : "\(interval)" + " " + "hours ago"
}
// Minute
if let interval = Calendar.current.dateComponents([.minute], from: fromDate, to: toDate).minute, interval > 0 {
return interval == 1 ? "\(interval)" + " " + "minute ago" : "\(interval)" + " " + "minutes ago"
}
return "a moment ago"
}
}
用法
yourDate.timeAgoSinceDate()
我的需求比较简单,要么"now"要么"x ago"
从 iOS 8 开始,您可以使用 (NS)DateComponentsFormatter
func getElapsedInterval() -> String {
let formatter = DateComponentsFormatter()
formatter.allowedUnits = [.minute, .hour, .day, .month, .year]
formatter.unitsStyle = .abbreviated
formatter.zeroFormattingBehavior = .dropAll
formatter.maximumUnitCount = 1
var dateString: String?
if self.timeIntervalSince(Date()) > -60*5 {
dateString = NSLocalizedString("now", comment: "")
} else {
dateString = String.init(format: NSLocalizedString("%@ ago", comment: ""), locale: .current, formatter.string(from: self, to: Date())!)
}
return dateString ?? ""
}
例如
var date = Date.init(timeIntervalSinceNow: -60)
print(date.getElapsedInterval())
date = Date.init(timeIntervalSinceNow: -60*10)
print(date.getElapsedInterval())
date = Date.init(timeIntervalSinceNow: -60*60)
print(date.getElapsedInterval())
date = Date.init(timeIntervalSinceNow: -60*60*24)
print(date.getElapsedInterval())
date = Date.init(timeIntervalSinceNow: -60*60*24*30)
print(date.getElapsedInterval())
date = Date.init(timeIntervalSinceNow: -60*60*24*31*12)
print(date.getElapsedInterval())
现在
10m 前
1小时前
1 天前
1个月前
1 年前
您需要在您的助手 class 或 swift 文件中的任何文件中添加此日期扩展。 Swift 4.2。如果你想在 swift 3 中取消注释行并注释下一行。
调用方法如下:
let dateText = Date().offsetFrom(date: yourDate!)
yourDate 是要更改的日期
////MARK: *************** Extension Date ***************
extension Date{
func convertToString(validDateFormatter:String) -> String {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = validDateFormatter //"dd MMM yyyy" //yyyy-mm-dd hh:mm
//return dateFormatter.stringFromDate(self)
return dateFormatter.string(from: self as Date)
}
func yearsFrom(date:Date) -> Int{
// return NSCalendar.currentCalendar.components(.Year, fromDate: date, toDate: self, options: []).year
// let calendar = NSCalendar.current
// let components = Calendar.current.dateComponents([.year], from: date, to: self as Date)
return Calendar.current.dateComponents([.year], from: date, to: self).year!
}
func monthsFrom(date:Date) -> Int{
// return NSCalendar.currentCalendar.components(.Month, fromDate: date, toDate: self, options: []).month
return Calendar.current.dateComponents([.month], from: date as Date, to: self).month!
}
func weeksFrom(date:Date) -> Int{
//return NSCalendar.currentCalendar.components(.WeekOfYear, fromDate: date, toDate: self, options: []).weekOfYear
return Calendar.current.dateComponents([.weekOfYear], from: date, to: self).weekOfYear!
}
func daysFrom(date:Date) -> Int{
// return NSCalendar.currentCalendar.components(.Day, fromDate: date, toDate: self, options: []).day
return Calendar.current.dateComponents([.day], from: date, to: self).day!
}
func hoursFrom(date:Date) -> Int{
// return NSCalendar.currentCalendar.components(.Hour, fromDate: date, toDate: self, options: []).hour
return Calendar.current.dateComponents([.hour], from: date, to: self).hour!
}
func minutesFrom(date:Date) -> Int{
// return NSCalendar.currentCalendar.components(.Minute, fromDate: date, toDate: self, options: []).minute
return Calendar.current.dateComponents([.minute], from: date, to: self).minute!
}
func secondsFrom(date:Date) -> Int{
// return NSCalendar.currentCalendar.components(.Second, fromDate: date, toDate: self, options: []).second
return Calendar.current.dateComponents([.second], from: date, to: self).second!
}
func offsetFrom(date:Date) -> String
{
if yearsFrom(date: date) > 0 {
return "\(yearsFrom(date: date))y"
}
if monthsFrom(date: date) > 0 {
return "\(monthsFrom(date: date))M"
}
if weeksFrom(date: date) > 0{
return "\(weeksFrom(date: date))w"
}
if daysFrom(date: date) > 0 {
return "\(daysFrom(date: date))d"
}
if hoursFrom(date: date) > 0 {
return "\(hoursFrom(date: date))h"
}
if minutesFrom(date: date) > 0 {
return "\(minutesFrom(date: date))m"
}
if secondsFrom(date: date) > 0 {
return "\(secondsFrom(date: date))s"
}
return ""
}
}
这里有解决办法,你可以复制粘贴
func timeAgoSinceDate(_ date:Date, numericDates:Bool = false) -> String? {
let calendar = NSCalendar.current
let unitFlags: Set<Calendar.Component> = [.minute, .hour, .day, .weekOfYear, .month, .year, .second]
let now = Date()
let earliest = now < date ? now : date
let latest = (earliest == now) ? date : now
let components = calendar.dateComponents(unitFlags, from: earliest, to: latest)
if (components.year! >= 2) {
return "\(components.year!)yr"
} else if (components.year! >= 1){
if (numericDates){
return "1yr"
} else {
return "Last year"
}
} else if (components.month! >= 2) {
return "\(components.month!)mo"
} else if (components.month! >= 1){
if (numericDates){
return "1 mo"
} else {
return "Last mo"
}
} else if (components.weekOfYear! >= 2) {
return "\(components.weekOfYear!) weeks"
} else if (components.weekOfYear! >= 1){
if (numericDates){
return "1 week"
} else {
return "Last week"
}
} else if (components.day! >= 2) {
return "\(components.day!) d"
} else if (components.day! >= 1){
if (numericDates){
return "1 d"
} else {
return "1 d"
}
} else if (components.hour! >= 2) {
return "\(components.hour!) hrs"
} else if (components.hour! >= 1){
if (numericDates){
return "1 hr"
} else {
return "1 hr"
}
} else if (components.minute! >= 2) {
return "\(components.minute!) m"
} else if (components.minute! >= 1){
if (numericDates){
return "1 m"
} else {
return "2 m"
}
} else if (components.second! >= 3) {
return "\(components.second!)s"
} else {
return "now"
}
}
调用,只需使用
// the date you are getting information about
let dateToReference = Date()
if let timeAgo = timeAgoSinceDate(dateToReference) {
//will be a String value
print(timeAgo)
} else {
//just in case something goes wrong
print("recently")
}
Swift 4 版
并且现在不为 TimeEnd 添加可选。
extension Date {
func getElapsedInterval(to end: Date = Date()) -> String {
if let interval = Calendar.current.dateComponents([Calendar.Component.year], from: self, to: end).day {
if interval > 0 {
return "\(interval) year\(interval == 1 ? "":"s")"
}
}
if let interval = Calendar.current.dateComponents([Calendar.Component.month], from: self, to: end).month {
if interval > 0 {
return "\(interval) month\(interval == 1 ? "":"s")"
}
}
if let interval = Calendar.current.dateComponents([Calendar.Component.weekOfMonth], from: self, to: end).weekOfMonth {
if interval > 0 {
return "\(interval) week\(interval == 1 ? "":"s")"
}
}
if let interval = Calendar.current.dateComponents([Calendar.Component.day], from: self, to: end).day {
if interval > 0 {
return "\(interval) day\(interval == 1 ? "":"s")"
}
}
if let interval = Calendar.current.dateComponents([Calendar.Component.hour], from: self, to: end).hour {
if interval > 0 {
return "\(interval) hour\(interval == 1 ? "":"s")"
}
}
if let interval = Calendar.current.dateComponents([Calendar.Component.minute], from: self, to: end).minute {
if interval > 0 {
return "\(interval) minute\(interval == 1 ? "":"s")"
}
}
return "Just now."
}
}
On Swift 5 使用 RelativeDateTimeFormatter,
let formatter = RelativeDateTimeFormatter()
formatter.localizedString(from: DateComponents(day: -1)) // "1 day ago"
formatter.localizedString(from: DateComponents(hour: 2)) // "in 2 hours"
formatter.localizedString(from: DateComponents(minute: 45)) // "in 45 minutes"
设置 dateTimeStyle 获取本地化指示语句,例如-
formatter.dateTimeStyle = .named
formatter.localizedString(from: DateComponents(day: -1)) // "yesterday"
对于swift5.x
extension Date {
func timeAgoSinceDate() -> String {
// From Time
let fromDate = self
// To Time
let toDate = Date()
// Year
if let interval = Calendar.current.dateComponents([.year], from: fromDate, to: toDate).year, interval > 0 {
return interval == 1 ? "\(interval)" + " " + "year ago" : "\(interval)" + " " + "years ago"
}
// Month
if let interval = Calendar.current.dateComponents([.month], from: fromDate, to: toDate).month, interval > 0 {
return interval == 1 ? "\(interval)" + " " + "month ago" : "\(interval)" + " " + "months ago"
}
// Day
if let interval = Calendar.current.dateComponents([.day], from: fromDate, to: toDate).day, interval > 0 {
return interval == 1 ? "\(interval)" + " " + "day ago" : "\(interval)" + " " + "days ago"
}
// Hours
if let interval = Calendar.current.dateComponents([.hour], from: fromDate, to: toDate).hour, interval > 0 {
return interval == 1 ? "\(interval)" + " " + "hour ago" : "\(interval)" + " " + "hours ago"
}
// Minute
if let interval = Calendar.current.dateComponents([.minute], from: fromDate, to: toDate).minute, interval > 0 {
return interval == 1 ? "\(interval)" + " " + "minute ago" : "\(interval)" + " " + "minutes ago"
}
return "just now"
}
}
使用方法
oldDate.timeAgoSinceDate()
与接受的答案相似,字符串处理更清晰:
extension Date
{
func getElapsedInterval() -> String
{
let interval = Calendar.current.dateComponents([.year, .month, .day], from: self, to: Date())
if let yearsPassed = interval.year,
yearsPassed > 0
{
return "\(yearsPassed) year\(yearsPassed == 1 ? "" : "s") ago"
}
else if let monthsPassed = interval.month,
monthsPassed > 0
{
return "\(monthsPassed) month\(monthsPassed == 1 ? "" : "s") ago"
}
else if let daysPassed = interval.day,
daysPassed > 0
{
return "\(daysPassed) day\(daysPassed == 1 ? "" : "s") ago"
}
return "a moment ago"
}
}
在 Swift5 中,我们有 RelativeDateTimeFormatter
Swift5 之前的版本:
我正在尝试将时间转换为以前的时间,我想做的是:
从 1 到 15 秒它会说“刚刚”
从 60 分钟到 119 分钟,它会说“一个小时前”
从 24 小时到 47 小时它会说“昨天”
从 7 天到 7 天 23 小时它会说“一周前”
我不确定我的计数是否错误,请随时为我修正
这是代码
extension NSDate {
struct Date {
static let timeFormatter: NSDateFormatter = {
let df = NSDateFormatter()
df.calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)
df.dateFormat = "h:mm a"
return df
}()
}
var time: String { return Date.timeFormatter.stringFromDate(self) }
var year: Int { return NSCalendar.autoupdatingCurrentCalendar().component(.Year, fromDate: self) }
var month: Int { return NSCalendar.autoupdatingCurrentCalendar().component(.Month, fromDate: self) }
var day: Int { return NSCalendar.autoupdatingCurrentCalendar().component(.Day, fromDate: self) }
var hour: Int { return NSCalendar.autoupdatingCurrentCalendar().component(.Hour, fromDate: self) }
var minute: Int { return NSCalendar.autoupdatingCurrentCalendar().component(.Minute, fromDate: self) }
var second: Int { return NSCalendar.autoupdatingCurrentCalendar().component(.Second, fromDate: self) }
struct DateComponents {
static let formatter: NSDateComponentsFormatter = {
let dcFormatter = NSDateComponentsFormatter()
dcFormatter.calendar = NSCalendar(identifier: NSCalendarIdentifierISO8601)!
dcFormatter.unitsStyle = .Full
dcFormatter.maximumUnitCount = 1
dcFormatter.zeroFormattingBehavior = .Default
dcFormatter.allowsFractionalUnits = false
dcFormatter.allowedUnits = [.Year, .Month, .Weekday, .Day, .Hour, .Minute, .Second]
return dcFormatter
}()
}
var elapsedTime: String {
if isecond(NSDate()) {
return "Just now"
}
if ishour(NSDate()) {
return "an hour ago"
}
if isyesterday(NSDate()) {
return "Yesterday"
}
if isweek(NSDate()) {
return "a week ago"
}
return (DateComponents.formatter.stringFromTimeInterval(NSDate().timeIntervalSinceDate(self)) ?? "") + " ago"
}
func isyesterday(date: NSDate) -> Bool {
return NSCalendar.autoupdatingCurrentCalendar().isDate(self, inSameDayAsDate: date.yesterday)
}
var yesterday: NSDate {
return NSCalendar.autoupdatingCurrentCalendar().dateWithEra(1, year: year, month: month, day: day-1, hour: 0, minute: 0, second: 0, nanosecond: 0)!
}
func isweek(date: NSDate) -> Bool {
return NSCalendar.autoupdatingCurrentCalendar().isDate(self, inSameDayAsDate: date.weekago)
}
var weekago: NSDate {
return NSCalendar.autoupdatingCurrentCalendar().dateWithEra(1, year: year, month: month, day: day-7, hour: 0, minute: 0, second: 0, nanosecond: 0)!
}
func isecond(date: NSDate) -> Bool {
return NSCalendar.autoupdatingCurrentCalendar().isDate(self, inSameDayAsDate: date.secondsago)
}
var secondsago: NSDate {
return NSCalendar.autoupdatingCurrentCalendar().dateWithEra(1, year: year, month: month, day: 0, hour: 0, minute: 0, second: second-15, nanosecond: 0)!
}
func ishour(date: NSDate) -> Bool {
return NSCalendar.autoupdatingCurrentCalendar().isDate(self, inSameDayAsDate: date.hourago)
}
var hourago: NSDate {
return NSCalendar.autoupdatingCurrentCalendar().dateWithEra(1, year: year, month: month, day: 0, hour: hour-1, minute: minute-1, second: 0, nanosecond: 0)!
}
}
这是我在我的应用程序中得到的:
"an hour ago"、“刚才”等引号没有显示,只显示“昨天”,我不确定是否只有 7 天到 23 小时!
这是我的第一个问题 link:
请帮我修改代码, 感谢@Leo Dabus 提供的代码。
根据需要更改文本。
extension NSDate {
func getElapsedInterval() -> String {
var interval = NSCalendar.currentCalendar().components(.Year, fromDate: self, toDate: NSDate(), options: []).year
if interval > 0 {
return interval == 1 ? "\(interval)" + " " + "year" :
"\(interval)" + " " + "years"
}
interval = NSCalendar.currentCalendar().components(.Month, fromDate: self, toDate: NSDate(), options: []).month
if interval > 0 {
return interval == 1 ? "\(interval)" + " " + "month" :
"\(interval)" + " " + "months"
}
interval = NSCalendar.currentCalendar().components(.Day, fromDate: self, toDate: NSDate(), options: []).day
if interval > 0 {
return interval == 1 ? "\(interval)" + " " + "day" :
"\(interval)" + " " + "days"
}
interval = NSCalendar.currentCalendar().components(.Hour, fromDate: self, toDate: NSDate(), options: []).hour
if interval > 0 {
return interval == 1 ? "\(interval)" + " " + "hour" :
"\(interval)" + " " + "hours"
}
interval = NSCalendar.currentCalendar().components(.Minute, fromDate: self, toDate: NSDate(), options: []).minute
if interval > 0 {
return interval == 1 ? "\(interval)" + " " + "minute" :
"\(interval)" + " " + "minutes"
}
return "a moment ago"
}
}
我将更新 Truongky 对 Swif 3 的回答:
extension Date {
func getElapsedInterval() -> String {
let interval = Calendar.current.dateComponents([.year, .month, .day], from: self, 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 {
return "a moment ago"
}
}
}
如果您更喜欢可本地化的响应而不是仅使用英语,则此代码可以完成工作
extension Date {
func getElapsedInterval() -> String {
var calendar = Calendar.current
calendar.locale = Locale(identifier: Bundle.main.preferredLocalizations[0])
// IF THE USER HAVE THE PHONE IN SPANISH BUT YOUR APP ONLY SUPPORTS I.E. ENGLISH AND GERMAN
// WE SHOULD CHANGE THE LOCALE OF THE FORMATTER TO THE PREFERRED ONE
// (IS THE LOCALE THAT THE USER IS SEEING THE APP), IF NOT, THIS ELAPSED TIME
// IS GOING TO APPEAR IN SPANISH
let formatter = DateComponentsFormatter()
formatter.unitsStyle = .full
formatter.maximumUnitCount = 1
formatter.calendar = calendar
var dateString: String?
let interval = calendar.dateComponents([.year, .month, .weekOfYear, .day], from: self, to: Date())
if let year = interval.year, year > 0 {
formatter.allowedUnits = [.year] //2 years
} else if let month = interval.month, month > 0 {
formatter.allowedUnits = [.month] //1 month
} else if let week = interval.weekOfYear, week > 0 {
formatter.allowedUnits = [.weekOfMonth] //3 weeks
} else if let day = interval.day, day > 0 {
formatter.allowedUnits = [.day] // 6 days
} else {
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: Bundle.main.preferredLocalizations[0]) //--> IF THE USER HAVE THE PHONE IN SPANISH BUT YOUR APP ONLY SUPPORTS I.E. ENGLISH AND GERMAN WE SHOULD CHANGE THE LOCALE OF THE FORMATTER TO THE PREFERRED ONE (IS THE LOCALE THAT THE USER IS SEEING THE APP), IF NOT, THIS ELAPSED TIME IS GOING TO APPEAR IN SPANISH
dateFormatter.dateStyle = .medium
dateFormatter.doesRelativeDateFormatting = true
dateString = dateFormatter.string(from: self) // IS GOING TO SHOW 'TODAY'
}
if dateString == nil {
dateString = formatter.string(from: self, to: Date())
}
return dateString!
}
Swift 3 版本
extension Date {
var timeAgoSinceNow: String {
return getTimeAgoSinceNow()
}
private func getTimeAgoSinceNow() -> String {
var interval = Calendar.current.dateComponents([.year], from: self, to: Date()).year!
if interval > 0 {
return interval == 1 ? "\(interval)" + " year" : "\(interval)" + " years"
}
interval = Calendar.current.dateComponents([.month], from: self, to: Date()).month!
if interval > 0 {
return interval == 1 ? "\(interval)" + " month" : "\(interval)" + " months"
}
interval = Calendar.current.dateComponents([.day], from: self, to: Date()).day!
if interval > 0 {
return interval == 1 ? "\(interval)" + " day" : "\(interval)" + " days"
}
interval = Calendar.current.dateComponents([.hour], from: self, to: Date()).hour!
if interval > 0 {
return interval == 1 ? "\(interval)" + " hour" : "\(interval)" + " hours"
}
interval = Calendar.current.dateComponents([.minute], from: self, to: Date()).minute!
if interval > 0 {
return interval == 1 ? "\(interval)" + " minute" : "\(interval)" + " minutes"
}
return "a moment ago"
}
}
使用 Date 而不是 NSDate:Answer taking from:
func timeAgoSinceDate(_ date:Date, numericDates:Bool = false) -> String {
let calendar = NSCalendar.current
let unitFlags: Set<Calendar.Component> = [.minute, .hour, .day, .weekOfYear, .month, .year, .second]
let now = Date()
let earliest = now < date ? now : date
let latest = (earliest == now) ? date : now
let components = calendar.dateComponents(unitFlags, from: earliest, to: latest)
if (components.year! >= 2) {
return "\(components.year!) years ago"
} else if (components.year! >= 1){
if (numericDates){
return "1 year ago"
} else {
return "Last year"
}
} else if (components.month! >= 2) {
return "\(components.month!) months ago"
} else if (components.month! >= 1){
if (numericDates){
return "1 month ago"
} else {
return "Last month"
}
} else if (components.weekOfYear! >= 2) {
return "\(components.weekOfYear!) weeks ago"
} else if (components.weekOfYear! >= 1){
if (numericDates){
return "1 week ago"
} else {
return "Last week"
}
} else if (components.day! >= 2) {
return "\(components.day!) days ago"
} else if (components.day! >= 1){
if (numericDates){
return "1 day ago"
} else {
return "Yesterday"
}
} else if (components.hour! >= 2) {
return "\(components.hour!) hours ago"
} else if (components.hour! >= 1){
if (numericDates){
return "1 hour ago"
} else {
return "An hour ago"
}
} else if (components.minute! >= 2) {
return "\(components.minute!) minutes ago"
} else if (components.minute! >= 1){
if (numericDates){
return "1 minute ago"
} else {
return "A minute ago"
}
} else if (components.second! >= 3) {
return "\(components.second!) seconds ago"
} else {
return "Just now"
}
}
使用方法
var createdDate : String = "123232323" //time stamp
var createdDataDisplayString: String {
let date = Date(timeIntervalSince1970: Double(self.createdDate)!).timeAgoSinceDate(numericDates: true)
return "\(date)"
}
print(self.createdDataDisplayString)
Swift 4.1。在函数参数中传递日期,函数将 return 过去。
func getPastTime(for date : Date) -> String {
var secondsAgo = Int(Date().timeIntervalSince(date))
if secondsAgo < 0 {
secondsAgo = secondsAgo * (-1)
}
let minute = 60
let hour = 60 * minute
let day = 24 * hour
let week = 7 * day
if secondsAgo < minute {
if secondsAgo < 2{
return "just now"
}else{
return "\(secondsAgo) secs ago"
}
} else if secondsAgo < hour {
let min = secondsAgo/minute
if min == 1{
return "\(min) min ago"
}else{
return "\(min) mins ago"
}
} else if secondsAgo < day {
let hr = secondsAgo/hour
if hr == 1{
return "\(hr) hr ago"
} else {
return "\(hr) hrs ago"
}
} else if secondsAgo < week {
let day = secondsAgo/day
if day == 1{
return "\(day) day ago"
}else{
return "\(day) days ago"
}
} else {
let formatter = DateFormatter()
formatter.dateFormat = "MMM dd, hh:mm a"
formatter.locale = Locale(identifier: "en_US")
let strDate: String = formatter.string(from: date)
return strDate
}
}
Swift 4+ 版本
extension Date {
func timeAgoSinceDate() -> String {
// From Time
let fromDate = self
// To Time
let toDate = Date()
// Estimation
// Year
if let interval = Calendar.current.dateComponents([.year], from: fromDate, to: toDate).year, interval > 0 {
return interval == 1 ? "\(interval)" + " " + "year ago" : "\(interval)" + " " + "years ago"
}
// Month
if let interval = Calendar.current.dateComponents([.month], from: fromDate, to: toDate).month, interval > 0 {
return interval == 1 ? "\(interval)" + " " + "month ago" : "\(interval)" + " " + "months ago"
}
// Day
if let interval = Calendar.current.dateComponents([.day], from: fromDate, to: toDate).day, interval > 0 {
return interval == 1 ? "\(interval)" + " " + "day ago" : "\(interval)" + " " + "days ago"
}
// Hours
if let interval = Calendar.current.dateComponents([.hour], from: fromDate, to: toDate).hour, interval > 0 {
return interval == 1 ? "\(interval)" + " " + "hour ago" : "\(interval)" + " " + "hours ago"
}
// Minute
if let interval = Calendar.current.dateComponents([.minute], from: fromDate, to: toDate).minute, interval > 0 {
return interval == 1 ? "\(interval)" + " " + "minute ago" : "\(interval)" + " " + "minutes ago"
}
return "a moment ago"
}
}
用法
yourDate.timeAgoSinceDate()
我的需求比较简单,要么"now"要么"x ago"
从 iOS 8 开始,您可以使用 (NS)DateComponentsFormatter
func getElapsedInterval() -> String {
let formatter = DateComponentsFormatter()
formatter.allowedUnits = [.minute, .hour, .day, .month, .year]
formatter.unitsStyle = .abbreviated
formatter.zeroFormattingBehavior = .dropAll
formatter.maximumUnitCount = 1
var dateString: String?
if self.timeIntervalSince(Date()) > -60*5 {
dateString = NSLocalizedString("now", comment: "")
} else {
dateString = String.init(format: NSLocalizedString("%@ ago", comment: ""), locale: .current, formatter.string(from: self, to: Date())!)
}
return dateString ?? ""
}
例如
var date = Date.init(timeIntervalSinceNow: -60)
print(date.getElapsedInterval())
date = Date.init(timeIntervalSinceNow: -60*10)
print(date.getElapsedInterval())
date = Date.init(timeIntervalSinceNow: -60*60)
print(date.getElapsedInterval())
date = Date.init(timeIntervalSinceNow: -60*60*24)
print(date.getElapsedInterval())
date = Date.init(timeIntervalSinceNow: -60*60*24*30)
print(date.getElapsedInterval())
date = Date.init(timeIntervalSinceNow: -60*60*24*31*12)
print(date.getElapsedInterval())
现在
10m 前
1小时前
1 天前
1个月前
1 年前
您需要在您的助手 class 或 swift 文件中的任何文件中添加此日期扩展。 Swift 4.2。如果你想在 swift 3 中取消注释行并注释下一行。
调用方法如下:
let dateText = Date().offsetFrom(date: yourDate!)
yourDate 是要更改的日期
////MARK: *************** Extension Date ***************
extension Date{
func convertToString(validDateFormatter:String) -> String {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = validDateFormatter //"dd MMM yyyy" //yyyy-mm-dd hh:mm
//return dateFormatter.stringFromDate(self)
return dateFormatter.string(from: self as Date)
}
func yearsFrom(date:Date) -> Int{
// return NSCalendar.currentCalendar.components(.Year, fromDate: date, toDate: self, options: []).year
// let calendar = NSCalendar.current
// let components = Calendar.current.dateComponents([.year], from: date, to: self as Date)
return Calendar.current.dateComponents([.year], from: date, to: self).year!
}
func monthsFrom(date:Date) -> Int{
// return NSCalendar.currentCalendar.components(.Month, fromDate: date, toDate: self, options: []).month
return Calendar.current.dateComponents([.month], from: date as Date, to: self).month!
}
func weeksFrom(date:Date) -> Int{
//return NSCalendar.currentCalendar.components(.WeekOfYear, fromDate: date, toDate: self, options: []).weekOfYear
return Calendar.current.dateComponents([.weekOfYear], from: date, to: self).weekOfYear!
}
func daysFrom(date:Date) -> Int{
// return NSCalendar.currentCalendar.components(.Day, fromDate: date, toDate: self, options: []).day
return Calendar.current.dateComponents([.day], from: date, to: self).day!
}
func hoursFrom(date:Date) -> Int{
// return NSCalendar.currentCalendar.components(.Hour, fromDate: date, toDate: self, options: []).hour
return Calendar.current.dateComponents([.hour], from: date, to: self).hour!
}
func minutesFrom(date:Date) -> Int{
// return NSCalendar.currentCalendar.components(.Minute, fromDate: date, toDate: self, options: []).minute
return Calendar.current.dateComponents([.minute], from: date, to: self).minute!
}
func secondsFrom(date:Date) -> Int{
// return NSCalendar.currentCalendar.components(.Second, fromDate: date, toDate: self, options: []).second
return Calendar.current.dateComponents([.second], from: date, to: self).second!
}
func offsetFrom(date:Date) -> String
{
if yearsFrom(date: date) > 0 {
return "\(yearsFrom(date: date))y"
}
if monthsFrom(date: date) > 0 {
return "\(monthsFrom(date: date))M"
}
if weeksFrom(date: date) > 0{
return "\(weeksFrom(date: date))w"
}
if daysFrom(date: date) > 0 {
return "\(daysFrom(date: date))d"
}
if hoursFrom(date: date) > 0 {
return "\(hoursFrom(date: date))h"
}
if minutesFrom(date: date) > 0 {
return "\(minutesFrom(date: date))m"
}
if secondsFrom(date: date) > 0 {
return "\(secondsFrom(date: date))s"
}
return ""
}
}
这里有解决办法,你可以复制粘贴
func timeAgoSinceDate(_ date:Date, numericDates:Bool = false) -> String? {
let calendar = NSCalendar.current
let unitFlags: Set<Calendar.Component> = [.minute, .hour, .day, .weekOfYear, .month, .year, .second]
let now = Date()
let earliest = now < date ? now : date
let latest = (earliest == now) ? date : now
let components = calendar.dateComponents(unitFlags, from: earliest, to: latest)
if (components.year! >= 2) {
return "\(components.year!)yr"
} else if (components.year! >= 1){
if (numericDates){
return "1yr"
} else {
return "Last year"
}
} else if (components.month! >= 2) {
return "\(components.month!)mo"
} else if (components.month! >= 1){
if (numericDates){
return "1 mo"
} else {
return "Last mo"
}
} else if (components.weekOfYear! >= 2) {
return "\(components.weekOfYear!) weeks"
} else if (components.weekOfYear! >= 1){
if (numericDates){
return "1 week"
} else {
return "Last week"
}
} else if (components.day! >= 2) {
return "\(components.day!) d"
} else if (components.day! >= 1){
if (numericDates){
return "1 d"
} else {
return "1 d"
}
} else if (components.hour! >= 2) {
return "\(components.hour!) hrs"
} else if (components.hour! >= 1){
if (numericDates){
return "1 hr"
} else {
return "1 hr"
}
} else if (components.minute! >= 2) {
return "\(components.minute!) m"
} else if (components.minute! >= 1){
if (numericDates){
return "1 m"
} else {
return "2 m"
}
} else if (components.second! >= 3) {
return "\(components.second!)s"
} else {
return "now"
}
}
调用,只需使用
// the date you are getting information about
let dateToReference = Date()
if let timeAgo = timeAgoSinceDate(dateToReference) {
//will be a String value
print(timeAgo)
} else {
//just in case something goes wrong
print("recently")
}
Swift 4 版
并且现在不为 TimeEnd 添加可选。
extension Date {
func getElapsedInterval(to end: Date = Date()) -> String {
if let interval = Calendar.current.dateComponents([Calendar.Component.year], from: self, to: end).day {
if interval > 0 {
return "\(interval) year\(interval == 1 ? "":"s")"
}
}
if let interval = Calendar.current.dateComponents([Calendar.Component.month], from: self, to: end).month {
if interval > 0 {
return "\(interval) month\(interval == 1 ? "":"s")"
}
}
if let interval = Calendar.current.dateComponents([Calendar.Component.weekOfMonth], from: self, to: end).weekOfMonth {
if interval > 0 {
return "\(interval) week\(interval == 1 ? "":"s")"
}
}
if let interval = Calendar.current.dateComponents([Calendar.Component.day], from: self, to: end).day {
if interval > 0 {
return "\(interval) day\(interval == 1 ? "":"s")"
}
}
if let interval = Calendar.current.dateComponents([Calendar.Component.hour], from: self, to: end).hour {
if interval > 0 {
return "\(interval) hour\(interval == 1 ? "":"s")"
}
}
if let interval = Calendar.current.dateComponents([Calendar.Component.minute], from: self, to: end).minute {
if interval > 0 {
return "\(interval) minute\(interval == 1 ? "":"s")"
}
}
return "Just now."
}
}
On Swift 5 使用 RelativeDateTimeFormatter,
let formatter = RelativeDateTimeFormatter()
formatter.localizedString(from: DateComponents(day: -1)) // "1 day ago"
formatter.localizedString(from: DateComponents(hour: 2)) // "in 2 hours"
formatter.localizedString(from: DateComponents(minute: 45)) // "in 45 minutes"
设置 dateTimeStyle 获取本地化指示语句,例如-
formatter.dateTimeStyle = .named
formatter.localizedString(from: DateComponents(day: -1)) // "yesterday"
对于swift5.x
extension Date {
func timeAgoSinceDate() -> String {
// From Time
let fromDate = self
// To Time
let toDate = Date()
// Year
if let interval = Calendar.current.dateComponents([.year], from: fromDate, to: toDate).year, interval > 0 {
return interval == 1 ? "\(interval)" + " " + "year ago" : "\(interval)" + " " + "years ago"
}
// Month
if let interval = Calendar.current.dateComponents([.month], from: fromDate, to: toDate).month, interval > 0 {
return interval == 1 ? "\(interval)" + " " + "month ago" : "\(interval)" + " " + "months ago"
}
// Day
if let interval = Calendar.current.dateComponents([.day], from: fromDate, to: toDate).day, interval > 0 {
return interval == 1 ? "\(interval)" + " " + "day ago" : "\(interval)" + " " + "days ago"
}
// Hours
if let interval = Calendar.current.dateComponents([.hour], from: fromDate, to: toDate).hour, interval > 0 {
return interval == 1 ? "\(interval)" + " " + "hour ago" : "\(interval)" + " " + "hours ago"
}
// Minute
if let interval = Calendar.current.dateComponents([.minute], from: fromDate, to: toDate).minute, interval > 0 {
return interval == 1 ? "\(interval)" + " " + "minute ago" : "\(interval)" + " " + "minutes ago"
}
return "just now"
}
}
使用方法
oldDate.timeAgoSinceDate()
与接受的答案相似,字符串处理更清晰:
extension Date
{
func getElapsedInterval() -> String
{
let interval = Calendar.current.dateComponents([.year, .month, .day], from: self, to: Date())
if let yearsPassed = interval.year,
yearsPassed > 0
{
return "\(yearsPassed) year\(yearsPassed == 1 ? "" : "s") ago"
}
else if let monthsPassed = interval.month,
monthsPassed > 0
{
return "\(monthsPassed) month\(monthsPassed == 1 ? "" : "s") ago"
}
else if let daysPassed = interval.day,
daysPassed > 0
{
return "\(daysPassed) day\(daysPassed == 1 ? "" : "s") ago"
}
return "a moment ago"
}
}