Rustam-Deniz Emirali
Rustam-Deniz Emirali

Reputation: 166

How to change timezone of date string in iso format?

I'am receiving following string: "2021-02-15T02:37:27.371243Z". I want to add hours by changing time zone of string to current time zone of device. Date received from DateFormatter with .current timezone property from dateFormatter.date method changes nothing.

Example:

let dateString = "2021-04-10T10:00:01.594119Z"
let dateFormatter = DateFormatter()
dateFormatter.timeZone = .current
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"
let date = dateFormatter.date(from: dateString)
let anotherDateFormatter = DateFormatter()
var calendar = Calendar.current
calendar.timeZone = .current
anotherDateFormatter.calendar = calendar
anotherDateFormatter.dateFormat = "hh:mm"
anotherDateFormatter.timeZone = .current
let string = anotherDateFormatter.string(from: date!)
print(string)

Output: 04:00. Incorrect, not my time.

I've come up with solution with calendar(current calendar has current time zone by default) by retrieving it's components:

let dateString = "2021-04-10T10:00:01.594119Z"
let dateFormatter = DateFormatter()
dateFormatter.timeZone = .current
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"
let date = dateFormatter.date(from: dateString)
print(hourWithMinutesForCurrentTimezone(date: date!))

private func hourWithMinutesForCurrentTimezone(date: Date) -> String {
    let calendar = Calendar.current
    let hours = String(calendar.component(.hour, from: date))
    let formattedHours = hours.count == 1 ? "0\(hours)" : hours
    let minutes = String(calendar.component(.minute, from: date))
    let formattedMinutes = minutes.count == 1 ? "0\(minutes)" : minutes
    return "\(formattedHours):\(formattedMinutes)"
}

Output: 16:00 - Yay! My time

It works and changes hour and minutes to the current timezone, but I don't find this solution elegant, anyone knows way of changing time to current timezone better?

Upvotes: 0

Views: 174

Answers (1)

Rickard Elimää
Rickard Elimää

Reputation: 7591

I don't have fully understanding in dates, but there is a formatter made specifically for this type of datestring called ISO8601DateFormatter(). It can be implemented like this.

extension String {
    func toLocalDate() -> Date? {            
        let formatter = ISO8601DateFormatter()
        formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
        
        return formatter.date(from: self)
    }
}

let dateString = "2021-02-15T02:37:27.371243Z"
let date = dateString.toLocalDate() // "Feb 15, 2021 at 3:37 AM" (Sweden, GMT +2)

You can also create your own formatter: yyyy-MM-dd'T'HH:mm:ss.SSSSZZZ
yyyy: years
MM: month, numerical
dd: days
'T': String
HH: Hours in 24h format
mm: minutes
ss: seconds
SSSS: fractions of seconds (milliseconds)
ZZZ: timezone: it's enough with one Z, but I added two to clearly show the timezone is determined by the last three characters in your dateString.

extension String {
    func toLocalDate() -> Date? {
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSSZZZ"
        
        formatter.timeZone = TimeZone.current
            
        return formatter.date(from: self)
    }
}

let dateString = "2021-02-15T02:37:27.371243Z"
let date = dateString.toLocalDate() // "Feb 15, 2021 at 3:37 AM" (Sweden, GMT +2)

When you have a Date, then you can basically just use Calendar to pick the hours and minutes from it with Calendar.current.dateComponents([.hour, .minute], from: date).

Do note, toLocalDate returns nil, if the dateString isn't formatted properly.

Upvotes: 2

Related Questions