使用 setDoesRelativeDateFormatting: YES 和 setDateFormat: 与 NSDateFormatter

Posted

技术标签:

【中文标题】使用 setDoesRelativeDateFormatting: YES 和 setDateFormat: 与 NSDateFormatter【英文标题】:Using setDoesRelativeDateFormatting: YES and setDateFormat: with NSDateFormatter 【发布时间】:2013-12-02 15:07:46 【问题描述】:

当当前语言支持时,NSDateFormatter 对生成诸如“今天”、“明天”、“昨天”等相对日期有很好的支持。一个很大的优势是所有这些都已经为您本地化了——您不需要翻译字符串。

您可以通过以下方式打开此功能:

[dateFormatter setDoesRelativeDateFormatting: YES];

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

[dateFormatter setDateStyle: NSDateFormatterShortStyle];

如果您将日期格式化程序设置为使用自定义格式,如下所示:

[dateFormatter setDateStyle: @"EEEE"];

然后当你打电话时:

[dateFormatter stringFromDate: date];

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

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

【问题讨论】:

【参考方案1】:

我在 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的信息。

一个限制……

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

【讨论】:

干得好。我建议的一种解决方法是使用dispatch_once 创建静态格式化程序 改为使用 dispatch_once。谢谢@GreatWiz。【参考方案2】:

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

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)
    

【讨论】:

以上是关于使用 setDoesRelativeDateFormatting: YES 和 setDateFormat: 与 NSDateFormatter的主要内容,如果未能解决你的问题,请参考以下文章

在使用加载数据流步骤的猪中,使用(使用 PigStorage)和不使用它有啥区别?

今目标使用教程 今目标任务使用篇

Qt静态编译时使用OpenSSL有三种方式(不使用,动态使用,静态使用,默认是动态使用)

MySQL db 在按日期排序时使用“使用位置;使用临时;使用文件排序”

使用“使用严格”作为“使用强”的备份

Kettle java脚本组件的使用说明(简单使用升级使用)