Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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:

  • today (if so, what time)

  • in the last seven days (if so, which day ... mon, tues etc?)

  • older than a week (if so, how to output in dd/mm/yy format?)

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

 

like image 825
cannyboy Avatar asked Nov 29 '22 11:11

cannyboy


2 Answers

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.

like image 95
Amos Joshua Avatar answered Dec 10 '22 08:12

Amos Joshua


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;
}
like image 40
cannyboy Avatar answered Dec 10 '22 09:12

cannyboy