Converting date between timezones swift

48,184

Solution 1

Couldn't you just use your data formatter again with a different time zone and convert it? Such as

dateFormatter.timeZone = NSTimeZone(abbreviation: "GMT")
let gmtDate = dateFormatter.dateFromString(string: "your old date as string here")

Solution 2

Simpler version:

extension Date {
    func convertToTimeZone(initTimeZone: TimeZone, timeZone: TimeZone) -> Date {
         let delta = TimeInterval(timeZone.secondsFromGMT(for: self) - initTimeZone.secondsFromGMT(for: self))
         return addingTimeInterval(delta)
    }
}

Solution 3

about 50 times more effecient

extension Date {
    func convertToLocalTime(fromTimeZone timeZoneAbbreviation: String) -> Date? {
        if let timeZone = TimeZone(abbreviation: timeZoneAbbreviation) {
            let targetOffset = TimeInterval(timeZone.secondsFromGMT(for: self))
            let localOffeset = TimeInterval(TimeZone.autoupdatingCurrent.secondsFromGMT(for: self))

            return self.addingTimeInterval(targetOffset - localOffeset)
        }

        return nil
    }
}

Solution 4

Since NSDate is always in GMT/UTC the time zone only becomes relevant when displaying it to, or getting it from, the user. Just always assume it's UTC internally, convert it for the user (by setting it on the NSDateFormatter) as necessary, and you no longer have to worry about the problem.

Solution 5

Based on mukaissi's answer, but the order of deductible in the expression has been corrected.

extension Date {    
    func convert(from initTimeZone: TimeZone, to targetTimeZone: TimeZone) -> Date {
        let delta = TimeInterval(initTimeZone.secondsFromGMT() - targetTimeZone.secondsFromGMT())
        return addingTimeInterval(delta)
    }    
}
Share:
48,184

Related videos on Youtube

Alk
Author by

Alk

Updated on July 09, 2022

Comments

  • Alk
    Alk almost 2 years

    I have a date stored on my online server database which is in GMT. I load the date and convert it to the user's timezone using the following code :

     if let messagedate = oneitem["timestamp"] as? String {
         let dateFormatter = NSDateFormatter()
         dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
         let date = dateFormatter.dateFromString(messagedate)
         let source_timezone = NSTimeZone(abbreviation: "GMT")
         let local_timezone = NSTimeZone.systemTimeZone()
         let source_EDT_offset = source_timezone?.secondsFromGMTForDate(date!)
         let destination_EDT_offset = local_timezone.secondsFromGMTForDate(date!)
         let time_interval : NSTimeInterval = Double(destination_EDT_offset - source_EDT_offset!)
    
    
         let final_date = NSDate(timeInterval: time_interval, sinceDate: date!)
         curr_item.date = final_date
     }
    

    Now I need to convert the date back to GMT in order to communicate it to the server, however I'm not sure how to convert it back to GMT.

  • Alk
    Alk almost 8 years
    The issue is that I load posts newer than post x with the date set above (x.date) , I need to convert the date set above back to GMT, otherwise the date in the user's timezone gets passed to the server and the whole query makes no sense.
  • David Berry
    David Berry almost 8 years
    That's kind of my point. The only time timezone matters is to the user. Get it from the user and immediately change it to GMT, so it's always in a consistent internal format everywhere it's used.
  • iDoc
    iDoc about 6 years
    I am sorry but i can not completely follow: If your function's name suggest convertingToLocalTime the targetOffset always should be autoupdatingCurrent. I think targetOffset and LocalOffset must be swapped in your code.
  • Greg432
    Greg432 about 6 years
    Pass GMT+10, it'll work... Now try GMT+8, it'll crash sorta like every other GMT timezone...So yes, very efficient
  • valeCocoa
    valeCocoa over 4 years
    Does this method also take into account daylight saving time differences?
  • Nikaaner
    Nikaaner over 4 years
    @valeCocoa Yes, because different time zones are used for DST and standard time
  • valeCocoa
    valeCocoa over 4 years
    then the delta should be calculated passing the date to secondsFromGMT(), otherwise how would be possible for it to know if it does fall under daylight saving time period or not. Moreover the order of the parameters for calculating the delta was right in @mukaissi method. Hence that would be: let delta = TimeInterval( targetTimeZone.secondsFromGMT(for: self) - initTimeZone.secondsFromGMT(for: self) )
  • Nikaaner
    Nikaaner over 4 years
    probably we use it for different purposes or in different circumstances, it turns out for someone fits this way but for other different one
  • valeCocoa
    valeCocoa over 4 years
    Test your method by feeding with this data: let gmtTZ = TimeZone(secondsFromGMT: 0)! let romeTZ = TimeZone(identifier: "Europe/Rome")! let gregCalGMT: Calendar = { var cal = Calendar(identifier: .gregorian) cal.timeZone = gmtTZ return cal }() let dc = DateComponents(year: 2019, month: 8, day: 15, hour: 12, minute: 30) let date = gregCalGMT.date(from: dc)! let inRome = date.convert(from: gmtTZ, to: romeTZ) print(date) print(inRome)
  • valeCocoa
    valeCocoa over 4 years
    In order to take account for DST (daylight time savings) the delta should be calculated using this formula: let delta = TimeInterval(timezone.secondsFromGMT(for: self) - initTimeZone.secondsFromGMT(for: self)) Moreover, since this is an "epoch calculation" I'd rename the method too with something describing better its functionality as epochConversion(from: to:)
  • mbi
    mbi about 4 years
    @valeCocoa is absolutely right about daylight saving times
  • dbplunkett
    dbplunkett almost 4 years
    Your delta direction is backwards - you should either swap the arguments in the subtraction, or swap the parameter names. However, even once that's fixed: Try converting 2020-03-08T05:00:00Z from GMT to EST. The result will be off by one hour (see my answer for details).
  • ScottyBlades
    ScottyBlades over 3 years
    How can we convert the date to a string that dateFromString(string:) would accept?
  • dbplunkett
    dbplunkett over 3 years
    @ScottyBlades This answer is for the case where you have a date string with no time offset, as the asker does. If you're starting with a Date, it's more efficient to do a direct Date -> Date conversion.
  • SmileBot
    SmileBot over 2 years
    Dealing strictly with GMT/UTC except when displaying it to the user is key. Otherwise you will pooping your diapers.
  • João Serra
    João Serra almost 2 years
    just a warning, although I slightly modified this code to receive a TimeZone instead a String, it giving me the wrong time by 1 hour(daylightSaving?), maybe it was me but I leave the warning here