Swift DateFormatter属性未更改 返回值

问题描述

这是一个非常令人困惑的情况,我在NSDateFormatter上阅读了许多文档,但似乎无法设置本地化的日期格式模板。使用dateFormat属性有效,但是使用setLocalizedDateFormatFromTemplate无效,基本上我在swift 5.3中具有以下代码

首先在终端中打开快速REPL并输入以下内容

import Foundation // takes a few secs

var ftt = DateFormatter()
ftt.locale = Locale(identifier: "en_US")
ftt.setLocalizedDateFormatFromTemplate("'Deliver on' MMMM d 'at' h:mm a 'sharp'")

运行后,我得到以下输出

ftt: DateFormatter = {
  baseNSFormatter@0 = {
    baseNSObject@0 = {
      isa = NSDateFormatter
    }
  }
  _attributes = 3 key/value pairs {
    [0] = {
      key = "locale"
      value =
    }
    [1] = {
      key = "formatterBehavior"
      value = Int64(1040)
    }
    [2] = {
      key = "dateFormat"
      value = "MMMM d,h:mm a"
    }
  }
  _formatter = {}
  _counter = 0
  _cacheGeneration = 3
  _behavior = 0
}

输出中可以看到,localedateFormat都没有被存储。格式化日期将导致以下结果:

 14> ftt.string(from: Date())
$R1: String = "October 21,8:19 PM"

我确保locale identifier是正确的,我遵循了有关DateFormatter的一些教程,例如:

并检查setLocalizedDateFormatFromTemplateApple's documentation用法,并确保在设置locale调用它。

如果我直接分配dateFormat属性,我将得到期望的结果:

17> ftt.dateFormat = "'Deliver on' MMMM d 'at' h:mm a 'sharp'"
ftt: DateFormatter = {
  baseNSFormatter@0 = {
    baseNSObject@0 = {
      isa = NSDateFormatter
    }
  }
  _attributes = 3 key/value pairs {
    [0] = {
      key = "locale"
      value =
    }
    [1] = {
      key = "formatterBehavior"
      value = Int64(1040)
    }
    [2] = {
      key = "dateFormat"
      value = "\'Deliver on\' MMMM d \'at\' h:mm a \'sharp\'"
    }
  }
  _formatter =
  _counter = 0
  _cacheGeneration = 2
  _behavior = 0
}

18> ftt.string(from: Date())
$R2: String = "Deliver on October 21 at 8:25 PM sharp"

这是怎么回事?!我缺少明显的东西吗?我想了解这种行为。

谢谢!

解决方法

这里的问题是模板中日期组件的顺序没有区别。您只是假设要传递组件,并且如何显示它们取决于语言环境。

let ftt = DateFormatter()
ftt.locale = Locale(identifier: "en_US")
ftt.setLocalizedDateFormatFromTemplate("dMMMMhm")
ftt.dateFormat  // "MMMM d,h:mm a"
ftt.string(from: Date())  // "October 22,12:45 AM"

ftt.locale = Locale(identifier: "pt_BR")
ftt.setLocalizedDateFormatFromTemplate("MMMMdysmH")
ftt.dateFormat  // "d 'de' MMMM 'de' y HH:mm:ss"
ftt.string(from: Date())  // "22 de outubro de 2020 00:45:36"
,

我认为您误解了setLocalizedDateFormatFromTemplate的功能。 Its documentation说:

调用此方法等效于(但不一定实现为)将dateFormat属性设置为调用dateFormat(fromTemplate:options:locale:)方法的结果,不传递任何选项和语言环境属性值。

现在dateFormat(fromTemplate:options:locale:)会做什么?让我们看看:

返回值

本地化的日期格式字符串,代表模板中给定的日期格式组件,并根据语言环境指定的语言环境进行适当排列。

返回的字符串可能不完全包含模板中给定的那些组件,但是(例如)可能已应用了特定于语言环境的调整。

因此,dateFormat(fromTemplate:options:locale:)尝试将模板本地化到指定的语言环境。如果未指定语言环境,则使用Locale.current。例如:

// this produces "MM/dd/yyyy"
DateFormatter.dateFormat(fromTemplate: "yyyy dd MM",options: 0,locale: Locale(identifier: "en-US"))

这说明了为什么它删除格式中所有带引号的字符串的原因,因为本地化引擎无法识别您的带引号的字符串,因此要生成日期格式的“本地化”版本,最好的办法是删除它们。就其而言,引用的字符串可以使用其他语言!

所以并不是setLocalizedDateFormatFromTemplate并没有改变dateFormat。它 did 将其更改为"MMMM d,h:mm a",这是iOS认为是格式最好的“本地化”版本

"'Deliver on' MMMM d 'at' h:mm a 'sharp'"

在这种情况下,您应该直接设置dateFormat,而不要设置setLocalizedDateFormatFromTemplate,因为您不希望使用本地化的日期格式。