How to convert NSDate in to relative format as “To

2019-01-06 10:08发布

I want to convert nsdate in to relative format like "Today","Yesterday","a week ago","a month ago","a year ago","date as it is".

I have written following method for it.. but some how its just printing as it is date.. can you please tell me what should be the problem?

//Following is my function which converts the date into relative string

+(NSString *)getDateDiffrence:(NSDate *)strDate{
    NSDateFormatter *df = [[NSDateFormatter alloc] init];

    df.timeStyle = NSDateFormatterMediumStyle;
    df.dateStyle = NSDateFormatterShortStyle;
    df.doesRelativeDateFormatting = YES;
    NSLog(@"STRING DATEEE : %@ REAL DATE TODAY %@",[df stringFromDate:strDate],[NSDate date]);
      return [df stringFromDate:strDate];

}

I have date string with the following format "2013-10-29T09:38:00"

When I tried to give the NSDate object then its always return me null date.
so I tried to convert that date in to yyyy-MM-dd HH:mm:ssZZZZ then I pass this date to function then it's just printing whole date..

How to solve this problem?

//Following is the code I call the above function

NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss"];
NSDate *date = [formatter dateFromString:[threadDict objectForKey:@"lastMessageDate"]];
[formatter setDateFormat:@"yyyy-MM-dd HH:mm:ssZZZZ"];

NSString *date1 = [formatter stringFromDate:date];
NSDate *date_d = [formatter dateFromString:date1];
NSString *resultstr=[UserManager getDateDiffrence:date];

self.dateLabel.text=resultstr;

16条回答
爷的心禁止访问
2楼-- · 2019-01-06 10:43

Complate Code If Futures Dates

NSCalendarUnit units = NSCalendarUnitDay | NSCalendarUnitWeekOfYear | 
                           NSCalendarUnitMonth | NSCalendarUnitYear;


    NSDateComponents *components = [[NSCalendar currentCalendar] components:units fromDate:date toDate:[NSDate date] options:0];

    if (components.year < 0) {
            return [NSString stringWithFormat:@"%ld years from now", labs((long)components.year)];
        } else if (components.month < 0) {
            return [NSString stringWithFormat:@"%ld months from now", labs((long)components.month)];
        } else if (components.weekOfYear < 0) {
            return [NSString stringWithFormat:@"%ld weeks from now", labs((long)components.weekOfYear)];
        } else if (components.day < 0) {
            if (components.day < 1) {
                return [NSString stringWithFormat:@"%ld days from now", labs((long)components.day)];
            } else {
                return @"Tomorrow";
            }
        }
        else if (components.year > 0) {
            return [NSString stringWithFormat:@"%ld years ago", (long)components.year];
        } else if (components.month > 0) {
            return [NSString stringWithFormat:@"%ld months ago", (long)components.month];
        } else if (components.weekOfYear > 0) {
            return [NSString stringWithFormat:@"%ld weeks ago", (long)components.weekOfYear];
        } else if (components.day > 0) {
            if (components.day > 1) {
                return [NSString stringWithFormat:@"%ld days ago", (long)components.day];
            } else {
                return @"Yesterday";
            }
        } else {
            return @"Today";
        }
查看更多
走好不送
3楼-- · 2019-01-06 10:46

FOR: SWIFT 3

Here's a Swift 3 version, for past dates, that handles all units and singular or plural in the returned String.

Example Use:

let oneWeekAgo = Calendar.current.date(byAdding: .weekOfYear, value: -1, to: Date())!

print(relativePast(for: oneWeekAgo)) // output: "1 week ago"

I based it on a riff off of Saurabh Yadav's. Thanks.

func relativePast(for date : Date) -> String {

    let units = Set<Calendar.Component>([.year, .month, .day, .hour, .minute, .second, .weekOfYear])
    let components = Calendar.current.dateComponents(units, from: date, to: Date())

    if components.year! > 0 {
        return "\(components.year!) " + (components.year! > 1 ? "years ago" : "year ago")

    } else if components.month! > 0 {
        return "\(components.month!) " + (components.month! > 1 ? "months ago" : "month ago")

    } else if components.weekOfYear! > 0 {
        return "\(components.weekOfYear!) " + (components.weekOfYear! > 1 ? "weeks ago" : "week ago")

    } else if (components.day! > 0) {
        return (components.day! > 1 ? "\(components.day!) days ago" : "Yesterday")

    } else if components.hour! > 0 {
        return "\(components.hour!) " + (components.hour! > 1 ? "hours ago" : "hour ago")

    } else if components.minute! > 0 {
        return "\(components.minute!) " + (components.minute! > 1 ? "minutes ago" : "minute ago")

    } else {
        return "\(components.second!) " + (components.second! > 1 ? "seconds ago" : "second ago")
    }
}
查看更多
该账号已被封号
4楼-- · 2019-01-06 10:48
NSString* AgoStringFromTime(NSDate* dateTime)
{
    NSDictionary *timeScale = @{@"sec"  :@1,
                                @"min"  :@60,
                                @"hr"   :@3600,
                                @"day"  :@86400,
                                @"week" :@605800,
                                @"month":@2629743,
                                @"year" :@31556926};
    NSString *scale;
    int timeAgo = 0-(int)[dateTime timeIntervalSinceNow];
    if (timeAgo < 60) {
        scale = @"sec";
    } else if (timeAgo < 3600) {
        scale = @"min";
    } else if (timeAgo < 86400) {
        scale = @"hr";
    } 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 %@%@", timeAgo, scale, s];
}
查看更多
虎瘦雄心在
5楼-- · 2019-01-06 10:50
let formatter = DateComponentsFormatter()
formatter.unitsStyle = .full

