Reputation: 535315
Here's a reduced version of my formatter class:
class MyDateFormatters {
let timeFormatter : DateFormatter
init(timeZone:Int) {
self.timeFormatter = {
let tz = TimeZone(secondsFromGMT: timezone)
let df = DateFormatter()
df.timeZone = tz
df.setLocalizedDateFormatFromTemplate("hhmm")
return df
}()
}
}
In my viewDidLoad
, I'm deriving a time string from raw data. But it's coming out wrong in a weird way: I'm seeing "PM" where I should see "AM"!
Here's the raw data (comes in thru JSON):
let timeZone = -14400
let sunriseRaw = 1570620145
Now, if just make a plain vanilla date formatter and print out sunriseRaw
, this is what I get:
let sunrise = Date(timeIntervalSince1970: Double(sunriseRaw))
let df = DateFormatter()
df.dateFormat = "hh:mm a"
df.timeZone = TimeZone(secondsFromGMT: timeZone)
print(df.string(from: sunrise))
// 07:22 AM
And that is correct. Okay, now I'll do with my date formatter:
let myf = MyDateFormatters(timeZone:timeZone).timeFormatter
let sunriseString = myf.string(from: sunrise)
print(sunriseString)
// 7:22 PM
How can this be? My class is doing exactly the same thing, except that it uses a localized date format with a template. Why am I seeing "PM" instead of "AM"
Upvotes: 1
Views: 159
Reputation: 535315
You've been caught by an unbelievably obscure bug in your code. Look very, very closely:
init(timeZone:Int) {
// ^
self.timeFormatter = {
let tz = TimeZone(secondsFromGMT: timezone)
// ^
So the timezone
you are using in your formatter is not the same as the timeZone
that arrived as parameter into your initializer.
So, you may, ask, what is timezone
? Why didn't the compiler flag it? Sigh, it's because Foundation injects the entirety of C / Darwin into your code. timezone
is a Darwin value. Open time.h and you'll see it. Tricky, eh?
(Unfortunately I don't think there's a way to get the compiler to warn about this kind of thing. Using Darwin values without explicit namespacing is legal, and you wouldn't want it not to be.)
Upvotes: 2