使用 DateFormatter 产生的结果会偏离一天
Using DateFormatter produces a result which is off by a day
使用 DateFormatter 产生的结果偏离一天(实际上是 12 小时)。使用以下代码始终如一地生成显示为前一天的日期。一段时间以来,我一直在许多应用程序中使用它,但终于抽出时间来深入研究它。
extension Date
{
func display() -> String
{
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MMMM dd, yyyy"
print(dateFormatter.locale)
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
let txt = dateFormatter.string(from: self)
print(txt)
return txt
}
}
与此相关的其他问题建议更改语言环境,因此为此添加了代码,但我检查了语言环境和实际日期。如果我在日期上加 8 小时,我会得到正确的显示结果,但加的时间少于 8 小时则没有任何效果。正在从联系人应用程序的生日字段中检索一些日期,这会产生具有一天中的时间 00:00:00 UTC 的日期。看来我需要将日期转换为当地时间?设备上的时区设置为本地时区(太平洋)。这看起来还不错,但是从日期选择器中检索到的日期不是 UTC 时间,而是当地时间。自从使用日历 class 并尝试提取 .timezone 组件后,我一直无法弄清楚如何判断日期所在的时区 "NSCalendarUnitTimeZone cannot be gotten by this method"。关于如何创建适用于所有情况的通用日期格式化程序有什么建议吗?
一些观察:
如果您的 Date
对象处于 UTC 时区,则也将格式化程序的 timeZone
设置为 TimeZone(secondsFromGMT: 0)
。
如果您要在 UI 中显示 Date
对象的字符串表示形式,您 不会 想要使用locale
个 en_US_POSIX
。你想在设备的默认位置显示它(即,根本不要更改格式化程序的 locale
)。您仅在处理内部使用的 ISO 8601 和 RFC 3339 日期字符串时使用 en_US_POSIX
,例如,用于与 Web 服务交换日期字符串)。
最后,我不会指定 dateFormat
字符串,因为并非所有用户都希望日期采用 MMMM dd, yyyy
格式。例如,英国用户希望它采用 d MMMM yyyy
格式。在 UI 中显示日期时,请改为指定 dateStyle
。或者,如果这些样式中的 none 有效,请继续并指定 dateFormat
,但使用 setLocalizedDateFormatFromTemplate(_:)
而不是固定字符串进行设置。
因此,为了您的目的,您可以这样做:
extension Date {
var dateString: String {
let formatter = DateFormatter()
formatter.dateStyle = .long
formatter.timeZone = TimeZone(secondsFromGMT: 0)
return formatter.string(from: self)
}
}
或者,如果您经常调用它,您可能希望重用格式化程序:
extension Date {
private static let formatterForDateString: DateFormatter = {
let formatter = DateFormatter()
formatter.dateStyle = .long
formatter.timeZone = TimeZone(secondsFromGMT: 0)
return formatter
}()
var dateString: String {
return Date.formatterForDateString.string(from: self)
}
}
使用timeZone属性,获取准确的日期,如下图:
formatter.timeZone = TimeZone(secondsFromGMT: 0)
它将解决您的问题!
使用 DateFormatter 产生的结果偏离一天(实际上是 12 小时)。使用以下代码始终如一地生成显示为前一天的日期。一段时间以来,我一直在许多应用程序中使用它,但终于抽出时间来深入研究它。
extension Date
{
func display() -> String
{
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MMMM dd, yyyy"
print(dateFormatter.locale)
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
let txt = dateFormatter.string(from: self)
print(txt)
return txt
}
}
与此相关的其他问题建议更改语言环境,因此为此添加了代码,但我检查了语言环境和实际日期。如果我在日期上加 8 小时,我会得到正确的显示结果,但加的时间少于 8 小时则没有任何效果。正在从联系人应用程序的生日字段中检索一些日期,这会产生具有一天中的时间 00:00:00 UTC 的日期。看来我需要将日期转换为当地时间?设备上的时区设置为本地时区(太平洋)。这看起来还不错,但是从日期选择器中检索到的日期不是 UTC 时间,而是当地时间。自从使用日历 class 并尝试提取 .timezone 组件后,我一直无法弄清楚如何判断日期所在的时区 "NSCalendarUnitTimeZone cannot be gotten by this method"。关于如何创建适用于所有情况的通用日期格式化程序有什么建议吗?
一些观察:
如果您的
Date
对象处于 UTC 时区,则也将格式化程序的timeZone
设置为TimeZone(secondsFromGMT: 0)
。如果您要在 UI 中显示
Date
对象的字符串表示形式,您 不会 想要使用locale
个en_US_POSIX
。你想在设备的默认位置显示它(即,根本不要更改格式化程序的locale
)。您仅在处理内部使用的 ISO 8601 和 RFC 3339 日期字符串时使用en_US_POSIX
,例如,用于与 Web 服务交换日期字符串)。最后,我不会指定
dateFormat
字符串,因为并非所有用户都希望日期采用MMMM dd, yyyy
格式。例如,英国用户希望它采用d MMMM yyyy
格式。在 UI 中显示日期时,请改为指定dateStyle
。或者,如果这些样式中的 none 有效,请继续并指定dateFormat
,但使用setLocalizedDateFormatFromTemplate(_:)
而不是固定字符串进行设置。
因此,为了您的目的,您可以这样做:
extension Date {
var dateString: String {
let formatter = DateFormatter()
formatter.dateStyle = .long
formatter.timeZone = TimeZone(secondsFromGMT: 0)
return formatter.string(from: self)
}
}
或者,如果您经常调用它,您可能希望重用格式化程序:
extension Date {
private static let formatterForDateString: DateFormatter = {
let formatter = DateFormatter()
formatter.dateStyle = .long
formatter.timeZone = TimeZone(secondsFromGMT: 0)
return formatter
}()
var dateString: String {
return Date.formatterForDateString.string(from: self)
}
}
使用timeZone属性,获取准确的日期,如下图:
formatter.timeZone = TimeZone(secondsFromGMT: 0)
它将解决您的问题!