iPhone:转换日期字符串到一个相对时间戳

问题描述:

我已经有了一个时间戳像一个字符串:iPhone:转换日期字符串到一个相对时间戳

周四,09年5月21日19时10分09秒-0700

和我'想要将它转换为'20分钟前'或'3天前'之类的相对时间戳。

使用Objective-C为iPhone做这件事的最好方法是什么?

+1

重复这一问题。 http://stackoverflow.com/questions/822124/fuzzy-date-algorithm – 2009-05-24 03:15:59

+0

...这反过来链接到这个问题:http://stackoverflow.com/questions/11(是的,问题#11) – 2010-11-17 21:24:27

+0

我发现此篇有用: [转换成nstimeinterval分秒等] [1] [1]:http://stackoverflow.com/questions/1189252/how-to-convert-an-nstimeinterval-seconds -into-minutes – 2011-07-25 18:03:42

-(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"; 
    } 
} 

使用的NSDate类:

timeIntervalSinceDate 

以秒返回的时间间隔。

快速运动来实现这个目标C:

  1. 获取时间“现在”的NSDate
  2. 获取的NSDate你想与
  3. 比较获得以秒为间隔使用timeIntervalSinceDate

然后实现这个伪代码:

if (x < 60) // x seconds ago 

else if(x/60 < 60) // floor(x/60) minutes ago 

else if (x/(60*60) < 24) // floor(x/(60*60) hours ago 

else if (x/(24*60*60) < 7) // floor(x(24*60*60) days ago 

等等......

那么你需要决定一个月是30,31还是28天。保持简单 - 挑选30

有可能是一个更好的办法,但它的凌晨2点,这是浮现在脑海的第一件事...

下面是从可可方法来帮助你获得相关信息(不知道他们是否都有可口可乐)。

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,这样做如下意见提出的方式,看起来很整洁,以及 - 我会继续我的答案历史原因,对于一些人来说,看看所用的逻辑可能仍然有用。

+0

ahh非常漂亮解决方案,谢谢! – 2009-05-26 00:37:41

+0

注意:旧的NSCalendarDate/NSDateComponents方式在Mac OS X上已被弃用。现在Apple似乎推荐使用NSDateFormatters。他们可以很容易地与任何组件搭配。另请参阅吉利的回答。 – andreb 2009-10-26 15:02:35

不知道为什么这不是可可触摸,我做这个很好的标准方法将是伟大的。

设置一些类型来保存数据,如果您需要更多的本地化数据,它会更容易。(很明显扩大,如果你需要更多的时间段)

typedef struct DayHours { 
    int Days; 
    double Hours; 
} DayHours; 


+ (DayHours) getHourBasedTimeInterval:(double) hourBased withHoursPerDay:(double) hpd 
{ 
    int NumberOfDays = (int)(fabs(hourBased)/hpd); 
    float hoursegment = fabs(hourBased) - (NumberOfDays * hpd); 
    DayHours dh; 
    dh.Days = NumberOfDays; 
    dh.Hours = hoursegment; 
    return dh; 
} 

注意:使用基于数计算我“米,因为这是我的数据是被第二基于NSTimeInterval我也不得不在两者之间转换。

我还不能编辑,但我还是把Gilean的代码,并做了几个调整的,并使其NSDateFormatter的一个类别。

它接受的格式字符串,以便将工作瓦特/任意字符串和我添加,如果子句有单数事件在语法上是正确的

干杯,

卡尔Ç-M

@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模仿轨漂亮的日期助手简单分类的完整代码。对于类别的复习,这些是您将调用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 *) dateToName:(NSDate*)dt withSec:(BOOL)sec { 

    NSLocale *locale = [NSLocale currentLocale]; 
    NSTimeInterval tI = [[NSDate date] timeIntervalSinceDate:dt]; 
    if (tI < 60) { 
     if (sec == NO) { 
      return NSLocalizedString(@"Just Now", @""); 
     } 
     return [NSString stringWithFormat: 
       NSLocalizedString(@"%d seconds ago", @""),(int)tI]; 
    } 
    if (tI < 3600) { 
     return [NSString stringWithFormat: 
       NSLocalizedString(@"%d minutes ago", @""),(int)(tI/60)]; 
    } 
    if (tI < 86400) { 
     return [NSString stringWithFormat: 
       NSLocalizedString(@"%d hours ago", @""),(int)tI/3600]; 
    } 

    NSDateFormatter *relativeDateFormatter = [[NSDateFormatter alloc] init]; 
    [relativeDateFormatter setTimeStyle:NSDateFormatterNoStyle]; 
    [relativeDateFormatter setDateStyle:NSDateFormatterMediumStyle]; 
    [relativeDateFormatter setDoesRelativeDateFormatting:YES]; 
    [relativeDateFormatter setLocale:locale]; 

    NSString * relativeFormattedString = 
      [relativeDateFormatter stringForObjectValue:dt]; 
    return relativeFormattedString; 
} 

