Swift DateFormatter 属性未更改

Swift DateFormatter properties not changing

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

首先在终端打开 swift 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 说:

Calling this method is equivalent to, but not necessarily implemented as, setting the dateFormat property to the result of calling the dateFormat(fromTemplate:options:locale:) method, passing no options and the locale property value.

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

Return Value

A localized date format string representing the date format components given in template, arranged appropriately for the locale specified by locale.

The returned string may not contain exactly those components given in template, but may—for example—have locale-specific adjustments applied.

因此 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确实将其更改为"MMMM d, h:mm a",这是iOS认为格式

的最佳“本地化”版本
"'Deliver on' MMMM d 'at' h:mm a 'sharp'"

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