Converting date between timezones swift
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)
}
}
Related videos on Youtube
Alk
Updated on July 09, 2022Comments
-
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 toGMT
. -
Alk almost 8 yearsThe 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 almost 8 yearsThat'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 about 6 yearsI 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 about 6 yearsPass GMT+10, it'll work... Now try GMT+8, it'll crash sorta like every other GMT timezone...So yes, very efficient
-
valeCocoa over 4 yearsDoes this method also take into account daylight saving time differences?
-
Nikaaner over 4 years@valeCocoa Yes, because different time zones are used for DST and standard time
-
valeCocoa over 4 yearsthen the
delta
should be calculated passing thedate
tosecondsFromGMT()
, 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 thedelta
was right in @mukaissi method. Hence that would be:let delta = TimeInterval( targetTimeZone.secondsFromGMT(for: self) - initTimeZone.secondsFromGMT(for: self) )
-
Nikaaner over 4 yearsprobably we use it for different purposes or in different circumstances, it turns out for someone fits this way but for other different one
-
valeCocoa over 4 yearsTest 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 over 4 yearsIn 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 asepochConversion(from: to:)
-
mbi about 4 years@valeCocoa is absolutely right about daylight saving times
-
dbplunkett almost 4 yearsYour 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 over 3 yearsHow can we convert the date to a string that
dateFromString(string:)
would accept? -
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 directDate
->Date
conversion. -
SmileBot over 2 yearsDealing strictly with GMT/UTC except when displaying it to the user is key. Otherwise you will pooping your diapers.
-
João Serra almost 2 yearsjust 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