let now = NSDate()


let dateMakerFormatter = DateFormatter()

dateMakerFormatter.dateFormat = "yyyy/MM/dd HH:mm:ss z"
let dateString = "2017-03-13 10:38:54 +0000"
let stPatricksDay = dateMakerFormatter.date(from: dateString)!


let calendar = NSCalendar.current



let components = calendar.dateComponents([.hour, .minute,.weekOfMonth,.day,.year,.month,.second], from: stPatricksDay, to: now as Date)



if components.year! > 0 {
    formatter.allowedUnits = .year
} else if components.month! > 0 {
    formatter.allowedUnits = .month
} else if components.weekOfMonth! > 0 {
    formatter.allowedUnits = .weekOfMonth
} else if components.day! > 0 {
    formatter.allowedUnits = .day
} else if components.hour! > 0 {
    formatter.allowedUnits = .hour
} else if components.minute! > 0 {
    formatter.allowedUnits = .minute
} else {
    formatter.allowedUnits = .second
}

let formatString = NSLocalizedString("%@ ago", comment: "Used to say how much time has passed. e.g. '2 hours ago'")

 let timeString = formatter.string(from: components)

String(format: formatString, timeString!)
查看更多
我欲成王,谁敢阻挡
6楼-- · 2019-01-06 10:51

This is just a copy of a previous answer but it returns Just now if it is less than five seconds.

func relativePast(for date : Date) -> String {

    let units = Set<Calendar.Component>([.year, .month, .day, .hour, .minute, .second, .weekOfYear])
    let components = Calendar.current.dateComponents(units, from: date, to: Date())

    if components.year! > 0 {
        return "\(components.year!) " + (components.year! > 1 ? "years ago" : "year ago")

    } else if components.month! > 0 {
        return "\(components.month!) " + (components.month! > 1 ? "months ago" : "month ago")

    } else if components.weekOfYear! > 0 {
        return "\(components.weekOfYear!) " + (components.weekOfYear! > 1 ? "weeks ago" : "week ago")

    } else if (components.day! > 0) {
        return (components.day! > 1 ? "\(components.day!) days ago" : "Yesterday")

    } else if components.hour! > 0 {
        return "\(components.hour!) " + (components.hour! > 1 ? "hours ago" : "hour ago")

    } else if components.minute! > 0 {
        return "\(components.minute!) " + (components.minute! > 1 ? "minutes ago" : "minute ago")

    } else {
        return "\(components.second!) " + (components.second! > 5 ? "seconds ago" : "Just Now".replacingOccurrences(of: "0", with: "")
    }
}
查看更多
闹够了就滚
7楼-- · 2019-01-06 10:53

For simplicity I'm assuming that the dates you are formatting are all in the past (no "tomorrow" or "next week"). It's not that it can't be done but it would be more cases to deal with and more strings to return.


You can use components:fromDate:toDate:options: with whatever combination of date components you are looking for to get the number of years, months, weeks, days, hours, etc. between two dates. By then going though them in order from most significant (e.g. year) to least significant (e.g. day), you can format a string based only on the most significant component.

For example: a date that is 1 week, 2 days and 7 hours ago would be formatted as "1 week".

If you want to create special strings for a special number of a unit, like "tomorrow" for "1 day ago" then you can check the value of that component after you have determined that it is the most significant component.

The code would look something like this:

- (NSString *)relativeDateStringForDate:(NSDate *)date
{
    NSCalendarUnit units = NSCalendarUnitDay | NSCalendarUnitWeekOfYear | 
                           NSCalendarUnitMonth | NSCalendarUnitYear;

    // if `date` is before "now" (i.e. in the past) then the components will be positive
    NSDateComponents *components = [[NSCalendar currentCalendar] components:units
                                                                   fromDate:date
                                                                     toDate:[NSDate date]
                                                                    options:0];

    if (components.year > 0) {
        return [NSString stringWithFormat:@"%ld years ago", (long)components.year];
    } else if (components.month > 0) {
        return [NSString stringWithFormat:@"%ld months ago", (long)components.month];
    } else if (components.weekOfYear > 0) {
        return [NSString stringWithFormat:@"%ld weeks ago", (long)components.weekOfYear];
    } else if (components.day > 0) {
        if (components.day > 1) {
            return [NSString stringWithFormat:@"%ld days ago", (long)components.day];
        } else {
            return @"Yesterday";
        }
    } else {
        return @"Today";
    }
}

If your dates could also be in the future then you can check the absolute value of the components in the same order and then check if it's positive or negative to return the appropriate strings. I'me only showing the year below:

if ( abs(components.year > 0) ) { 
    // year is most significant component
    if (components.year > 0) {
        // in the past
        return [NSString stringWithFormat:@"%ld years ago", (long)components.year];
    } else {
        // in the future
        return [NSString stringWithFormat:@"In %ld years", (long)components.year];
    }
} 
查看更多
登录 后发表回答