cannyboy
cannyboy

Reputation: 24426

Getting human readable relative times and dates from a unix timestamp?

Starting with a unix timestamp like 1290529723, how would I (assuming gmt) get the information on whether it is:

I need this for a list of messages like the iPhone's Mail app, where date/times are shown relative to the current date and time, like so:

15:45
Yesterday
Sunday
Saturday
10/10/10

etc

 

Upvotes: 4

Views: 6429

Answers (6)

wholly_cow
wholly_cow

Reputation: 977

The NSDateFormatter class has what you need. It does do "today", "tomorrow" etc. via the doesRelativeDateFormatting method.

Hope that helps someone else who lands on here and doesn't want to use an external class or creates his own.

Upvotes: 4

Daniel Rinser
Daniel Rinser

Reputation: 8855

There is a library for that: TTTTimeIntervalFormatter in mattt's FormatterKit :)

Upvotes: 3

benathon
benathon

Reputation: 7633

I personally like the https://github.com/kevinlawler/NSDate-TimeAgo library on github. It only has two files and it's very simple to use. It also has localization if you want!

Upvotes: 4

Brad
Brad

Reputation: 11505

Convert it to an NSDate with:

+ (id)dateWithTimeIntervalSince1970:(NSTimeInterval)seconds

Then compare to other dates with:

* – compare:
* – earlierDate:
* – isEqual: (NSObject protocol)
* – laterDate:

Upvotes: 0

Amos Joshua
Amos Joshua

Reputation: 1743

It takes a bit of fiddling to get a solution that respects the device's locale. The following method relativeStringFromDate returns a string representing the date, formatted as following:

  • just the time if the date is today, according to locale (e.g. '3:40PM' or '15:40')
  • 'Yesterday' if the date is yesterday (but will be internationalized into locale's language)
  • name of the day of the week if date is two to six days ago (e.g. 'Monday', 'Tuesday', etc, again according to locale's language)
  • just the date component if the date is over one week ago, according to locale (e.g. '1/20/2012' in US vs '20/1/2012' in Europe)

    - (NSString *)relativeStringFromDate:(NSDate *)date {
        if ([self dateIsToday:date])
            return [self dateAsStringTime:date];
        else if ([self dateIsYesterday:date])
            return [self dateAsStringDate:date];
        else if ([self dateIsTwoToSixDaysAgo:date])
            return [self dateAsStringDay:date];
        else
            return [self dateAsStringDate:date];
    }
    
    - (BOOL)date:(NSDate *)date 
            isDayWithTimeIntervalSinceNow:(NSTimeInterval)interval {
        NSDateFormatter *df = [[NSDateFormatter alloc] init];
        [df setDateFormat:@"yyyy-MM-dd"];
    
        NSDate *other_date;
        other_date = [NSDate dateWithTimeIntervalSinceNow:interval];
    
        NSString *d1, *d2;
        d1 = [df stringFromDate:date];
        d2 = [df stringFromDate:other_date];
        return [d1 isEqualToString:d2];    
    }
    
    - (BOOL)dateIsToday:(NSDate *)date {
        return [self date:date isDayWithTimeIntervalSinceNow:0];
    }
    
    - (BOOL)dateIsYesterday:(NSDate *)date {
        return [self date:date isDayWithTimeIntervalSinceNow:-86400];
    }
    
    - (BOOL)dateIsTwoToSixDaysAgo:(NSDate *)date {
        for (int i = 2; i <= 6; i += 1)
            if ([self date:date isDayWithTimeIntervalSinceNow:i*-86400])
                return YES;
        return NO;    
    }
    
    - (NSString *)dateAsStringDate:(NSDate *)date {
        NSDateFormatter *df = [[NSDateFormatter alloc] init];
        [df setDateStyle:NSDateFormatterShortStyle];
        [df setDoesRelativeDateFormatting:YES];
        NSString *str = [df stringFromDate:date];
        return str;
    }
    
    - (NSString *)dateAsStringTime:(NSDate *)date {
        NSDateFormatter *df = [[NSDateFormatter alloc] init];
        [df setTimeStyle:NSDateFormatterShortStyle];
        NSString *str = [df stringFromDate:date];
        return str;
    }
    
    - (NSString *)dateAsStringDay:(NSDate *)date {
        NSDateFormatter *df = [[NSDateFormatter alloc] init];
        [df setDateFormat:@"EEEE"];
        NSString *str_day = [df stringFromDate:date];
        return str_day;
    }
    

As mentioned in yours and Brad's answers, you can obtain an NSDate from a timestamp using NSDate's dateWithTimeIntervalSince1970.

Upvotes: 9

cannyboy
cannyboy

Reputation: 24426

I made this method to change the unix time stamp into a nice readable, relative string. Probably doesn't work properly in the first few days of a new year, but hopefully you should be too hungover to notice.

-(NSString *)relativeTime:(int)datetimestamp
{
    NSDate *aDate = [NSDate dateWithTimeIntervalSince1970:datetimestamp];
    NSCalendar *calendar = [NSCalendar currentCalendar];
    unsigned int unitFlags =  NSYearCalendarUnit|NSMonthCalendarUnit|NSWeekCalendarUnit|NSWeekdayOrdinalCalendarUnit|NSWeekdayCalendarUnit|NSDayCalendarUnit|NSHourCalendarUnit|NSMinuteCalendarUnit;
    NSDateComponents *messageDateComponents = [calendar components:unitFlags fromDate:aDate];
    NSDateComponents *todayDateComponents = [calendar components:unitFlags fromDate:[NSDate date]];

    NSUInteger dayOfYearForMessage = [calendar ordinalityOfUnit:NSDayCalendarUnit inUnit:NSYearCalendarUnit forDate:aDate];
    NSUInteger dayOfYearForToday = [calendar ordinalityOfUnit:NSDayCalendarUnit inUnit:NSYearCalendarUnit forDate:[NSDate date]];


    NSString *dateString;

    if ([messageDateComponents year] == [todayDateComponents year] && 
        [messageDateComponents month] == [todayDateComponents month] &&
        [messageDateComponents day] == [todayDateComponents day]) 
    {
        dateString = [NSString stringWithFormat:@"%02d:%02d", [messageDateComponents hour], [messageDateComponents minute]];
    } else if ([messageDateComponents year] == [todayDateComponents year] && 
               dayOfYearForMessage == (dayOfYearForToday-1))
    {
        dateString = @"Yesterday";
    } else if ([messageDateComponents year] == [todayDateComponents year] &&
               dayOfYearForMessage > (dayOfYearForToday-6))
    {

        NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
        [dateFormatter setDateFormat:@"EEEE"];
        dateString = [dateFormatter stringFromDate:aDate];
        [dateFormatter release];

    } else {

        NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
        [dateFormatter setDateFormat:@"yy"];
        dateString = [NSString stringWithFormat:@"%02d/%02d/%@", [messageDateComponents day], [messageDateComponents month], [dateFormatter stringFromDate:aDate]];
        [dateFormatter release];
    }

    return dateString;
}

Upvotes: 4

Related Questions