Duplicating 24-hour format issue in simulator

On a device, If I have a string, say "04:00 PM" and convert it to a date using a dateformatter:

let dateFormatter = DateFormatter() dateFormatter.format = "h:mm a"

let d = dateFormatter.date(from: "04:00 PM")

If the device is set to a 24 hour time format, then d is nil. On a simulator, the result is a date. What I want to do is to somehow set up the simulator to return a nil under this circumstance. How do I do that?

Things I have tried: setting 24-hour format on the Mac, setting the region on the Mac, setting the region on the simulator, setting the locale in the simulator (maybe there's a locale setting I missed). For the Mac update settings, I reset the simulator afterward for the change to take effect.

So far nothing I've tried works.

The purpose of this is to allow automated tests to be able to detect these nils that will happen on actual devices.

Replies

On a device, If I have a string, say "04:00 PM" and convert it to a date using a dateformatter:

let dateFormatter = DateFormatter() dateFormatter.format = "h:mm a"
let d = dateFormatter.date(from: "04:00 PM")

This code is incorrect. It’s not safe to use a fixed-format date formatter without also pinning the locale. See QA1480 NSDateFormatter and Internet Dates for a detailed explanation of this.

As to what you should do, that depends on your specific circumstances. Where does this time string come from?

Share and Enjoy

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

  • That does not answer the question. I know it's wrong, and I've pointed it out to the development team who coded it. What I'm looking for is a way to get the simulator to behave like a device in order to be able to trap such things with unit tests. Maybe there's some other code somewhere in the app that has a similar issue. It won't be caught by unit tests running on a simulator unless we can somehow set the simulator to behave the same way.

    The docs say that it uses the locale setting, so maybe there's a way to set the locale to mimic what I described in my original post. What I've tried doesn't work, though.

  • Reference for DateFormatter says, "func date(from: String) -> Date? Returns a date representation of a specified string that the system interprets using the receiver’s current settings." So it seems like I should be able to set it some way to duplicate the behavior. For unit tests, we'd probably want to loop through a bunch of settings. I'm looking for some settings that duplicate the behavior, above.

Add a Comment

I know it's wrong, and I've pointed it out to the development team who coded it.

That would have been a useful factoid to include in your question, eh?

There are at least two ways that this code can fail. The first is the most common one:

  1. On a real device, in Settings > General > Language & Region, configure your phone to use a 12-hour locale, like the US.

  2. In Settings > General > Date & Time, enable 24-hour time.

The second is explained in Parsing Dates Without Times.

Combined, the ‘win’ for using DateFormatter to parse fixed-format time-only strings is illusory. IMO you’re better off writing your own parser. Doing that obviates the need for a unit test because your parser is clearly independent of the user’s locale preferences.

If you want to go down the DateFormatter path regardless, I don’t think there’s a good way to configure the simulator to behave this way because:

  • The simulator does not support Settings > General > Date & Time [1].

  • In Xcode, Product > Scheme > Edit Scheme > {Run,Test} > App Region does not let you specify a 12-hour region with a 24-hour override [2].

You could probably hack around this by grovelling through user defaults to find the key that’s set by the 24-Hour Time switch. For an example of that process, see this thread.

IMPORTANT Relying on undocumented preferences keys for testing is OK, but do not encode that info into a shipping product.

Share and Enjoy

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

[1] The fact that it doesn’t is kinda annoying IMO and, if you agree, feel free to file a bug about that. Please post your bug number, just for the record.

[2] Again, that’s fine bug fodder IMO.

  • "That would have been a useful factoid to include in your question, eh?"

    Sure. I did mention it was for automated testing, whose purpose is largely to catch errors made by developers. Why they didn't just use date components in this instance (they did later in the same code) is a mystery to me. :)

    Thanks for the links. I'll review them when I get some time.

Add a Comment

Experienced the same thing, whenever I change the phone settings to a 24 hour format it spits out nil for some reason.

I tried changing the local to: dateFormatter.locale = Locale(identifier: "en_US_POSIX") and it worked