matt
matt

Reputation: 535315

DateFormatter localized date format printing "PM" when it should be "AM"

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

Answers (1)

matt
matt

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

Related Questions