String relativa do NSDate

Alguém sabe de uma biblioteca ou algo que irá converter um NSDate em strings como os exemplos abaixo?

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

O NSDateFormatter fará muito do que foi mencionado acima usando setDoesRelativeDateFormatting: em uma instância. A partir daí, você pode controlar a formatação usando o estilo de data e o estilo de horário para ajustá-lo às suas necessidades.

Se isso não der o que você precisa, verifique o SORelativeDateTransformer , é uma subclass NSValueTransformer que tenta fornecer o mesmo comportamento que você vê com datas relativas em SO.

Finalmente, se você quiser fazer sua própria pesquisa ou fazer mais pesquisas, aqui está a (provável) pergunta original sobre o tópico … sim, é a questão 11 .

Para a posteridade, aqui está um método da categoria NSDate que eu joguei juntos, que usa o cálculo da relatividade do Stack Overflow vinculado por David, bem como outras dicas compiladas de outras perguntas SO semelhantes:

 - (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; } 

NÃO use sua própria tradução de string personalizada. Escrever sua própria tradução que faz algo como “3 segundos atrás” não só tem o problema de precisar ser atualizado constantemente, mas também não se localiza em outros idiomas.

Em vez disso, use o NSDateFormatter da Apple:

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

Isso produzirá algo como “Today, 11:10 PM”, ou “7/17/14, 5:44 AM”.

Parece que TTTTimeIntervalFormatter no FormatterKit também pode ajudar a gerar sequências de intervalos de tempo relativos.

O DateTools é uma estrutura abrangente e impressionante para fazer todos os tipos de funções relacionadas à data. https://github.com/MatthewYork/DateTools

Como categoria NSDate, é mais fácil de usar do que o SORelativeDateTransformer.

No entanto, existe um problema em obter valores diários precisos. (Por exemplo, se hoje é segunda-feira de manhã, o sábado à noite será relatado como “Ontem”; deve ser “Dois dias atrás”)

Isso deve funcionar melhor (usando 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]; } }