我可以使用 DateComponentsFormatter 来呈现一天中的时间吗?

Can I use a DateComponentsFormatter to render the time of day?

我想以一种简单的方式存储一天中的时间。就我的应用而言,我只关心一天中的特定时间,例如 2:30pm 或 1:10am。

使用 DateComponentsFormatter 我可以非常接近。

import Foundation

let formatter = DateComponentsFormatter()
formatter.unitsStyle = .positional
formatter.allowedUnits = [
    .hour,
    .minute
]
 
// Use the configured formatter to generate the string.
let timeAmount = 9000.0
let outputString = formatter.string(from: timeAmount)
let desiredString = "2:30 pm"import Foundation

let formatter = DateComponentsFormatter()
formatter.unitsStyle = .positional
formatter.allowedUnits = [
    .hour,
    .minute
]
 
// Use the configured formatter to generate the string.
let timeAmount = 9000.0
let outputString = formatter.string(from: timeAmount) // yields "2:30"
let desiredString = "2:30 pm"

现在,格式化程序似乎真的只是在说“2 小时 30 分钟”,所以我可能在这里咆哮错误。 DateComponentsFormatter 支持我的用例吗?

来自documentation

An DateComponentsFormatter object takes quantities of time and formats them as a user-readable string.

重点是 DateComponentsFormatter 时间量 上运行(例如 2 小时 10 分钟),而您想要 及时。这些是非常不同的事情。如果您足够努力,尝试使用 DateComponentsFormatter 生成一天中的某个时间可能会奏效,只是您就是 misusing/abusing 它。

您似乎将一天中的时间存储为自午夜以来的秒数。要将其格式化为 DateComponentsFormatter,您需要对存储的数字进行大量检查和计算:

  • 您需要自己添加 am/pm 字符串。
  • 任何少于 1 小时的时间都需要加上 12 小时。
  • 存储时间大于12小时需要减去12小时
  • 您可能还需要考虑我遗漏的更多信息

此外,am/pm 不可本地化。世界上也可能有一些文化使用不同的格式来显示一天中的时间量(我不知道!),这将导致这种方法完全失效。


DateFormatter 应该用于格式化一天中的时间。只需将存储的时间添加到 UNIX 纪元时间(或任何其他午夜)并使用 UTC 时区进行格式化:

let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.dateFormat = "hh:mm a"
// or you can replace the above 2 lines with something more localised:
// formatter.timeStyle = .short
formatter.timeZone = TimeZone(identifier: "UTC")
let output = formatter.string(from: Date(timeIntervalSince1970: storedTime))

DateComponentsFormatter表示两个日期之间的时间间隔。 DateFormatter 用于格式化日期或时间。使用 DateFormatter.

如果您打算在 UI 中显示时间,请使用 DateFormatter,但

  • 不要使用dateFormat,而是使用timeStyle
  • 不要覆盖 locale
  • 不设置timeZone;

例如在 UI:

中显示当前时间
let date = Date()
let formatter = DateFormatter()
formatter.timeStyle = .short
let string = formatter.string(from: date)

顺便说一句,这将根据用户的喜好格式化时间字符串(例如,AM/PM 对我们中的一些人来说,但在其他地区,用户可能更喜欢 24 小时制表示)。在 UI 中显示信息时,我们应该始终尊重用户的偏好。


如果您要将 9,000 秒转换为 2:30am:

let startOfDay = Calendar.current.startOfDay(for: Date())
let date = startOfDay.addingTimeInterval(9000)

let formatter = DateFormatter()
formatter.timeStyle = .short
let string = formatter.string(from: date)    // 2:30 AM

显然,如果您碰巧在夏令时转换或退出夏令时的日期,您的结果可能会有所不同。