DateFormatter doesn't work on certain device

this test fail on the specific device which disabled "Date & Time -> 24-Hour Time" and location is Japan, and when I set the locale, it runs fine on that specific device to, and I am curious what makes this happen, so anybody know the reason please help

import XCTest

final class DateFormatterTest: XCTestCase {
        
    func testDateFormatter() throws {
        let sendTime = "2023-04-25T02:07:29"
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
//        dateFormatter.locale = Locale(identifier: "en_US_POSIX") // test fail until I set locale
        let result = dateFormatter.date(from: sendTime)
        
        XCTAssertNotNil(result)
    }
}
Answered by DTS Engineer in 751949022

This is a long-standing gotcha with DateFormatter. I explain it in detail in QA1480 NSDateFormatter and Internet Dates.

IMPORTANT When you apply en_US_POSIX, do it before setting the dateFormat property.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Accepted Answer

This is a long-standing gotcha with DateFormatter. I explain it in detail in QA1480 NSDateFormatter and Internet Dates.

IMPORTANT When you apply en_US_POSIX, do it before setting the dateFormat property.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Even better, don’t use DateFormatter to parse internet dates; use the newer ISO8601DateFormatter (link) instead. It Just Works™.

Your example date almost works with the default options in ISO8601DateFormatter except that it’s missing a time zone marker on the end. So this is what Just Works™:

let f = ISO8601DateFormatter()
f.formatOptions.remove(.withTimeZone)
print(f.date(from: "2023-04-25T02:07:29")!) // 2023-04-25 02:07:29 +0000 

Note the formatter defaults to GMT, so you may also need to set timeZone. (This is different from DateFormatter which defaults to your local time zone, not GMT.)

@eskimo: Maybe that old tech note could use an update to mention ISO8601DateFormatter?

use the newer ISO8601DateFormatter

While ISO8601DateFormatter is fab, I always find myself running into problems like the one here, where it’s very slightly out of alignment with the requirements.

Maybe that old tech note could use an update to mention ISO8601DateFormatter?

QA1480 is in the documentation archive and so I can’t directly update it.

Note that the key points from that doc have made it into the modern docs but I like linking to QA1480 because the Buddhist calendar example is a strong motivator.

I could replace QA1480 wholesale but I don’t think that’s the right option.

After spending years trying to document our way out of this problem my conclusion is that it simply won’t work. The dateFormat property is such an ‘obviously correct’ approach that folks never actually read the docs about it.

IMO the path forward here is to deprecate dateFormat (r. 33988168) and replace it with localizedDateFormat and fixedDateFormat, where setting the latter forces the locale. However, that’s just my opinion and there’s no sign of it actually happening. On the plus side, I think issue will slowly go away as folks move to the VerbatimFormatStyle.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

DateFormatter doesn't work on certain device
 
 
Q