swiftlang / swift-foundation

The Foundation project
Apache License 2.0
2.38k stars 154 forks source link

ISO8601DateFormatter treats timeZone differently from DateFormatter #877

Open adam-fowler opened 1 month ago

adam-fowler commented 1 month ago

When parsing a date with DateFormatter is you set the timeZone of the DateFormatter then the parsed date will be in that time zone. When parsing a date with ISO8601DateFormatter the timeZone parameter is ignored and the Date is always assumed to be UTC.

The output from the following code is

2021-06-21 20:10:15 +0000
2021-06-21 21:10:15 +0000
import Foundation

// create date formatter to parse ISO8601 date strings
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss'Z'"
dateFormatter.timeZone = TimeZone(secondsFromGMT: 3600)!

let date = dateFormatter.date(from: "2021-06-21T21:10:15Z")
print(date!)

let iso8601DateFormatter = ISO8601DateFormatter()
iso8601DateFormatter.timeZone = TimeZone(secondsFromGMT: 3600)!

let date2 = iso8601DateFormatter.date(from: "2021-06-21T21:10:15Z")
print(date2!)
prachigauriar commented 2 weeks ago

I believe the issue here is that you’re using a literal Z in your DateFormatter’s dateFormat. In ISO-8601, the Z indicates UTC. If you update your DateFormatter to be "yyyy-MM-dd'T'HH:mm:ssZZZZZ", both will give the same result:

let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
dateFormatter.timeZone = TimeZone(secondsFromGMT: 3600)!

let date = dateFormatter.date(from: "2021-06-21T21:10:15Z")
print(date!)

let iso8601DateFormatter = ISO8601DateFormatter()
iso8601DateFormatter.timeZone = TimeZone(secondsFromGMT: 3600)!

let date2 = iso8601DateFormatter.date(from: "2021-06-21T21:10:15Z")
print(date2!)

Output:

2021-06-21 21:10:15 +0000
2021-06-21 21:10:15 +0000