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

前端 未结 16 2048
天命终不由人
天命终不由人 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:34

    check NSDate-TimeAgo, it also supports multiple languages.

    0 讨论(0)
  • 2020-11-28 22:34

    Here is code I created for my use:

    + (NSString*) getTimestampForDate:(NSDate*)date {
    
        NSDate* sourceDate = date;
    
        // Timezone Offset compensation (optional, if your target users are limited to a single time zone.)
    
        NSTimeZone* sourceTimeZone = [NSTimeZone timeZoneWithName:@"America/New_York"];
        NSTimeZone* destinationTimeZone = [NSTimeZone systemTimeZone];
    
        NSInteger sourceGMTOffset = [sourceTimeZone secondsFromGMTForDate:sourceDate];
        NSInteger destinationGMTOffset = [destinationTimeZone secondsFromGMTForDate:sourceDate];
    
        NSTimeInterval interval = destinationGMTOffset - sourceGMTOffset;
    
        NSDate* destinationDate = [[NSDate alloc] initWithTimeInterval:interval sinceDate:sourceDate];
    
        // Timestamp calculation (based on compensation)
    
        NSCalendar* currentCalendar = [NSCalendar currentCalendar];
        NSCalendarUnit unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit |  NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit;
    
        NSDateComponents *differenceComponents = [currentCalendar components:unitFlags fromDate:destinationDate toDate:[NSDate date] options:0];//Use `date` instead of `destinationDate` if you are not using Timezone offset correction
    
        NSInteger yearDifference = [differenceComponents year];
        NSInteger monthDifference = [differenceComponents month];
        NSInteger dayDifference = [differenceComponents day];
        NSInteger hourDifference = [differenceComponents hour];
        NSInteger minuteDifference = [differenceComponents minute];
    
        NSString* timestamp;
    
        if (yearDifference == 0
            && monthDifference == 0
            && dayDifference == 0
            && hourDifference == 0
            && minuteDifference <= 2) {
    
            //"Just Now"
    
            timestamp = @"Just Now";
    
        } else if (yearDifference == 0
                   && monthDifference == 0
                   && dayDifference == 0
                   && hourDifference == 0
                   && minuteDifference < 60) {
    
            //"13 minutes ago"
    
            timestamp = [NSString stringWithFormat:@"%ld minutes ago", (long)minuteDifference];
    
        } else if (yearDifference == 0
                   && monthDifference == 0
                   && dayDifference == 0
                   && hourDifference == 1) {
    
            //"1 hour ago" EXACT
    
            timestamp = @"1 hour ago";
    
        } else if (yearDifference == 0
                   && monthDifference == 0
                   && dayDifference == 0
                   && hourDifference < 24) {
    
            timestamp = [NSString stringWithFormat:@"%ld hours ago", (long)hourDifference];
    
        } else {
    
            NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
            [formatter setLocale:[NSLocale currentLocale]];
    
            NSString* strDate, *strDate2 = @"";
    
            if (yearDifference == 0
                && monthDifference == 0
                && dayDifference == 1) {
    
                //"Yesterday at 10:23 AM", "Yesterday at 5:08 PM"
    
                [formatter setDateFormat:@"hh:mm a"];
                strDate = [formatter stringFromDate:date];
    
                timestamp = [NSString stringWithFormat:@"Yesterday at %@", strDate];
    
            } else if (yearDifference == 0
                       && monthDifference == 0
                       && dayDifference < 7) {
    
                //"Tuesday at 7:13 PM"
    
                [formatter setDateFormat:@"EEEE"];
                strDate = [formatter stringFromDate:date];
                [formatter setDateFormat:@"hh:mm a"];
                strDate2 = [formatter stringFromDate:date];
    
                timestamp = [NSString stringWithFormat:@"%@ at %@", strDate, strDate2];
    
            } else if (yearDifference == 0) {
    
                //"July 4 at 7:36 AM"
    
                [formatter setDateFormat:@"MMMM d"];
                strDate = [formatter stringFromDate:date];
                [formatter setDateFormat:@"hh:mm a"];
                strDate2 = [formatter stringFromDate:date];
    
                timestamp = [NSString stringWithFormat:@"%@ at %@", strDate, strDate2];
    
            } else {
    
                //"March 24 2010 at 4:50 AM"
    
                [formatter setDateFormat:@"d MMMM yyyy"];
                strDate = [formatter stringFromDate:date];
                [formatter setDateFormat:@"hh:mm a"];
                strDate2 = [formatter stringFromDate:date];
    
                timestamp = [NSString stringWithFormat:@"%@ at %@", strDate, strDate2];
            }
        }
    
        return timestamp;
    }
    
    0 讨论(0)
  • 2020-11-28 22:35

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

    To format the given "sourceDate" as "5:56 pm" for today, "yesterday" for any time yesterday, "January 16" for any day in the same year and "January 16, 2014". I am posting my own method.

    sourceDate = //some date that you need to take into consideration
    
    
     NSDateComponents *components = [[NSCalendar currentCalendar] components:NSCalendarUnitMinute | NSCalendarUnitHour | NSCalendarUnitDay | NSCalendarUnitMonth | NSCalendarUnitYear fromDate:[NSDate date]];
        NSDateComponents *sourceDateComponents = [[NSCalendar currentCalendar] components:NSCalendarUnitMinute | NSCalendarUnitHour | NSCalendarUnitDay | NSCalendarUnitMonth | NSCalendarUnitYear fromDate: sourceDate];
    
        NSString* timestamp;
    
        NSDateFormatter *formatSourceDate   =   [NSDateFormatter new];
        [formatSourceDate setAMSymbol:@"AM"];
        [formatSourceDate setPMSymbol:@"PM"];
    
        //same day - time in h:mm am/pm
        if (components.day == sourceDateComponents.day) {
            NSLogInfo(@"time");
            [formatSourceDate setDateFormat:@"h:mm a"];
            timestamp = [NSString stringWithFormat:@"%@",[formatSourceDate stringFromDate:date]];
            return timestamp;
        }
        else if (components.day - sourceDateComponents.day == 1) {
            //yesterday
            timestamp = NSLocalizedString(@"Yesterday", nil);
            return timestamp;
        }
        if (components.year == sourceDateComponents.year) {
            //september 29, 5:56 pm
            [formatSourceDate setDateFormat:@"MMMM d"];
            timestamp = [NSString stringWithFormat:@"%@",[formatSourceDate stringFromDate:date]];
            return timestamp;
        }
        [formatSourceDate setDateFormat:@"MMMM d year"];
        timestamp = [NSString stringWithFormat:@"%@",[formatSourceDate stringFromDate:date]];
        return timestamp;
    
        NSLogInfo(@"Timestamp : %@",timestamp);
    
    0 讨论(0)
  • 2020-11-28 22:37

    Please note that as of iOS 13 there is now RelativeDateTimeFormatter which does it all most of it for you! WWDC 2019 video here.

    let formatter = RelativeDateTimeFormatter()
    let dateString = formatter.localizedString(for: aDate, relativeTo: now)
    
    // en_US: "2 weeks ago"
    // es_ES: "hace 2 semanas"
    // zh_TW: "2 週前"
    

    I've left my previous answer below for posterity. Cheers!

    ⚠️ You will want to read through the previous answer for some key tips to avoid certain bugs. Hint: use the end of the current day's date/time for the relative date when comparing dates that are not today!


    Here's my answer (in Swift 3!) and why it's better.

    Answer:

    func datePhraseRelativeToToday(from date: Date) -> String {
    
        // Don't use the current date/time. Use the end of the current day 
        // (technically 0h00 the next day). Apple's calculation of 
        // doesRelativeDateFormatting niavely depends on this start date.
        guard let todayEnd = dateEndOfToday() else {
            return ""
        }
    
        let calendar = Calendar.autoupdatingCurrent
    
        let units = Set([Calendar.Component.year,
                     Calendar.Component.month,
                     Calendar.Component.weekOfMonth,
                     Calendar.Component.day])
    
        let difference = calendar.dateComponents(units, from: date, to: todayEnd)
    
        guard let year = difference.year,
            let month = difference.month,
            let week = difference.weekOfMonth,
            let day = difference.day else {
                return ""
        }
    
        let timeAgo = NSLocalizedString("%@ ago", comment: "x days ago")
    
        let dateFormatter: DateFormatter = {
            let formatter = DateFormatter()
            formatter.locale = Locale.autoupdatingCurrent
            formatter.dateStyle = .medium
            formatter.doesRelativeDateFormatting = true
            return formatter
        }()
    
        if year > 0 {
            // sample output: "Jan 23, 2014"
            return dateFormatter.string(from: date)
        } else if month > 0 {
            let formatter = DateComponentsFormatter()
            formatter.unitsStyle = .brief // sample output: "1mth"
            formatter.allowedUnits = .month
            guard let timePhrase = formatter.string(from: difference) else {
                return ""
            }
            return String(format: timeAgo, timePhrase)
        } else if week > 0 {
            let formatter = DateComponentsFormatter()
            formatter.unitsStyle = .brief; // sample output: "2wks"
            formatter.allowedUnits = .weekOfMonth
            guard let timePhrase = formatter.string(from: difference) else {
                return ""
            }
            return String(format: timeAgo, timePhrase)
        } else if day > 1 {
                let formatter = DateComponentsFormatter()
                formatter.unitsStyle = .abbreviated; // sample output: "3d"
                formatter.allowedUnits = .day
                guard let timePhrase = formatter.string(from: difference) else {
                    return ""
                }
                return String(format: timeAgo, timePhrase)
        } else {
            // sample output: "Yesterday" or "Today"
            return dateFormatter.string(from: date)
        }
    }
    
    func dateEndOfToday() -> Date? {
        let calendar = Calendar.autoupdatingCurrent
        let now = Date()
        let todayStart = calendar.startOfDay(for: now)
        var components = DateComponents()
        components.day = 1
        let todayEnd = calendar.date(byAdding: components, to: todayStart)
        return todayEnd
    }
    

    Remember to reuse your formatters to avoid any performance hit! Hint: extensions on DateFormatter and DateComponentsFormatter are good ideas.

    Why it's better:

    • Utilizes DateFormatter's "Yesterday" and "Today". This is already translated by Apple, which saves you work!
    • Uses DateComponentsFormatter's already translated "1 week" string. (Again less work for you, courtesy of Apple.) All you have to do is translate the "%@ ago" string.
    0 讨论(0)
  • 2020-11-28 22:41
    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!)
    
    0 讨论(0)
提交回复
热议问题