How to convert NSDate in to relative format as “Today”,“Yesterday”,“a week ago”,“a month ago”,“a year ago”?

前端 未结 16 2049
天命终不由人
天命终不由人 2020-11-28 22: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 writ

相关标签:
16条回答
  • 2020-11-28 22:50
    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];
    }
    
    0 讨论(0)
  • 2020-11-28 22:53

    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")
        }
    }
    
    0 讨论(0)
  • 2020-11-28 22:55

    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];
        }
    } 
    
    0 讨论(0)
  • 2020-11-28 22:55

    I have attached demo here please find on this link. TimestampAgo-Demo

    Thanks to n00bprogrammer

    Edit :- I made changes in Sourcetimezone with [NSTimeZone systemTimeZone] because due to static time zone , issue occure in GMT or UTC format. (second goes in minus) and change deprecated Methods.

    0 讨论(0)
提交回复
热议问题