iPhone:将日期字符串转换为相对时间戳

时间:2022-04-07 01:57:38

I've got a timestamp as a string like:

我有一个时间戳像这样的字符串:

Thu, 21 May 09 19:10:09 -0700

Thu, 09年5月21日19:10:09 -0700。

and I'd like to convert it to a relative time stamp like '20 minutes ago' or '3 days ago'.

我想把它转换成一个相对时间戳,比如“20分钟前”或“3天前”。

What's the best way to do this using Objective-C for the iPhone?

用Objective-C来做iPhone的最好方法是什么?

11 个解决方案

#1


71  

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

#2


22  

Here are methods from Cocoa to help you to get relevant info (not sure if they are all available in coca-touch).

这里有一些Cocoa的方法来帮助你获得相关信息(不确定它们是否都可以用古柯尔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]);

The NSDateComponents object seems to hold the difference in relevant units (as specified). If you specify all units you can then use this method:

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

If you want to calculate yourself you can have a look at:

如果你想计算你自己,你可以看看:

NSDate timeIntervalSinceDate

And then use seconds in the algorithm.

然后在算法中使用秒。

Disclaimer: If this interface is getting deprecated (I haven't checked), Apple's preferred way of doing this via NSDateFormatters, as suggested in comments below, looks pretty neat as well - I'll keep my answer for historical reasons, it may still be useful for some to look at the logic used.

免责声明:如果这个接口被弃用了(我还没有检查),那么苹果通过NSDateFormatters进行此操作的首选方式(如下面的评论所示)看上去也相当整洁——出于历史原因,我将保留我的答案,对于一些人来说,查看使用的逻辑可能仍然有用。

#3


14  

I can't edit yet, but I took Gilean's code and made a couple of tweaks and made it a category of NSDateFormatter.

我还不能编辑,但是我使用了Gilean的代码,做了一些调整,使它成为NSDateFormatter的一个类别。

It accepts a format string so it will work w/ arbitrary strings and I added if clauses to have singular events be grammatically correct.

它接受一个格式字符串,因此它可以处理w/任意的字符串,我还添加了if子句,使其具有语法上正确的单数事件。

Cheers,

欢呼,

Carl C-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

#4


8  

In the interest of completeness, based on a @Gilean's answer, here's the complete code for a simple category on NSDate that mimics rails' nifty date helpers. For a refresher on categories, these are instance methods that you would call on NSDate objects. So, if I have an NSDate that represents yesterday, [myDate distanceOfTimeInWordsToNow] => "1 day".

出于完整性的考虑,基于@Gilean的回答,以下是NSDate上一个简单类别的完整代码,它模仿了rails漂亮的日期助手。对于类别的复习,这些是实例方法,您可以在NSDate对象上调用它们。所以,如果我有一个代表昨天的NSDate, [myDate distanceOfTimeInWordsToNow] => "1天"。

Hope it's useful!

希望它是有用的!

@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

#5


6  

There are already a lot of answers that come to the same solution but it can't hurt to have choices. Here's what I came up with.

已经有很多的答案来解决同样的问题,但是有选择是没有坏处的。这是我想到的。

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

#6


4  

I took Carl Coryell-Martin's code and made a simpler NSDate category that doesn't have warnings about the string formatting of the singulars, and also tidys up the week ago singular:

我使用了卡尔·科瑞尔-马丁的代码,制作了一个更简单的NSDate类别,它没有关于单线的字符串格式的警告,而且还整理了一周前的单数:

@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

#7


3  

In Swift

在斯威夫特

Usage:

用法:

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

Extension:

扩展:

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

#8


1  

Use the NSDate class:

使用NSDate类:

timeIntervalSinceDate

returns the interval in seconds.

返回以秒为单位的间隔。

Quick exercise to implement this in objective-c:

快速练习在objective-c中实现这一点:

  1. Get time "now" NSDate
  2. “现在”NSDate得到时间
  3. Get the NSDate you wish to compare with
  4. 获取您希望与之比较的NSDate。
  5. Get the interval in seconds using timeIntervalSinceDate
  6. 使用timeIntervalSinceDate以秒为单位获取间隔

Then implement this pseudo code:

然后实现这个伪代码:

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

and so on...

等等……

then you need to decide whether a month is 30,31 or 28 days. Keep it simple - pick 30.

然后你需要决定一个月是30天,31天还是28天。保持简单——挑选30个。

There might be a better way, but its 2am and this is the first thing that came to mind...

也许有更好的办法,但是凌晨两点,这是我首先想到的……

#9


1  

My solution:

我的解决方案:

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

#10


0  

Not sure why this isnt in cocoa-touch, i nice standard way of doing this would be great.

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

Set up some types to keep the data in, it will make it easier if you ever ned to localise it a bit more. (obviously expand if you need more time periods)

设置一些类型来保存数据,如果您想要使数据本地化更多一点的话,会更容易一些。(如果你需要更多的时间)

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

NOTE: I"m using an hour based calculation , as that is what my data is in. NSTimeInterval is second based. I also had to convert between the two.

注意:我使用一个小时计算,因为这是我的数据。基于NSTimeInterval第二。我还需要在两者之间进行转换。

#11


0  

I saw that there were several time ago functions in snippets of code on Stack Overflow and I wanted one that really gave the clearest sense of the time (since some action occurred). To me this means "time ago" style for short time intervals (5 min ago, 2 hours ago) and specific dates for longer time periods (April 15, 2011 instead of 2 years ago). Basically I thought Facebook did a really good job at this and I wanted to just go by their example (as I'm sure they out a lot of thought into this and it is very easy and clear to understand from the consumer perspective).

我看到有几段时间以前,在Stack Overflow的代码片段中有一些函数,我想要一个能够真正给出最清晰的时间感觉的函数(因为一些操作发生了)。对我来说,这意味着“时间前”的短时间间隔(5分钟前,2小时前)和较长时间的特定日期(2011年4月15日,而不是2年前)。基本上,我认为Facebook在这方面做得很好,我想以他们为例(我相信他们对此有很多想法,从消费者的角度来看,这很容易理解)。

After a long time of googling I was pretty surprised to see that no one had implemented this as far as I could tell. Decided that I wanted it bad enough to spend the time writing and thought that I would share.

在谷歌上搜索了很长一段时间之后,我很惊讶地发现,就我所知,还没有人实现这个功能。决定我想要它足够坏花时间写和认为我将分享。

Hope you enjoy :)

希望你喜欢:)

