NSDateFormatter:使用具有相对格式的自定义格式

Posted

技术标签:

【中文标题】NSDateFormatter:使用具有相对格式的自定义格式【英文标题】:NSDateFormatter: Using custom format with relative formatting 【发布时间】:2015-08-21 15:20:48 【问题描述】:

我正在尝试将NSDates 格式化为一种在适用时使用相对格式而在不适用时使用星期几的格式:“今天”、“明天”、“星期日”、“星期一”……

问题是,NSDateFormatterdoesRelativeFormatting 仅在使用 dateStyle 时有效,而在 dateFormat 时无效。 (基本上,我需要 dateFormat = "EEEE" 的功能来维持后天的所有日子。)

目前,我正在使用以下代码:

let dateFormatter = NSDateFormatter()
dateFormatter.timeStyle = .NoStyle
dateFormatter.dateStyle = .FullStyle
dateFormatter.doesRelativeDateFormatting = true

let dateString = dateFormatter.stringFromDate(theDate)
return dateString.componentsSeparatedByString(" ")[0]

这恰好在我的特定语言环境中工作,NSDateFormatterStyle.FullStyle 输出类似“2015 年 8 月 23 日星期日”的内容,但显然这不是一个好的或通用的解决方案。

我找到的最接近的东西是 this question,但对于我的用例来说,它似乎不必要地复杂,如果可能的话,我想要更优雅的东西。

谢谢!

【问题讨论】:

【参考方案1】:

我会使用 3 个日期格式化程序:

    dateStyle = .FullStyledoesRelativeDateFormatting = true dateStyle = .FullStyledoesRelativeDateFormatting = false dateFormat = "EEEE"doesRelativeDateFormatting = false

获取 1 和 2 的格式化字符串。如果它们不同,则使用来自 1 的字符串。如果它们相同,则获取并使用来自 3 的字符串。

这应该适用于所有语言环境。出于性能原因,请确保保留所有 3 个格式化程序,而不是每次都重新创建它们。

【讨论】:

【参考方案2】:

这是DateFormatter() 的有效扩展:

import Foundation

extension DateFormatter 

    /*
     * Returns a string representation of a given date in relative format.
     * If the current local doesn't offer a relative format for the given date,
     * then then a given format is applied.
     *
     * - parameter _date: The date to be formatted
     * - parameter _format: The format to be applied to non-relative dates
     *
     * - returns: A string representing a formatted version of a given date
     */

    func relativeStringWithFormat(from: Date, format: String) -> String? 

        // Create date formatters
        let _formatRelative = DateFormatter()
            _formatRelative.dateStyle = .full
            _formatRelative.doesRelativeDateFormatting = true
            _formatRelative.timeStyle = .none

        let _formatFull = DateFormatter()
            _formatFull.dateStyle = .full
            _formatFull.doesRelativeDateFormatting = false
            _formatFull.timeStyle = .none

        let _formatCustom = DateFormatter()
            _formatCustom.dateFormat = format
            _formatCustom.doesRelativeDateFormatting = false

        // Get dates in available formats
        let _dateRelative = _formatRelative.string(from: from)
        let _dateFull = _formatFull.string(from: from)
        let _dateCustom = _formatCustom.string(from: from)

        // Return appropriatly formatted date/string
        if _dateRelative != _dateFull 

            return _dateRelative

         else 

            return _dateCustom
        
       

【讨论】:

【参考方案3】:

@eranschau 的回答不包括本地化日期,因此我添加了一个可选参数来设置 Locale,并且还修复了一个错误,当比较不起作用时,因为在某些情况下出现意外的大写。

extension DateFormatter

    /**
     * Returns a string representation of a given date in relative format.
     * If the current local doesn't offer a relative format for the given date,
     * then then a given format is applied.
     *
     * - parameter date: The date to be formatted
     * - parameter format: The format to be applied to non-relative dates
     * - parameter locale: The locale to be used for date formatting
     *
     * - returns: A string representing a formatted version of a given date
     */

    func relativeStringWithFormat(from: Date, format: String, locale: Locale? = nil) -> String
    
        // Create date formatters
        let _formatRelative = DateFormatter()
            _formatRelative.dateStyle = .full
            _formatRelative.doesRelativeDateFormatting = true
            _formatRelative.timeStyle = .none
            _formatRelative.locale = locale ?? Locale.current

        let _formatFull = DateFormatter()
            _formatFull.dateStyle = .full
            _formatFull.doesRelativeDateFormatting = false
            _formatFull.timeStyle = .none
            _formatFull.locale = locale ?? Locale.current

        let _formatCustom = DateFormatter()
            _formatCustom.dateFormat = DateFormatter.dateFormat(fromTemplate: format, options: 0, locale: locale ?? Locale.current)

        // Get dates in available formats
        let _dateRelative = _formatRelative.string(from: from)
        let _dateFull = _formatFull.string(from: from)
        let _dateCustom = _formatCustom.string(from: from)

        // Return appropriatly formatted date/string
        if _dateRelative.caseInsensitiveCompare(_dateFull) != .orderedSame 
            return _dateRelative
         else 
            return _dateCustom
        
    

【讨论】:

以上是关于NSDateFormatter:使用具有相对格式的自定义格式的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 nsdateformatter 将 nsdate 转换为另一种格式

使用 NSDateFormatter 快速格式化日期

使用 NSDateFormatter 格式化月份和年份返回无效日期

NSDateFormatter dateFromString 格式字符串问题

将事件添加到日历时,NSDateFormatter 未正确格式化日期

使用 setDoesRelativeDateFormatting: YES 和 setDateFormat: 与 NSDateFormatter