Ram Keerthy
Ram Keerthy

Reputation: 227

Converting UTC date time to local date time in iOS

I am trying to convert UTC date time to local date time and below is my code.

func dateTimeStatus(date: String) -> String{
    let dateFormatter = DateFormatter()
    dateFormatter.dateFormat = "MM/dd/yy hh:mm:ss a"
    dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
    let dt = dateFormatter.date(from: date)

    dateFormatter.timeZone = TimeZone.current
    dateFormatter.dateFormat = "MM/dd/yy hh:mm:ss a"

    return dateFormatter.string(from: dt!) // .string(from: dt!)
}

The above set of code works when the system(iPhone or iPad) language is set to English(India). If I change the language to Japanese then a exception is thrown as below.

Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value

at return statement.

I very well know that I am messing up with dateFormatter due to which date is not recognised by the dateFormatter.date(from: date). Hence a nil value is assigned to the dt.

Any suggestions for generically using the date time format for all system language would be appreciable.

Upvotes: 2

Views: 6883

Answers (1)

rmaddy
rmaddy

Reputation: 318774

Whenever you attempt to parse a fixed format date string, you need to set the formatter's locale to a special locale of en_US_POSIX. This deals with many possible issues including the user's region and language, and the user's 12/24 hour settings.

dateFormatter.locale = Locale(identifier: "en_US_POSIX")

Then reset it to the user's locale along with the time zone.

dateFormatter.locale = Locale.current

You should also avoid forced unwrapping in case you get an unexpected date string.

Updated code:

func dateTimeStatus(date: String) -> String {
    let dateFormatter = DateFormatter()
    dateFormatter.dateFormat = "MM/dd/yy hh:mm:ss a"
    dateFormatter.locale = Locale(identifier: "en_US_POSIX")
    dateFormatter.timeZone = TimeZone(secondsFromGMT: 0)
    if let dt = dateFormatter.date(from: date) {
        dateFormatter.locale = Locale.current
        dateFormatter.timeZone = TimeZone.current
        dateFormatter.dateFormat = "MM/dd/yy hh:mm:ss a"

        return dateFormatter.string(from: dt)
    } else {
        return "Unknown date"
    }
}

You should also consider using a date and time style instead of a fixed format when presenting a date/time to a user. This ensures the date is in a friendly format. In your case you have a real issue.

Let's say you get a result of "06/05/18 10:30:00 am".

What date is that? Depending on where you live that could be June 5, 2018. It could be May 6, 2018. It could be May 18, 2006. It's very ambiguous.

Better to use something like:

func dateTimeStatus(date: String) -> String {
    let dateFormatter = DateFormatter()
    dateFormatter.dateFormat = "MM/dd/yy hh:mm:ss a"
    dateFormatter.locale = Locale(identifier: "en_US_POSIX")
    dateFormatter.timeZone = TimeZone(secondsFromGMT: 0)
    if let dt = dateFormatter.date(from: date) {
        let userFormatter = DateFormatter()
        userFormatter.dateStyle = .medium // Set as desired
        userFormatter.timeStyle = .medium // Set as desired

        return userFormatter.string(from: dt)
    } else {
        return "Unknown date"
    }
}

Upvotes: 6

Related Questions