Get time from timestamp string that includes timezone

117 Views Asked by At

I receive a date

let slotDateString: String =  "2023-12-06T15:45:00+04:00"

I have two formatters:

var iso8601FormatterWithFullTimeZone: DateFormatter {
    let formatter = DateFormatter(withFormat: "yyyy-MM-dd'T'HH:mm:ssZZZZZ")
    formatter.locale = Locale(identifier: "en_US_POSIX")
    formatter.timeZone = .current

    return formatter
}

var hoursMinutesFormatter: DateFormatter {
    let formatter = DateFormatter(withFormat: "HH:mm")
    formatter.locale = Locale(identifier: "en_US_POSIX")
    formatter.timeZone = .current

    return formatter
}

When I run the following code:

let dateFormatter: DateFormatter = .iso8601FormatterWithFullTimeZone
let hoursMinutesFormatter: DateFormatter = .hoursMinutesFormatter

guard let slotDate: Date = dateFormatter.date(from: slotDateString) else {
     return
}

let slotHour: String = hoursMinutesFormatter.string(from: slotDate)

The slotDate returns me 2023-12-06 12:45:00 +0000and the slotHour returns me "12:45"

I live in timezone +01:00, but I want to get a date and an hour that take into account offset given in the original string. So slotDate should have value of something like 2023-12-06 15:45:00 +4000 or 2023-12-06 12:45:00 +0100 and slotHour should have exactly "15:45"

4

There are 4 best solutions below

0
On BEST ANSWER

You can drop the timezone part and then get the hour:

let slotDateString = String("2023-12-06T15:45:00+01:00".dropLast(6)) //  Drop timezone from the string
var iso8601FormatterWithFullTimeZone: DateFormatter {
    let formatter = DateFormatter(withFormat: "yyyy-MM-dd'T'HH:mm:ss") //  No timezone in the formatter
    ,,,
}

So the slotHour would be exactly "15:45"

0
On

You say "...I want to get a date and an hour that take into account offset given in the original string." I don't think there is an easy way to extract the time zone from a date string using a DateFormatter.

If you know it's going to be in ISO8601DateFormatter .withInternetDateTime format, you could write code to extract the offset from UDT yourself, and then apply that timezone to your output date formatter before converting your date to a string.

4
On

If you want a specific output from your Date object you need to use a second formatter for the output

let formatter = ISO8601DateFormatter()
formatter.formatOptions = [.withInternetDateTime]
formatter.timeZone = .current // <-- Same as yours, +1

let output = formatter.string(from: slotDate)
print(output)

2023-12-06T12:45:00+01:00

And to get the hour/minute string in the original time zone you need to use that time zone in your formatter

var hoursMinutesFormatter: DateFormatter {
    let formatter = DateFormatter()
    formatter.dateFormat = "HH:mm"
    formatter.timeZone = TimeZone(secondsFromGMT: 4*3600) // Or use an identifier/abbrevation init if you know the zone 
    return formatter
}

let slotHour = hoursMinutesFormatter.string(from: slotDate)
print(slotHour)

15:45

0
On

If you want the same HH:mm for the same timezone then simply access the value from the original string. No date formatters are needed in this case.

let slotDateString: String =  "2023-12-06T15:45:00+04:00"
let slotHour = String(slotDateString.dropLast(9).dropFirst(11))

This works as long as slotDateString is in the format you show in your question and as long as you want the time is the same timezone of the original string and not the user's current timezone.