Относительная строка из NSDate - PullRequest
13 голосов
/ 08 февраля 2011

Кто-нибудь знает библиотеку или что-то, что преобразует NSDate в строки, как в примерах ниже?

1 hour ago
yesterday
last Thursday
2 days ago
last month
6 months ago
last year

Ответы [ 5 ]

17 голосов
/ 08 февраля 2011

NSDateFormatter сделает многое из того, что упомянуто выше, используя setDoesRelativeDateFormatting: в экземпляре.Оттуда вы можете управлять форматированием, используя стиль даты и стиль времени, чтобы точно настроить его в соответствии с вашими потребностями.

Если это не дает вам того, что вам нужно, посмотрите SORelativeDateTransformer , это подкласс NSValueTransformer, который пытается обеспечить то же поведение, которое вы видите с относительными датами в SO.

Наконец, если вы хотите прокрутить свое собственное или провести дополнительные исследования, вот (вероятно) оригинальный вопрос отема ... да, это вопрос 11 .

16 голосов
/ 12 октября 2011

Для потомков, вот метод категории NSDate, который я создал вместе, который использует расчет относительности Переполнения стека, связанный Дэвидом, а также другие советы, придуманные из других подобных вопросов SO:

- (NSString *)relativeDateString
{
    const int SECOND = 1;
    const int MINUTE = 60 * SECOND;
    const int HOUR = 60 * MINUTE;
    const int DAY = 24 * HOUR;
    const int MONTH = 30 * DAY;

    NSDate *now = [NSDate date];
    NSTimeInterval delta = [self timeIntervalSinceDate:now] * -1.0;

    NSCalendar *calendar = [NSCalendar currentCalendar];
    NSUInteger units = (NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit);
    NSDateComponents *components = [calendar components:units fromDate:self toDate:now options:0];

    NSString *relativeString;

    if (delta < 0) {
        relativeString = @"!n the future!";

    } else if (delta < 1 * MINUTE) {
        relativeString = (components.second == 1) ? @"One second ago" : [NSString stringWithFormat:@"%d seconds ago",components.second];

    } else if (delta < 2 * MINUTE) {
        relativeString =  @"a minute ago";

    } else if (delta < 45 * MINUTE) {
        relativeString = [NSString stringWithFormat:@"%d minutes ago",components.minute];

    } else if (delta < 90 * MINUTE) {
        relativeString = @"an hour ago";

    } else if (delta < 24 * HOUR) {
        relativeString = [NSString stringWithFormat:@"%d hours ago",components.hour];

    } else if (delta < 48 * HOUR) {
        relativeString = @"yesterday";

    } else if (delta < 30 * DAY) {
        relativeString = [NSString stringWithFormat:@"%d days ago",components.day];

    } else if (delta < 12 * MONTH) {
        relativeString = (components.month <= 1) ? @"one month ago" : [NSString stringWithFormat:@"%d months ago",components.month];

    } else {
        relativeString = (components.year <= 1) ? @"one year ago" : [NSString stringWithFormat:@"%d years ago",components.year];

    }

    return relativeString;
}
5 голосов
/ 23 июля 2014

НЕ ИСПОЛЬЗУЙТЕ свой собственный пользовательский перевод строк. При написании собственного перевода, который выполняет что-то вроде «3 секунды назад», возникает проблема не только необходимости постоянного обновления, но и локализация вДругие языки.

Вместо этого используйте встроенный в Apple NSDateFormatter:

NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.doesRelativeDateFormatting = YES;
formatter.locale = [NSLocale currentLocale];
formatter.dateStyle = NSDateFormatterShortStyle;
formatter.timeStyle = NSDateFormatterShortStyle;
NSString *timeString = [formatter stringFromDate:self.date];

Это выдаст что-то вроде «Сегодня, 23:10» или «17.07.14, 5:44»,

3 голосов
/ 09 августа 2012

Похоже, что TTTTimeIntervalFormatter в FormatterKit также может помочь с генерацией строк относительного временного интервала.

1 голос
/ 26 мая 2014

DateTools - это потрясающая комплексная среда для выполнения всевозможных функций, связанных с датами. https://github.com/MatthewYork/DateTools

В качестве категории NSDate его проще использовать, чем SORelativeDateTransformer.

Однако существует проблема с получением точных значений дня. (Например, если сегодня утро понедельника, субботний вечер будет обозначен как «вчера»; должно быть «два дня назад»)

Это должно работать лучше (используя DateTools):

- (NSString *)relativeDateStringForDate:(NSDate *)d
{
    if ([d daysAgo] < 1) {
        //Return as is
        return [d timeAgoSinceNow];
    }
    else { //More than 24 hours ago. The default implementation will underreport (round down) day durations.
           //We should modify the reference date we're using to midnight on the current day.

        NSDate *date = [NSDate date];
        date = [date dateByAddingDays:1];
        NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar];
        NSUInteger preservedComponents = (NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit);
        NSDate *todayAtMidnight = [calendar dateFromComponents:[calendar components:preservedComponents fromDate:date]];

        return [d timeAgoSinceDate:todayAtMidnight];

    }
}
...