我把卡尔·科里尔 - 马丁公司的代码和由不具有对英文单的字符串格式化的警告更简单的NSDate类别,也tidys了一周前奇异:

@interface NSDate (Extras) 
- (NSString *)differenceString; 
@end 

@implementation NSDate (Extras) 

- (NSString *)differenceString{ 
    NSDate* date = self; 
    NSDate *now = [NSDate date]; 
    double time = [date timeIntervalSinceDate:now]; 
    time *= -1; 
    if (time < 60) { 
     int diff = round(time); 
     if (diff == 1) 
      return @"1 second ago"; 
     return [NSString stringWithFormat:@"%d seconds ago", diff]; 
    } else if (time < 3600) { 
     int diff = round(time/60); 
     if (diff == 1) 
      return @"1 minute ago"; 
     return [NSString stringWithFormat:@"%d minutes ago", diff]; 
    } else if (time < 86400) { 
     int diff = round(time/60/60); 
     if (diff == 1) 
      return @"1 hour ago"; 
     return [NSString stringWithFormat:@"%d hours ago", diff]; 
    } else if (time < 604800) { 
     int diff = round(time/60/60/24); 
     if (diff == 1) 
      return @"yesterday"; 
     if (diff == 7) 
      return @"a week ago"; 
     return[NSString stringWithFormat:@"%d days ago", diff]; 
    } else { 
     int diff = round(time/60/60/24/7); 
     if (diff == 1) 
      return @"a week ago"; 
     return [NSString stringWithFormat:@"%d weeks ago", diff]; 
    } 
} 

@end 

我看到有几个前段时间功能在堆栈溢出的代码片段,我想一个真正放弃的时候最明显的感觉(因为一些诉权n发生)。对我而言,这意味着在较短的时间间隔(5分钟前,2小时前)和较长时间段(2011年4月15日,而不是2年前)的特定日期的“时间前”风格。基本上我认为Facebook在这方面做得非常出色,我想要以他们的榜样为例(因为我确信他们对此有很多想法,并且从消费者的角度来看很容易理解)。

经过了很长时间的谷歌搜索后,我很惊讶地发现没有人按照我的说法实现了这一点。决定我想花时间写作并认为我会分享。

希望您能喜欢:)

获取此代码:https://github.com/nikilster/NSDate-Time-Ago

已经有很多这得出了同样的解决答案,但它不能伤害有选择。这是我想出来的。

- (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]; 
} 

在斯威夫特

用法:

let time = NSDate(timeIntervalSince1970: timestamp).timeIntervalSinceNow 
let relativeTimeString = NSDate.relativeTimeInString(time) 
println(relativeTimeString) 

扩展:

extension NSDate { 
    class func relativeTimeInString(value: NSTimeInterval) -> String { 
     func getTimeData(value: NSTimeInterval) -> (count: Int, suffix: String) { 
      let count = Int(floor(value)) 
      let suffix = count != 1 ? "s" : "" 
      return (count: count, suffix: suffix) 
     } 

     let value = -value 
     switch value { 
      case 0...15: return "just now" 

      case 0..<60: 
       let timeData = getTimeData(value) 
       return "\(timeData.count) second\(timeData.suffix) ago" 

      case 0..<3600: 
       let timeData = getTimeData(value/60) 
       return "\(timeData.count) minute\(timeData.suffix) ago" 

      case 0..<86400: 
       let timeData = getTimeData(value/3600) 
       return "\(timeData.count) hour\(timeData.suffix) ago" 

      case 0..<604800: 
       let timeData = getTimeData(value/86400) 
       return "\(timeData.count) day\(timeData.suffix) ago" 

      default: 
       let timeData = getTimeData(value/604800) 
       return "\(timeData.count) week\(timeData.suffix) ago" 
     } 
    } 
}