Get the code here: https://github.com/nikilster/NSDate-Time-Ago

在这里获取代码:https://github.com/nikilster/NSDate-Time-Ago

#1


71  

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

#2


22  

Here are methods from Cocoa to help you to get relevant info (not sure if they are all available in coca-touch).

这里有一些Cocoa的方法来帮助你获得相关信息(不确定它们是否都可以用古柯尔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]);

The NSDateComponents object seems to hold the difference in relevant units (as specified). If you specify all units you can then use this method:

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

If you want to calculate yourself you can have a look at:

如果你想计算你自己,你可以看看:

NSDate timeIntervalSinceDate

And then use seconds in the algorithm.

然后在算法中使用秒。

Disclaimer: If this interface is getting deprecated (I haven't checked), Apple's preferred way of doing this via NSDateFormatters, as suggested in comments below, looks pretty neat as well - I'll keep my answer for historical reasons, it may still be useful for some to look at the logic used.

免责声明:如果这个接口被弃用了(我还没有检查),那么苹果通过NSDateFormatters进行此操作的首选方式(如下面的评论所示)看上去也相当整洁——出于历史原因,我将保留我的答案,对于一些人来说,查看使用的逻辑可能仍然有用。

#3


14  

I can't edit yet, but I took Gilean's code and made a couple of tweaks and made it a category of NSDateFormatter.

我还不能编辑,但是我使用了Gilean的代码,做了一些调整,使它成为NSDateFormatter的一个类别。

It accepts a format string so it will work w/ arbitrary strings and I added if clauses to have singular events be grammatically correct.

它接受一个格式字符串,因此它可以处理w/任意的字符串,我还添加了if子句,使其具有语法上正确的单数事件。

Cheers,

欢呼,

Carl C-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

#4


8  

In the interest of completeness, based on a @Gilean's answer, here's the complete code for a simple category on NSDate that mimics rails' nifty date helpers. For a refresher on categories, these are instance methods that you would call on NSDate objects. So, if I have an NSDate that represents yesterday, [myDate distanceOfTimeInWordsToNow] => "1 day".

出于完整性的考虑,基于@Gilean的回答,以下是NSDate上一个简单类别的完整代码,它模仿了rails漂亮的日期助手。对于类别的复习,这些是实例方法,您可以在NSDate对象上调用它们。所以,如果我有一个代表昨天的NSDate, [myDate distanceOfTimeInWordsToNow] => "1天"。

Hope it's useful!

希望它是有用的!

@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

#5


6  

There are already a lot of answers that come to the same solution but it can't hurt to have choices. Here's what I came up with.

已经有很多的答案来解决同样的问题,但是有选择是没有坏处的。这是我想到的。

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

#6


4  

I took Carl Coryell-Martin's code and made a simpler NSDate category that doesn't have warnings about the string formatting of the singulars, and also tidys up the week ago singular:

我使用了卡尔·科瑞尔-马丁的代码,制作了一个更简单的NSDate类别,它没有关于单线的字符串格式的警告,而且还整理了一周前的单数:

@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

#7


3  

In Swift

在斯威夫特

Usage:

用法:

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

Extension:

扩展:

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

#8


1  

Use the NSDate class:

使用NSDate类:

timeIntervalSinceDate

returns the interval in seconds.

返回以秒为单位的间隔。

Quick exercise to implement this in objective-c:

快速练习在objective-c中实现这一点:

  1. Get time "now" NSDate
  2. “现在”NSDate得到时间
  3. Get the NSDate you wish to compare with
  4. 获取您希望与之比较的NSDate。
  5. Get the interval in seconds using timeIntervalSinceDate
  6. 使用timeIntervalSinceDate以秒为单位获取间隔

Then implement this pseudo code:

然后实现这个伪代码:

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

and so on...

等等……

then you need to decide whether a month is 30,31 or 28 days. Keep it simple - pick 30.

然后你需要决定一个月是30天,31天还是28天。保持简单——挑选30个。

There might be a better way, but its 2am and this is the first thing that came to mind...

也许有更好的办法,但是凌晨两点,这是我首先想到的……

#9


1  

My solution:

我的解决方案:

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

#10


0  

Not sure why this isnt in cocoa-touch, i nice standard way of doing this would be great.

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

Set up some types to keep the data in, it will make it easier if you ever ned to localise it a bit more. (obviously expand if you need more time periods)

设置一些类型来保存数据,如果您想要使数据本地化更多一点的话,会更容易一些。(如果你需要更多的时间)

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

NOTE: I"m using an hour based calculation , as that is what my data is in. NSTimeInterval is second based. I also had to convert between the two.

注意:我使用一个小时计算,因为这是我的数据。基于NSTimeInterval第二。我还需要在两者之间进行转换。

#11


0  

I saw that there were several time ago functions in snippets of code on Stack Overflow and I wanted one that really gave the clearest sense of the time (since some action occurred). To me this means "time ago" style for short time intervals (5 min ago, 2 hours ago) and specific dates for longer time periods (April 15, 2011 instead of 2 years ago). Basically I thought Facebook did a really good job at this and I wanted to just go by their example (as I'm sure they out a lot of thought into this and it is very easy and clear to understand from the consumer perspective).

我看到有几段时间以前,在Stack Overflow的代码片段中有一些函数,我想要一个能够真正给出最清晰的时间感觉的函数(因为一些操作发生了)。对我来说,这意味着“时间前”的短时间间隔(5分钟前,2小时前)和较长时间的特定日期(2011年4月15日,而不是2年前)。基本上,我认为Facebook在这方面做得很好,我想以他们为例(我相信他们对此有很多想法,从消费者的角度来看,这很容易理解)。

After a long time of googling I was pretty surprised to see that no one had implemented this as far as I could tell. Decided that I wanted it bad enough to spend the time writing and thought that I would share.

在谷歌上搜索了很长一段时间之后,我很惊讶地发现,就我所知,还没有人实现这个功能。决定我想要它足够坏花时间写和认为我将分享。

Hope you enjoy :)

希望你喜欢:)

Get the code here: https://github.com/nikilster/NSDate-Time-Ago

在这里获取代码:https://github.com/nikilster/NSDate-Time-Ago