如何将NSDate转换为“今天”,“昨天”,“一周前”,“一个月前”,“一年前”的相对格式?
我想将nsdate转换为"Today","Yesterday","a week ago","a month ago","a year ago","date as it is"
等相对格式。
我已经为它写了下面的方法..但一些如何它只是打印,因为它是date..你能告诉我应该是什么问题?
//以下是将date转换为相对string的函数
+(NSString *)getDateDiffrence:(NSDate *)strDate{ NSDateFormatter *df = [[NSDateFormatter alloc] init]; df.timeStyle = NSDateFormatterMediumStyle; df.dateStyle = NSDateFormatterShortStyle; df.doesRelativeDateFormatting = YES; NSLog(@"STRING DATEEE : %@ REAL DATE TODAY %@",[df stringFromDate:strDate],[NSDate date]); return [df stringFromDate:strDate]; }
我有以下格式的datestring"2013-10-29T09:38:00"
当我试图给NSDate对象时,它总是返回我空date。
所以我试图将该date转换为yyyy-MM-dd HH:mm:ssZZZZ
然后我将这个date传递给函数,然后它只是打印整个date..
如何解决这个问题?
//以下是我称之为上述function的代码
NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; [formatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss"]; NSDate *date = [formatter dateFromString:[threadDict objectForKey:@"lastMessageDate"]]; [formatter setDateFormat:@"yyyy-MM-dd HH:mm:ssZZZZ"]; NSString *date1 = [formatter stringFromDate:date]; NSDate *date_d = [formatter dateFromString:date1]; NSString *resultstr=[UserManager getDateDiffrence:date]; self.dateLabel.text=resultstr;
为了简单起见,我假定你正在格式化的date都是过去的(不是“明天”或“下周”)。 这并不是说它不能完成,而是要处理更多的情况,并返回更多的string。
您可以使用components:fromDate:toDate:options:
使用date组件的任意组合来获取两个date之间的年,月,周,日,小时等数字。 然后按照从最重要的(例如年)到最不重要的(例如日)的顺序排列,您可以仅基于最重要的组件来格式化string。
例如:1周,2天和7小时前的date将被格式化为“1周”。
如果要为特定的单位创build特殊string,例如“1天前”的“明天”,则可以在确定它是最重要的组件后检查该组件的值。
代码看起来像这样:
- (NSString *)relativeDateStringForDate:(NSDate *)date { NSCalendarUnit units = NSCalendarUnitDay | NSCalendarUnitWeekOfYear | NSCalendarUnitMonth | NSCalendarUnitYear; // if `date` is before "now" (ie in the past) then the components will be positive NSDateComponents *components = [[NSCalendar currentCalendar] components:units fromDate:date toDate:[NSDate date] options:0]; if (components.year > 0) { return [NSString stringWithFormat:@"%ld years ago", (long)components.year]; } else if (components.month > 0) { return [NSString stringWithFormat:@"%ld months ago", (long)components.month]; } else if (components.weekOfYear > 0) { return [NSString stringWithFormat:@"%ld weeks ago", (long)components.weekOfYear]; } else if (components.day > 0) { if (components.day > 1) { return [NSString stringWithFormat:@"%ld days ago", (long)components.day]; } else { return @"Yesterday"; } } else { return @"Today"; } }
如果您的date也可能在将来,那么您可以按照相同的顺序检查组件的绝对值,然后检查它是正还是负来返回适当的string。 我只在下面展示一年:
if ( abs(components.year > 0) ) { // year is most significant component if (components.year > 0) { // in the past return [NSString stringWithFormat:@"%ld years ago", (long)components.year]; } else { // in the future return [NSString stringWithFormat:@"In %ld years", (long)components.year]; } }
Swift更新,感谢DavidRönnqvist的客观答案,它将在过去的date工作。
func relativeDateStringForDate(date : NSDate) -> NSString { let todayDate = NSDate() let units: NSCalendarUnit = [.Hour, .Day, .Month, .Year, .WeekOfYear] let components = NSCalendar.currentCalendar().components(units, fromDate: date , toDate: todayDate, options: NSCalendarOptions.MatchFirst ) let year = components.year let month = components.month let day = components.day let hour = components.hour let weeks = components.weekOfYear // if `date` is before "now" (ie in the past) then the components will be positive if components.year > 0 { return NSString.init(format: "%d years ago", year); } else if components.month > 0 { return NSString.init(format: "%d months ago", month); } else if components.weekOfYear > 0 { return NSString.init(format: "%d weeks ago", weeks); } else if (components.day > 0) { if components.day > 1 { return NSString.init(format: "%d days ago", day); } else { return "Yesterday"; } } else { return NSString.init(format: "%d hours ago", hour); } }
对于:SWIFT 3
这是一个Swift 3版本,用于处理过去的date,处理所有单位,返回的string中有单数或复数。
使用示例:
let oneWeekAgo = Calendar.current.date(byAdding: .weekOfYear, value: -1, to: Date())! print(relativePast(for: oneWeekAgo)) // output: "1 week ago"
我把它build立在Saurabh Yadav's的一段即兴之上。 谢谢。
func relativePast(for date : Date) -> String { let units = Set<Calendar.Component>([.year, .month, .day, .hour, .minute, .second, .weekOfYear]) let components = Calendar.current.dateComponents(units, from: date, to: Date()) if components.year! > 0 { return "\(components.year!) " + (components.year! > 1 ? "years ago" : "year ago") } else if components.month! > 0 { return "\(components.month!) " + (components.month! > 1 ? "months ago" : "month ago") } else if components.weekOfYear! > 0 { return "\(components.weekOfYear!) " + (components.weekOfYear! > 1 ? "weeks ago" : "week ago") } else if (components.day! > 0) { return (components.day! > 1 ? "\(components.day!) days ago" : "Yesterday") } else if components.hour! > 0 { return "\(components.hour!) " + (components.hour! > 1 ? "hours ago" : "hour ago") } else if components.minute! > 0 { return "\(components.minute!) " + (components.minute! > 1 ? "minutes ago" : "minute ago") } else { return "\(components.second!) " + (components.second! > 1 ? "seconds ago" : "second ago") } }
为了避免Budidino提到的24小时的问题,大卫的答案,我改变它,如下所示 –
- (NSString *)relativeDateStringForDate:(NSDate *)date { NSCalendarUnit units = NSDayCalendarUnit | NSWeekOfYearCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit ; NSCalendar *cal = [NSCalendar currentCalendar]; NSDateComponents *components1 = [cal components:(NSCalendarUnitEra|NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay) fromDate:[NSDate date]]; NSDate *today = [cal dateFromComponents:components1]; components1 = [cal components:(NSCalendarUnitEra|NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay) fromDate:date]; NSDate *thatdate = [cal dateFromComponents:components1]; // if `date` is before "now" (ie in the past) then the components will be positive NSDateComponents *components = [[NSCalendar currentCalendar] components:units fromDate:thatdate toDate:today options:0]; if (components.year > 0) { return [NSString stringWithFormat:@"%ld years ago", (long)components.year]; } else if (components.month > 0) { return [NSString stringWithFormat:@"%ld months ago", (long)components.month]; } else if (components.weekOfYear > 0) { return [NSString stringWithFormat:@"%ld weeks ago", (long)components.weekOfYear]; } else if (components.day > 0) { if (components.day > 1) { return [NSString stringWithFormat:@"%ld days ago", (long)components.day]; } else { return @"Yesterday"; } } else { return @"Today"; } }
基本上,它创build了2个新的date,不包括时间片。然后比较“天”的差异。
检查NSDate-TimeAgo ,它也支持多种语言。
你需要自己制定这个逻辑。 您将需要确定这两个date之间的天数。
这是一个相对天真的方法:
+ (NSString *) dateDifference:(NSDate *)date { const NSTimeInterval secondsPerDay = 60 * 60 * 24; NSTimeInterval diff = [date timeIntervalSinceNow] * -1.0; // if the difference is negative, then the given date/time is in the future // (because we multiplied by -1.0 to make it easier to follow later) if (diff < 0) return @"In the future"; diff /= secondsPerDay; // get the number of days // if the difference is less than 1, the date occurred today, etc. if (diff < 1) return @"Today"; else if (diff < 2) return @"Yesterday"; else if (diff < 8) return @"Last week"; else return [date description]; // use a date formatter if necessary }
天真的原因有很多:
- 它不考虑闰日
- 假设一天有86400秒(有闰秒这样的事情!)
但是,这至less应该帮助你朝正确的方向前进。 另外,避免使用get
方法名称。 使用get
方法名称通常表示调用者必须提供自己的输出缓冲区。 考虑NSArray
的方法getItems:range:
和NSString
的方法getCharacters:range:
NSString* AgoStringFromTime(NSDate* dateTime) { NSDictionary *timeScale = @{@"sec" :@1, @"min" :@60, @"hr" :@3600, @"day" :@86400, @"week" :@605800, @"month":@2629743, @"year" :@31556926}; NSString *scale; int timeAgo = 0-(int)[dateTime timeIntervalSinceNow]; if (timeAgo < 60) { scale = @"sec"; } else if (timeAgo < 3600) { scale = @"min"; } else if (timeAgo < 86400) { scale = @"hr"; } else if (timeAgo < 605800) { scale = @"day"; } else if (timeAgo < 2629743) { scale = @"week"; } else if (timeAgo < 31556926) { scale = @"month"; } else { scale = @"year"; } timeAgo = timeAgo/[[timeScale objectForKey:scale] integerValue]; NSString *s = @""; if (timeAgo > 1) { s = @"s"; } return [NSString stringWithFormat:@"%d %@%@", timeAgo, scale, s]; }
这是我的答案(在Swift 3中 !)以及为什么它更好。
回答:
func datePhraseRelativeToToday(from date: Date) -> String { // Don't use the current date/time. Use the end of the current day // (technically 0h00 the next day). Apple's calculation of // doesRelativeDateFormatting niavely depends on this start date. guard let todayEnd = dateEndOfToday() else { return "" } let calendar = Calendar.autoupdatingCurrent let units = Set([Calendar.Component.year, Calendar.Component.month, Calendar.Component.weekOfMonth, Calendar.Component.day]) let difference = calendar.dateComponents(units, from: date, to: todayEnd) guard let year = difference.year, let month = difference.month, let week = difference.weekOfMonth, let day = difference.day else { return "" } let timeAgo = NSLocalizedString("%@ ago", comment: "x days ago") let dateFormatter: DateFormatter = { let formatter = DateFormatter() formatter.locale = Locale.autoupdatingCurrent formatter.dateStyle = .medium formatter.doesRelativeDateFormatting = true return formatter }() if year > 0 { // sample output: "Jan 23, 2014" return dateFormatter.string(from: date) } else if month > 0 { let formatter = DateComponentsFormatter() formatter.unitsStyle = .brief // sample output: "1mth" formatter.allowedUnits = .month guard let timePhrase = formatter.string(from: difference) else { return "" } return String(format: timeAgo, timePhrase) } else if week > 0 { let formatter = DateComponentsFormatter() formatter.unitsStyle = .brief; // sample output: "2wks" formatter.allowedUnits = .weekOfMonth guard let timePhrase = formatter.string(from: difference) else { return "" } return String(format: timeAgo, timePhrase) } else if day > 1 { let formatter = DateComponentsFormatter() formatter.unitsStyle = .abbreviated; // sample output: "3d" formatter.allowedUnits = .day guard let timePhrase = formatter.string(from: difference) else { return "" } return String(format: timeAgo, timePhrase) } else { // sample output: "Yesterday" or "Today" return dateFormatter.string(from: date) } } func dateEndOfToday() -> Date? { let calendar = Calendar.autoupdatingCurrent let now = Date() let todayStart = calendar.startOfDay(for: now) var components = DateComponents() components.day = 1 let todayEnd = calendar.date(byAdding: components, to: todayStart) return todayEnd }
请记住要重用您的格式化程序以避免任何性能下降 ! 提示:在DateFormatter和DateComponentsFormatter上的扩展是好主意。
为什么更好:
- 利用DateFormatter的“昨天”和“今天”。 这已经被苹果公司翻译,这可以节省你的工作!
- 使用DateComponentsFormatter已经翻译的“1周”string。 (对苹果来说,再次减less工作量)。你所要做的就是翻译“%@前”string。 🙂
- 其他答案错误地计算了当天从“今天”切换到“昨天”等时间。固定常数是一个很大的NO-NO,因为原因 。 此外,其他答案使用当前date/时间来使用当前date/时间的结尾 。
- 使用autoupdatingCurrent作为日历和语言环境,确保您的应用程序立即与Settings.app中用户的日历和语言首选项保持一致
这个答案是由GitHub上的DateTools启发的。
这里是我为我的使用创build的代码:
+ (NSString*) getTimestampForDate:(NSDate*)date { NSDate* sourceDate = date; // Timezone Offset compensation (optional, if your target users are limited to a single time zone.) NSTimeZone* sourceTimeZone = [NSTimeZone timeZoneWithName:@"America/New_York"]; NSTimeZone* destinationTimeZone = [NSTimeZone systemTimeZone]; NSInteger sourceGMTOffset = [sourceTimeZone secondsFromGMTForDate:sourceDate]; NSInteger destinationGMTOffset = [destinationTimeZone secondsFromGMTForDate:sourceDate]; NSTimeInterval interval = destinationGMTOffset - sourceGMTOffset; NSDate* destinationDate = [[NSDate alloc] initWithTimeInterval:interval sinceDate:sourceDate]; // Timestamp calculation (based on compensation) NSCalendar* currentCalendar = [NSCalendar currentCalendar]; NSCalendarUnit unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit; NSDateComponents *differenceComponents = [currentCalendar components:unitFlags fromDate:destinationDate toDate:[NSDate date] options:0];//Use `date` instead of `destinationDate` if you are not using Timezone offset correction NSInteger yearDifference = [differenceComponents year]; NSInteger monthDifference = [differenceComponents month]; NSInteger dayDifference = [differenceComponents day]; NSInteger hourDifference = [differenceComponents hour]; NSInteger minuteDifference = [differenceComponents minute]; NSString* timestamp; if (yearDifference == 0 && monthDifference == 0 && dayDifference == 0 && hourDifference == 0 && minuteDifference <= 2) { //"Just Now" timestamp = @"Just Now"; } else if (yearDifference == 0 && monthDifference == 0 && dayDifference == 0 && hourDifference == 0 && minuteDifference < 60) { //"13 minutes ago" timestamp = [NSString stringWithFormat:@"%ld minutes ago", (long)minuteDifference]; } else if (yearDifference == 0 && monthDifference == 0 && dayDifference == 0 && hourDifference == 1) { //"1 hour ago" EXACT timestamp = @"1 hour ago"; } else if (yearDifference == 0 && monthDifference == 0 && dayDifference == 0 && hourDifference < 24) { timestamp = [NSString stringWithFormat:@"%ld hours ago", (long)hourDifference]; } else { NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; [formatter setLocale:[NSLocale currentLocale]]; NSString* strDate, *strDate2 = @""; if (yearDifference == 0 && monthDifference == 0 && dayDifference == 1) { //"Yesterday at 10:23 AM", "Yesterday at 5:08 PM" [formatter setDateFormat:@"hh:mm a"]; strDate = [formatter stringFromDate:date]; timestamp = [NSString stringWithFormat:@"Yesterday at %@", strDate]; } else if (yearDifference == 0 && monthDifference == 0 && dayDifference < 7) { //"Tuesday at 7:13 PM" [formatter setDateFormat:@"EEEE"]; strDate = [formatter stringFromDate:date]; [formatter setDateFormat:@"hh:mm a"]; strDate2 = [formatter stringFromDate:date]; timestamp = [NSString stringWithFormat:@"%@ at %@", strDate, strDate2]; } else if (yearDifference == 0) { //"July 4 at 7:36 AM" [formatter setDateFormat:@"MMMM d"]; strDate = [formatter stringFromDate:date]; [formatter setDateFormat:@"hh:mm a"]; strDate2 = [formatter stringFromDate:date]; timestamp = [NSString stringWithFormat:@"%@ at %@", strDate, strDate2]; } else { //"March 24 2010 at 4:50 AM" [formatter setDateFormat:@"d MMMM yyyy"]; strDate = [formatter stringFromDate:date]; [formatter setDateFormat:@"hh:mm a"]; strDate2 = [formatter stringFromDate:date]; timestamp = [NSString stringWithFormat:@"%@ at %@", strDate, strDate2]; } } return timestamp; }
这只是前一个答案的副本,但是如果小于五秒,它就会返回。
func relativePast(for date : Date) -> String { let units = Set<Calendar.Component>([.year, .month, .day, .hour, .minute, .second, .weekOfYear]) let components = Calendar.current.dateComponents(units, from: date, to: Date()) if components.year! > 0 { return "\(components.year!) " + (components.year! > 1 ? "years ago" : "year ago") } else if components.month! > 0 { return "\(components.month!) " + (components.month! > 1 ? "months ago" : "month ago") } else if components.weekOfYear! > 0 { return "\(components.weekOfYear!) " + (components.weekOfYear! > 1 ? "weeks ago" : "week ago") } else if (components.day! > 0) { return (components.day! > 1 ? "\(components.day!) days ago" : "Yesterday") } else if components.hour! > 0 { return "\(components.hour!) " + (components.hour! > 1 ? "hours ago" : "hour ago") } else if components.minute! > 0 { return "\(components.minute!) " + (components.minute! > 1 ? "minutes ago" : "minute ago") } else { return "\(components.second!) " + (components.second! > 5 ? "seconds ago" : "Just Now".replacingOccurrences(of: "0", with: "") } }
doesRelativeDateFormatting
的问题是它几乎局限于Yesterday
, Today
, Tomorrow
。 如果你正在寻找更彻底的东西,那么看看这里的答案 。
如果期货date过晚,则采用Complate代码
NSCalendarUnit units = NSCalendarUnitDay | NSCalendarUnitWeekOfYear | NSCalendarUnitMonth | NSCalendarUnitYear; NSDateComponents *components = [[NSCalendar currentCalendar] components:units fromDate:date toDate:[NSDate date] options:0]; if (components.year < 0) { return [NSString stringWithFormat:@"%ld years from now", labs((long)components.year)]; } else if (components.month < 0) { return [NSString stringWithFormat:@"%ld months from now", labs((long)components.month)]; } else if (components.weekOfYear < 0) { return [NSString stringWithFormat:@"%ld weeks from now", labs((long)components.weekOfYear)]; } else if (components.day < 0) { if (components.day < 1) { return [NSString stringWithFormat:@"%ld days from now", labs((long)components.day)]; } else { return @"Tomorrow"; } } else if (components.year > 0) { return [NSString stringWithFormat:@"%ld years ago", (long)components.year]; } else if (components.month > 0) { return [NSString stringWithFormat:@"%ld months ago", (long)components.month]; } else if (components.weekOfYear > 0) { return [NSString stringWithFormat:@"%ld weeks ago", (long)components.weekOfYear]; } else if (components.day > 0) { if (components.day > 1) { return [NSString stringWithFormat:@"%ld days ago", (long)components.day]; } else { return @"Yesterday"; } } else { return @"Today"; }
我附上演示在这里请find这个链接。 TimestampAgo-演示
感谢nbprogrammer
编辑: –我做了与[NSTimeZone systemTimeZone]的Sourcetimezone更改,因为由于静态时区,以GMT或UTC格式发生。 (第二次进入减号)并更改不推荐使用的方法。
这是我在Swift 2中的解决scheme,通过比较两个date和零时间来避免24小时的问题。
extension NSDate { private func dateWithZeroTime(date: NSDate) -> NSDate? { let calendar = NSCalendar.currentCalendar() let units: NSCalendarUnit = [.Day, .WeekOfYear, .Month, .Year] let components = calendar.components(units, fromDate: date) return calendar.dateFromComponents(components) } private func thisDay() -> NSDate? { return self.dateWithZeroTime(self) } private func today() -> NSDate? { return self.dateWithZeroTime(NSDate()) } var relativeFormat: String? { let today = self.today() let thisDay = self.thisDay() let formatter = NSDateFormatter() formatter.dateStyle = NSDateFormatterStyle.LongStyle let dateString = formatter.stringFromDate(self) if nil != thisDay && nil != today { let units: NSCalendarUnit = [.Day, .WeekOfYear, .Month, .Year] let components = NSCalendar.currentCalendar().components(units, fromDate: thisDay!, toDate: today!, options: []) if (components.year > 0) { return components.year == 1 ? "A year ago, \(dateString)" : "\(components.year) years ago, \(dateString)" } else if (components.month > 0) { return components.month == 1 ? "A month ago, \(dateString)" : "\(components.month) months ago, \(dateString)" } else if (components.weekOfYear > 0) { return components.weekOfYear == 1 ? "A week ago, \(dateString)" : "\(components.weekOfYear) weeks ago, \(dateString)" } else if (components.day > 0) { return components.day == 1 ? "Yesterday, \(dateString)" : "\(self.dayOfTheWeek()), \(dateString)" } else { return "Today" } } return nil } func dayOfTheWeek() -> String { let weekdays = [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ] let calendar: NSCalendar = NSCalendar.currentCalendar() let components: NSDateComponents = calendar.components(.Weekday, fromDate: self) return weekdays[components.weekday - 1] } }
let formatter = DateComponentsFormatter() formatter.unitsStyle = .full let now = NSDate() let dateMakerFormatter = DateFormatter() dateMakerFormatter.dateFormat = "yyyy/MM/dd HH:mm:ss z" let dateString = "2017-03-13 10:38:54 +0000" let stPatricksDay = dateMakerFormatter.date(from: dateString)! let calendar = NSCalendar.current let components = calendar.dateComponents([.hour, .minute,.weekOfMonth,.day,.year,.month,.second], from: stPatricksDay, to: now as Date) if components.year! > 0 { formatter.allowedUnits = .year } else if components.month! > 0 { formatter.allowedUnits = .month } else if components.weekOfMonth! > 0 { formatter.allowedUnits = .weekOfMonth } else if components.day! > 0 { formatter.allowedUnits = .day } else if components.hour! > 0 { formatter.allowedUnits = .hour } else if components.minute! > 0 { formatter.allowedUnits = .minute } else { formatter.allowedUnits = .second } let formatString = NSLocalizedString("%@ ago", comment: "Used to say how much time has passed. eg '2 hours ago'") let timeString = formatter.string(from: components) String(format: formatString, timeString!)
将给定的“sourceDate”格式设置为今天“5:56 pm”,“昨天”为昨天的任何时间,“January 16”为同一年的任何一天,“2014年1月16日”。 我张贴我自己的方法。
sourceDate = //some date that you need to take into consideration NSDateComponents *components = [[NSCalendar currentCalendar] components:NSCalendarUnitMinute | NSCalendarUnitHour | NSCalendarUnitDay | NSCalendarUnitMonth | NSCalendarUnitYear fromDate:[NSDate date]]; NSDateComponents *sourceDateComponents = [[NSCalendar currentCalendar] components:NSCalendarUnitMinute | NSCalendarUnitHour | NSCalendarUnitDay | NSCalendarUnitMonth | NSCalendarUnitYear fromDate: sourceDate]; NSString* timestamp; NSDateFormatter *formatSourceDate = [NSDateFormatter new]; [formatSourceDate setAMSymbol:@"AM"]; [formatSourceDate setPMSymbol:@"PM"]; //same day - time in h:mm am/pm if (components.day == sourceDateComponents.day) { NSLogInfo(@"time"); [formatSourceDate setDateFormat:@"h:mm a"]; timestamp = [NSString stringWithFormat:@"%@",[formatSourceDate stringFromDate:date]]; return timestamp; } else if (components.day - sourceDateComponents.day == 1) { //yesterday timestamp = NSLocalizedString(@"Yesterday", nil); return timestamp; } if (components.year == sourceDateComponents.year) { //september 29, 5:56 pm [formatSourceDate setDateFormat:@"MMMM d"]; timestamp = [NSString stringWithFormat:@"%@",[formatSourceDate stringFromDate:date]]; return timestamp; } [formatSourceDate setDateFormat:@"MMMM d year"]; timestamp = [NSString stringWithFormat:@"%@",[formatSourceDate stringFromDate:date]]; return timestamp; NSLogInfo(@"Timestamp : %@",timestamp);