我有一个时间戳作为字符串,如:
星期四,2009年5月21日19:10:09 -0700
而且我想将它转换为像'20分钟前'或'3天前'的相对时间戳.
使用Objective-C为iPhone做到这一点的最佳方法是什么?
-(NSString *)dateDiff:(NSString *)origDate { NSDateFormatter *df = [[NSDateFormatter alloc] init]; [df setFormatterBehavior:NSDateFormatterBehavior10_4]; [df setDateFormat:@"EEE, dd MMM yy HH:mm:ss VVVV"]; NSDate *convertedDate = [df dateFromString:origDate]; [df release]; NSDate *todayDate = [NSDate date]; double ti = [convertedDate timeIntervalSinceDate:todayDate]; ti = ti * -1; if(ti < 1) { return @"never"; } else if (ti < 60) { return @"less than a minute ago"; } else if (ti < 3600) { int diff = round(ti / 60); return [NSString stringWithFormat:@"%d minutes ago", diff]; } else if (ti < 86400) { int diff = round(ti / 60 / 60); return[NSString stringWithFormat:@"%d hours ago", diff]; } else if (ti < 2629743) { int diff = round(ti / 60 / 60 / 24); return[NSString stringWithFormat:@"%d days ago", diff]; } else { return @"never"; } }
以下是来自Cocoa的方法,可以帮助您获取相关信息(不确定它们是否都可以通过coca-touch获得).
NSDate * today = [NSDate date]; NSLog(@"today: %@", today); NSString * str = @"Thu, 21 May 09 19:10:09 -0700"; NSDate * past = [NSDate dateWithNaturalLanguageString:str locale:[[NSUserDefaults standardUserDefaults] dictionaryRepresentation]]; NSLog(@"str: %@", str); NSLog(@"past: %@", past); NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; unsigned int unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit; NSDateComponents *components = [gregorian components:unitFlags fromDate:past toDate:today options:0]; NSLog(@"months: %d", [components month]); NSLog(@"days: %d", [components day]); NSLog(@"hours: %d", [components hour]); NSLog(@"seconds: %d", [components second]);
NSDateComponents对象似乎在相关单位中保持差异(如指定的那样).如果指定所有单位,则可以使用此方法:
void dump(NSDateComponents * t) { if ([t year]) NSLog(@"%d years ago", [t year]); else if ([t month]) NSLog(@"%d months ago", [t month]); else if ([t day]) NSLog(@"%d days ago", [t day]); else if ([t minute]) NSLog(@"%d minutes ago", [t minute]); else if ([t second]) NSLog(@"%d seconds ago", [t second]); }
如果你想自己计算,你可以看看:
NSDate timeIntervalSinceDate
然后在算法中使用秒.
免责声明:如果这个界面被弃用(我还没有检查过),苹果公司首选的做法NSDateFormatters
,如下面的评论所示,看起来也很漂亮 - 我会保留我的答案,因为历史原因,它可能仍然是有些人可以看一下使用的逻辑.
我还无法编辑,但我采用了Gilean的代码并进行了一些调整,并使其成为NSDateFormatter的一个类别.
它接受一个格式字符串,因此它将使用任意字符串,并且我添加了if子句以使单个事件在语法上正确.
干杯,
卡尔CM
@interface NSDateFormatter (Extras) + (NSString *)dateDifferenceStringFromString:(NSString *)dateString withFormat:(NSString *)dateFormat; @end @implementation NSDateFormatter (Extras) + (NSString *)dateDifferenceStringFromString:(NSString *)dateString withFormat:(NSString *)dateFormat { NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; [dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4]; [dateFormatter setDateFormat:dateFormat]; NSDate *date = [dateFormatter dateFromString:dateString]; [dateFormatter release]; NSDate *now = [NSDate date]; double time = [date timeIntervalSinceDate:now]; time *= -1; if(time < 1) { return dateString; } else if (time < 60) { return @"less than a minute ago"; } else if (time < 3600) { int diff = round(time / 60); if (diff == 1) return [NSString stringWithFormat:@"1 minute ago", diff]; return [NSString stringWithFormat:@"%d minutes ago", diff]; } else if (time < 86400) { int diff = round(time / 60 / 60); if (diff == 1) return [NSString stringWithFormat:@"1 hour ago", diff]; return [NSString stringWithFormat:@"%d hours ago", diff]; } else if (time < 604800) { int diff = round(time / 60 / 60 / 24); if (diff == 1) return [NSString stringWithFormat:@"yesterday", diff]; if (diff == 7) return [NSString stringWithFormat:@"last week", diff]; return[NSString stringWithFormat:@"%d days ago", diff]; } else { int diff = round(time / 60 / 60 / 24 / 7); if (diff == 1) return [NSString stringWithFormat:@"last week", diff]; return [NSString stringWithFormat:@"%d weeks ago", diff]; } } @end
为了完整性,基于@Gilean的答案,这里是NSDate上一个简单类别的完整代码,模仿rails的漂亮日期帮助器.有关类别的更新,这些是您将在NSDate对象上调用的实例方法.所以,如果我有一个代表昨天的NSDate,[myDate distanceOfTimeInWordsToNow] =>"1天".
希望它有用!
@interface NSDate (NSDate_Relativity) -(NSString *)distanceOfTimeInWordsSinceDate:(NSDate *)aDate; -(NSString *)distanceOfTimeInWordsToNow; @end @implementation NSDate (NSDate_Relativity) -(NSString *)distanceOfTimeInWordsToNow { return [self distanceOfTimeInWordsSinceDate:[NSDate date]]; } -(NSString *)distanceOfTimeInWordsSinceDate:(NSDate *)aDate { double interval = [self timeIntervalSinceDate:aDate]; NSString *timeUnit; int timeValue; if (interval < 0) { interval = interval * -1; } if (interval< 60) { return @"seconds"; } else if (interval< 3600) { // minutes timeValue = round(interval / 60); if (timeValue == 1) { timeUnit = @"minute"; } else { timeUnit = @"minutes"; } } else if (interval< 86400) { timeValue = round(interval / 60 / 60); if (timeValue == 1) { timeUnit = @"hour"; } else { timeUnit = @"hours"; } } else if (interval< 2629743) { int days = round(interval / 60 / 60 / 24); if (days < 7) { timeValue = days; if (timeValue == 1) { timeUnit = @"day"; } else { timeUnit = @"days"; } } else if (days < 30) { int weeks = days / 7; timeValue = weeks; if (timeValue == 1) { timeUnit = @"week"; } else { timeUnit = @"weeks"; } } else if (days < 365) { int months = days / 30; timeValue = months; if (timeValue == 1) { timeUnit = @"month"; } else { timeUnit = @"months"; } } else if (days < 30000) { // this is roughly 82 years. After that, we'll say 'forever' int years = days / 365; timeValue = years; if (timeValue == 1) { timeUnit = @"year"; } else { timeUnit = @"years"; } } else { return @"forever ago"; } } return [NSString stringWithFormat:@"%d %@", timeValue, timeUnit]; } @end
已经有很多答案出现在同一个解决方案中,但选择却不会有什么坏处.这就是我想出来的.
- (NSString *)stringForTimeIntervalSinceCreated:(NSDate *)dateTime { NSDictionary *timeScale = @{@"second":@1, @"minute":@60, @"hour":@3600, @"day":@86400, @"week":@605800, @"month":@2629743, @"year":@31556926}; NSString *scale; int timeAgo = 0-(int)[dateTime timeIntervalSinceNow]; if (timeAgo < 60) { scale = @"second"; } else if (timeAgo < 3600) { scale = @"minute"; } else if (timeAgo < 86400) { scale = @"hour"; } 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 %@%@ ago", timeAgo, scale, s]; }