【问题标题】:Relative string from NSDate来自 NSDate 的相对字符串
【发布时间】:2011-06-23 15:51:21
【问题描述】:

有没有人知道像下面的例子那样可以将 NSDate 转换为字符串的库或其他东西?

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

【问题讨论】:

    标签: cocoa nsstring nsdate


    【解决方案1】:

    NSDateFormatter 将通过在实例上使用 setDoesRelativeDateFormatting: 来完成上面提到的大量工作。从那里,您可以使用日期样式和时间样式控制格式,以根据您的需要对其进行微调。

    如果这不能满足您的需求,请查看SORelativeDateTransformer,它是一个 NSValueTransformer 子类,它尝试提供与 SO 上的相对日期相同的行为。

    最后,如果您想自己动手或做更多研究,这里是(可能的)关于该主题的原始问题...yes it is question 11

    【讨论】:

    • 有趣,我之前从未NSDateFormatter 上看到过这种方法,我发誓我已经找到它了...
    • 真棒,非常彻底的答案! SORelativeDateTransformer 正是我正在寻找的,并且了解 NSDateFormatter 也很有用。
    • 值得注意的是,NSDateFormatter 只有少数这些相对字符串。几乎就是“明天”、“今天”和“昨天”。
    【解决方案2】:

    日期数学很烂。查看 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】:

      请勿使用您自己的自定义字符串翻译。 编写您自己的翻译来执行“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”的内容。

      【讨论】:

        【解决方案4】:

        看来FormatterKit 中的TTTTimeIntervalFormatter 也可以帮助生成相对时间间隔字符串。

        【讨论】:

          【解决方案5】:

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2023-03-18
            • 1970-01-01
            • 1970-01-01
            • 2012-02-22
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多