【发布时间】:2011-06-23 15:51:21
【问题描述】:
有没有人知道像下面的例子那样可以将 NSDate 转换为字符串的库或其他东西?
1 hour ago
yesterday
last Thursday
2 days ago
last month
6 months ago
last year
【问题讨论】:
有没有人知道像下面的例子那样可以将 NSDate 转换为字符串的库或其他东西?
1 hour ago
yesterday
last Thursday
2 days ago
last month
6 months ago
last year
【问题讨论】:
NSDateFormatter 将通过在实例上使用 setDoesRelativeDateFormatting: 来完成上面提到的大量工作。从那里,您可以使用日期样式和时间样式控制格式,以根据您的需要对其进行微调。
如果这不能满足您的需求,请查看SORelativeDateTransformer,它是一个 NSValueTransformer 子类,它尝试提供与 SO 上的相对日期相同的行为。
最后,如果您想自己动手或做更多研究,这里是(可能的)关于该主题的原始问题...yes it is question 11。
【讨论】:
NSDateFormatter 上看到过这种方法,我发誓我已经找到它了...
NSDateFormatter 只有少数这些相对字符串。几乎就是“明天”、“今天”和“昨天”。
日期数学很烂。查看 Dave Delong 的年表库 (https://github.com/davedelong/Chronology),或者,对于 iOS 13+,(NS)RelativeDateTimeFormatter
我将以下内容留给后代,但这绝对是错误的事情。我更新的答案在上面。
这是我汇总的一个 NSDate 类别方法,它使用 David 链接的 Stack Overflow 相对性计算以及从其他类似 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;
}
【讨论】:
请勿使用您自己的自定义字符串翻译。 编写您自己的翻译来执行“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];
这将输出类似“今天,晚上 11:10”或“2014 年 7 月 17 日,上午 5:44”的内容。
【讨论】:
看来FormatterKit 中的TTTTimeIntervalFormatter 也可以帮助生成相对时间间隔字符串。
【讨论】:
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];
}
}
【讨论】: