skip to Main Content

I’m using this code to convert HH:mm string to gmt time string HH:mm:

func convertToGMT(timeString: String) -> String {
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "HH:mm"
        
        // Assuming the input time is in the user's local time zone
        dateFormatter.timeZone = TimeZone.current
        
        // Parse the input time string into a Date object
        guard let date = dateFormatter.date(from: timeString) else {
            return "" // Return nil if the input format is invalid
        }
        
        // Convert the date to GMT (UTC) time zone
        dateFormatter.timeZone = TimeZone(abbreviation: "GMT")
        let gmtTimeString = dateFormatter.string(from: date)
        
        return gmtTimeString
    }

The problem is that is Jerusalem gmt -3 i get for 12:00 -> 10:00 instead of 09:00.

What is the problem?

3

Answers


  1. The problem is how your converting the date, when you’re doing the conversion to date using the date formatter

        // Parse the input time string into a Date object
        guard let date = dateFormatter.date(from: timeString) else {
            return "" // Return nil if the input format is invalid
        }
        
    

    It is producing the following date 2000-01-01 10:00:00 +0000.

    Upon looking on a time zone converter website the result produced below shows that the conversion being done on your current code is correct.
    enter image description here

    The conversion shown below using current date indicates a difference of 3 hours, which is also the difference you expected your code to produce. This difference is explained by JeremyP in the comments:

    In July, Israel is in daylight savings time. In January it is not. In
    January of any year including 2000, Israel is two hours ahead of GMT.
    In July it is three hours ahead.

    enter image description here

    A possible solution is to create the date using DateComponents:

    func convertToGMT(timeString: String) -> String {
        var dateComponents = Calendar.current.dateComponents(
            in: TimeZone.current,
            from: Date()
        )
        
        let dateParts = timeString.split(separator: ":")
        dateComponents.hour = Int(dateParts[0]) // TODO: validate existance on array
        dateComponents.minute = Int(dateParts[1]) // TODO: validate existance on array
        
        // Parse the input time string into a Date object
        guard let date = Calendar.current.date(from: dateComponents) else {
            return "" // Return nil if the input format is invalid
        }
        
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "HH:mm"
        // Convert the date to GMT (UTC) time zone
        dateFormatter.timeZone = TimeZone(abbreviation: "GMT")
        let gmtTimeString = dateFormatter.string(from: date)
        
        return gmtTimeString
    }
    
    Login or Signup to reply.
  2. As mentioned in Claudio’s answer the actual time difference depends on the date portion, and the confusion occurs because DateFormatter sets the date to Jan 1, 2000 for a pure time string.

    You have to calculate the time difference from the time in today to consider daylight saving time.

    This is an approach which extracts hour and minute with Regular Expression and sets the hour and minute of the current date with date(bySettingHour:minute:second:of: of Calendar.

    The code works in any locale and throws errors for a format mismatch and if the digits are not in 0..<24 (hour) and 0..<60 (minute).

    enum TimeConversionError: Error {
        case formatMismatch, outOfRange
    }
    
    func convertToGMT(timeString: String) throws -> String {
        guard let hhmm = timeString.firstMatch(of: /(d{1,2}):(d{2})/) else { throw TimeConversionError.formatMismatch }
        guard let currentDate = Calendar.current.date(bySettingHour: Int(hhmm.1)!, minute: Int(hhmm.2)!, second: 0, of: .now) else { throw TimeConversionError.outOfRange }
        let dateFormatter = DateFormatter()
        dateFormatter.timeZone = TimeZone(secondsFromGMT: 0)
        dateFormatter.dateFormat = "HH:mm"
        return dateFormatter.string(from: currentDate)
    }
    
    let string = "12:00"
    do {
        let gmtDateString = try convertToGMT(timeString: string)
    } catch { print(error) }
    
    Login or Signup to reply.
  3. The problem is that you need to set the dateFormater’s defaultDate to startOfDay for .now. Make sure to set the dateFormatter calendar property as well.

    func convertToUTC(timeString: String) -> String? {
        let calendar = Calendar(identifier: .iso8601)
        let locale = Locale(identifier: "en_US_POSIX")
        let defaultDate = calendar.startOfDay(for: .now)
        let dateFormatter = DateFormatter()
        dateFormatter.calendar = calendar
        dateFormatter.locale = locale
        // Assuming the input time is in the user's local time zone which is the default. This line can be omitted
        dateFormatter.timeZone = .current
        dateFormatter.defaultDate = defaultDate
        dateFormatter.dateFormat = "HH:mm"
        // Parse the input time string into a Date object
        guard let date = dateFormatter.date(from: timeString) else {
            return nil // Return nil if the input format is invalid
        }
        // Convert the date to UTC time zone
        dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
        return dateFormatter.string(from: date)
    }
    convertToUTC(timeString: "09:00")  // "12:00" my timezone is -3hs
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search