DateFormatter returns unexpected date for Timezone

2019-01-29 01:35发布

问题:

I've read multiple posts about this, and most were due to not setting a specific Timezone and the system getting the current one. My scenario is slightly different and gives unexpected results, so I'll try to explain in detail.

I'm dealing with a backend that returns dates split into a date and a time, stored as an Integer value. For example, a return value could be 131006, which would translate to 13:10:06. I know that this backend always returns the date in UTC. I cast this to a String and I convert the String to a Date with the following code:

let timeFormatter = DateFormatter()
timeFormatter.dateFormat = "HHmmss"
timeFormatter.timeZone = TimeZone(identifier: "UTC")
let time = timeFormatter.date(from: "131006")

To do some checks, I wrote some print statements in this code. The most important one here, is print(timeFormatter.timeZone.abbreviation()), which returns Optional("GMT"). This is fine and as expected, since GMT == UTC. I also checked the value of time, which returns 2000-01-01 13:10:06 +0000, which is still the expected outcome.

Now on to the code where I then format that date into the desired String, with the desired TimeZone:

let timeToString = DateFormatter()
timeToString.dateFormat = "HH:mm"
timeToString.timeZone = TimeZone.current
let timeString = timeToString.string(from: time!)

In this code, I also print the TimeZone.current.abbreviation()) property, which returns Optional("GMT+2"), which is again the expected result. However, when we print the value of the timeString variable, the output is 14:10, instead of the expected result of 15:10.

What is wrong about the way I use DateFormatter? Thanks!

回答1:

In

let timeFormatter = DateFormatter()
timeFormatter.dateFormat = "HHmmss"
timeFormatter.timeZone = TimeZone(identifier: "UTC")
let time = timeFormatter.date(from: "131006")

only a time is provided, but no day/month/year. In this case the date formatter uses a default date of Jan 1, 2001, as you can verify with

print(time!) // 2000-01-01 13:10:06 +0000

Daylight saving time was not active on that day, therefore your local time for that point in time is 14:10, not 15:10.

To solve the issue, you can either combine the date and time strings sent from the server and parse that, or convert the date string first and set it as default date when converting the time string:

timeFormatter.defaultDate = ...