从字符串解析日期时,如何阻止将其转换为本地时间?

When parsing a date from a string, how can I stop it from being converted to local time?

当我将任何类型的时间戳转换为日期时,无论是 UTC 还是其他偏移量,它都会将其转换为我的本地时间。我怎样才能阻止它这样做?

例如,以下代码打印出 2022-05-24 09:40:11 +0000,但它应该显示为 2022-05-24 01:40:11 +0000。我不希望它返回的是我自己时区的等效时间

let dateStr = "2022-05-024T01:40:11.126-08:00"
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"
let parsedDate = dateFormatter.date(from: dateStr)
print(parsedDate)

Date 只是自某个锚点以来经过的时间量的容器(即自 Unix 纪元以来的毫秒数),它不会“转换”该值,它所做的是,当您使用“打印”时,它会利用平台 locale/timezone 来呈现它所代表的时间的“人类可读”演示文稿

例如...

let dateStr = "2022-05-024T01:40:11.126-08:00"
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"
let date = dateFormatter.date(from: dateStr)!
print(date)

打印2022-05-24 09:40:11 +0000

但是,如果我更改格式化程序的时区,例如...

let utcFormatter = DateFormatter()
utcFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"
utcFormatter.timeZone = TimeZone(abbreviation: "UTC")
let utcDate = utcFormatter.date(from: dateStr)!
print(utcDate)

它仍然打印 2022-05-24 09:40:11 +0000

好吧,无论如何它都是以 UTC 打印的,所以让我们尝试不同的时区:

let auFormatter = DateFormatter()
auFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"
auFormatter.timeZone = TimeZone(abbreviation: "AEST")
let auDate = auFormatter.date(from: dateStr)!
print(auDate)

它仍然打印 2022-05-24 09:40:11 +0000

如果我们阅读 docs 它实际上是说 “表示仅对调试有用。”

如果您希望以不同的方式进行演示,请使用不同的格式化程序,例如...

let dateStr = "2022-05-024T01:40:11.126-08:00"
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"
let date = dateFormatter.date(from: dateStr)!
print(date)

dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
print(dateFormatter.string(from: date))

dateFormatter.timeZone = TimeZone(secondsFromGMT: -(8 * 60 * 60))
print(dateFormatter.string(from: date))

dateFormatter.timeZone = TimeZone(abbreviation: "AEST")
print(dateFormatter.string(from: date))

打印...

2022-05-24 09:40:11 +0000        // print(date)
2022-05-24T09:40:11.126Z         // UTC
2022-05-24T01:40:11.126-08:00    // -8
2022-05-24T19:40:11.126+10:00    // AEST

(显然你也可以为不同的表示配置Locale

它们都代表相同的date/time值,只是在不同的时区

您还可以使用 Date#timeIntervalSinceReferenceDateDate#timeIntervalSince1970 检查不同的日期值,例如...

let dateStr = "2022-05-024T01:40:11.126-08:00"
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"
print(dateFormatter.date(from: dateStr)!.timeIntervalSince1970)

dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
print(dateFormatter.date(from: dateStr)!.timeIntervalSince1970)

dateFormatter.timeZone = TimeZone(secondsFromGMT: -(8 * 60 * 60))
print(dateFormatter.date(from: dateStr)!.timeIntervalSince1970)

dateFormatter.timeZone = TimeZone(abbreviation: "AEST")
print(dateFormatter.date(from: dateStr)!.timeIntervalSince1970)

打印...

1653385211.126
1653385211.126
1653385211.126
1653385211.126

并且作为 docs 状态,“日期值与 1970 年 1 月 1 日 00:00:00 UTC 之间的间隔。”

在这种情况下,格式化程序时区对解析没有影响,仅对表示有影响(locale 可以解决解析问题,但这是另一个话题)