使用setDoesRelativeDateFormatting:YES和setDateFormat:with NSDateFormatter

时间:2013-12-02 15:07:47

标签: ios cocoa-touch nsdate nsdateformatter nscalendar

NSDateFormatter非常支持生成相关日期,例如“今天”,“明天”,“昨天”,当前语言支持这些日期。一个很大的优点是所有这些都已经为您本地化了 - 您不需要翻译字符串。

您可以使用以下方式启用此功能:

[dateFormatter setDoesRelativeDateFormatting: YES];

缺点是,这似乎只适用于使用其中一种预定义格式的实例,例如:

[dateFormatter setDateStyle: NSDateFormatterShortStyle];

如果您设置日期格式化程序以使用自定义格式,请执行以下操作:

[dateFormatter setDateStyle: @"EEEE"];

然后当你打电话:

[dateFormatter stringFromDate: date];

...你只会得到一个空字符串。

我希望能够在可能的情况下获得相关字符串,并在不存在时使用我自己的自定义格式。

2 个答案:

答案 0 :(得分:9)

我在NSDateFormatter上设置了一个类别,为此提供了一种解决方法。代码后面有一个解释。

在NSDateFormatter + RelativeDateFormat.h中:

@interface NSDateFormatter (RelativeDateFormat)
-(NSString*) relativeStringFromDateIfPossible:(NSDate *)date;
@end

在NSDateFormatter + RelativeDateFormat.m中:

@implementation NSDateFormatter (RelativeDateFormat)
-(NSString*) relativeStringFromDateIfPossible:(NSDate *)date
{
  static NSDateFormatter *relativeFormatter;
  static NSDateFormatter *absoluteFormatter;

  static dispatch_once_t onceToken;
  dispatch_once(&onceToken, ^{
    const NSDateFormatterStyle arbitraryStyle = NSDateFormatterShortStyle;

    relativeFormatter = [[NSDateFormatter alloc] init];
    [relativeFormatter setDateStyle: arbitraryStyle];
    [relativeFormatter setTimeStyle: NSDateFormatterNoStyle];
    [relativeFormatter setDoesRelativeDateFormatting: YES];

    absoluteFormatter = [[NSDateFormatter alloc] init];
    [absoluteFormatter setDateStyle: arbitraryStyle];
    [absoluteFormatter setTimeStyle: NSDateFormatterNoStyle];
    [absoluteFormatter setDoesRelativeDateFormatting: NO];
  });

  NSLocale *const locale = [self locale];
  if([relativeFormatter locale] != locale)
  {
    [relativeFormatter setLocale: locale];
    [absoluteFormatter setLocale: locale];
  }

  NSCalendar *const calendar = [self calendar];
  if([relativeFormatter calendar] != calendar)
  {
    [relativeFormatter setCalendar: calendar];
    [absoluteFormatter setCalendar: calendar];
  }

  NSString *const maybeRelativeDateString = [relativeFormatter stringFromDate: date];
  const BOOL isRelativeDateString = ![maybeRelativeDateString isEqualToString: [absoluteFormatter stringFromDate: date]];

  if(isRelativeDateString)
  {
    return maybeRelativeDateString;
  }
  else
  {
    return [self stringFromDate: date];
  }
}
@end

这是如何工作的?

它使用(任意)标准格式维护两个日期格式化程序。它们的格式相同,除了一个将提供相对日期字符串而另一个不提供。

通过使用两种格式化程序格式化给定日期,可以查看相对日期格式化程序是否给出特殊的相对日期。当两个格式化程序提供不同的结果时,会有一个特殊的相对日期。

  • 如果特殊的相对日期字符串,则返回该特殊相对日期字符串。
  • 如果不是特殊的相对日期字符串,则原始格式化程序将用作后备,并使用您在其上定义的格式设置。

您可以找到有关dispatch_once here的更多信息。

限制......

该实现不处理您可能放入格式字符串的时间组件。当相对日期字符串可用时,将忽略您的格式标记,并获得相对日期字符串。

答案 1 :(得分:1)

我认为@Benjohn代码的快速版本对其他人有用

extension NSDateFormatter {    
   @nonobjc static let relativeFormatter : NSDateFormatter = {
        let formatter = NSDateFormatter()
        formatter.dateStyle = .MediumStyle
        formatter.timeStyle = .NoStyle
        formatter.doesRelativeDateFormatting = true
        return formatter
    }()

    @nonobjc static let absoluteFormatter : NSDateFormatter = {
        let formatter = NSDateFormatter()
        formatter.dateStyle = .MediumStyle
        formatter.timeStyle = .NoStyle
        formatter.doesRelativeDateFormatting = false
        return formatter
    }()

    func relativeStringFromDateIfPossible(date:NSDate) -> String
    {    
        if NSDateFormatter.relativeFormatter.locale != locale {
            NSDateFormatter.relativeFormatter.locale = locale
            NSDateFormatter.absoluteFormatter.locale = locale
        }

        if NSDateFormatter.absoluteFormatter.calendar != calendar {
            NSDateFormatter.relativeFormatter.calendar = calendar
            NSDateFormatter.absoluteFormatter.calendar = calendar
        }

        let maybeRelativeString = NSDateFormatter.relativeFormatter.stringFromDate(date)
        let absoluteString = NSDateFormatter.absoluteFormatter.stringFromDate(date)

        return (maybeRelativeString != absoluteString ) ? maybeRelativeString : stringFromDate(date)
    }
}