NSDate - Convert Date to GMT

63,218

Solution 1

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.dateFormat = @"yyyy-MM-dd'T'HH:mm";
        
NSTimeZone *gmt = [NSTimeZone timeZoneWithAbbreviation:@"GMT"];
[dateFormatter setTimeZone:gmt];
NSString *timeStamp = [dateFormatter stringFromDate:[NSDate date]];
[dateFormatter release];

Solution 2

Working with time in Cocoa can be complicated. When you get an NSDate object, it's in the local time zone. [[NSTimeZone defaultTimeZone] secondsFromGMT] gives you the offset of the current time zone from GMT. Then you can do this:

NSDate *localDate = // get the date
NSTimeInterval timeZoneOffset = [[NSTimeZone defaultTimeZone] secondsFromGMT]; // You could also use the systemTimeZone method
NSTimeInterval gmtTimeInterval = [localDate timeIntervalSinceReferenceDate] - timeZoneOffset;
NSDate *gmtDate = [NSDate dateWithTimeIntervalSinceReferenceDate:gmtTimeInterval];

Now gmtDate should have the correct date in GMT for you. In order to display it, look at NSDateFormatter, specifically the setDateStyle and setTimeStyle methods. You create an NSDateFormatter, configure it the way you want, and then call stringFromDate: to get a nicely formatted string.

Solution 3

Howard's Answer is correct and please vote it up and accept it.

For reference I think it is useful to explain the difference between date objects and localised date representations are.

In many programming languages date objects are used to represent unique points in time. Ignoring Relativistic arguments it can be assumed that at any instance we can define a point in time which is equal universally for every one, regardless of how we measure time.

If for each point in time we could construct a unique label, that label could be passed around and referenced unambiguously. The purpose of date objects is to act as a unique universal label for a given point in time.

One could come up with any number of techniques to construct such a labelling scheme and how each date object chooses to do so is immaterial to anyone using them.

An example may be to use a numeric offset from a universal event (X seconds since the sun exploded).

It is only when we wish to take a time point and serialize it into a human readable string that we must deal with the complexities of time zones, locales, etc...

(Local Date String) + (Date Formatter) => Time Point

Time Point + (Date Formatter) => (Local Date String)

Every time point is universal... there is no such thing as a new york time point, or gmt time point, only once you convert a time point to a local string (using a date formatter) does any association to a time zone appear.

Note: I'm sure there are many blogs/articles on this very issue, but my google foo is failing me at this hour. If anyone has the enthusiasm to expand on this issue please feel free to do so.

Solution 4

Swift 4:

//UTC or GMT ⟺ Local 

extension Date {

    // Convert local time to UTC (or GMT)
    func toGlobalTime() -> Date {
        let timezone = TimeZone.current
        let seconds = -TimeInterval(timezone.secondsFromGMT(for: self))
        return Date(timeInterval: seconds, since: self)
    }

    // Convert UTC (or GMT) to local time
    func toLocalTime() -> Date {
        let timezone = TimeZone.current
        let seconds = TimeInterval(timezone.secondsFromGMT(for: self))
        return Date(timeInterval: seconds, since: self)
    }

}

Solution 5

While Alex's answer was a good start, it didn't deal with DST (daylight savings time) and added an unnecessary conversion to/from the reference date. The following works for me:

To convert from a localDate to GMT, taking DST into account:

NSDate *localDate = <<your local date>>
NSTimeInterval timeZoneOffset = [[NSTimeZone systemTimeZone] secondsFromGMTForDate:localDate];
NSDate *gmtDate = [localDate dateByAddingTimeInterval:-timeZoneOffset]; // NOTE the "-" sign!

To convert from a GMT date to a localDate, taking DST into account:

NSDate *gmtDate  = <<your gmt date>>
NSTimeInterval timeZoneOffset = [[NSTimeZone systemTimeZone] secondsFromGMTForDate:gmtDate];
NSDate *localDate = [gmtDate dateByAddingTimeInterval:timeZoneOffset];

One small note: I used dateByAddingTimeInterval, which is iOS 4 only. If you are on OS 3 or earlier, use addTimerInterval.

Share:
63,218
Admin
Author by

Admin

Updated on February 09, 2021

Comments

  • Admin
    Admin over 3 years

    I need the ability to convert an NSDate value to a GMT Date.

    How can I go about converting an NSDate value to a GMT formatted NSDate value, independent of whatever date locale settings the iPhone device is using?

  • Donna
    Donna over 14 years
    Does the DateFormatter work with both "%d" type codes... and just "d" type codes?
  • Felixyz
    Felixyz about 14 years
    While this seems good at first, I want to strongly advice against using this method, which can lead to a lot of confusion. A date represents a single point in time. The issue is that you want different representations of this date. The same point in time has different "names" in Delhi and in New York, etc. Therefore, think hard about what your context is. You can set the calendar.timeZone property on UIDatePickers to make them use another time zone, and as Howard shows, you can customize date formatters to work with different zones.
  • vond
    vond almost 14 years
    This is also a less than ideal solution. As Felixyz pointed out in his response to Alex, you do not want to be messing with the NSDate itself but rather its representation. Howard's answer will give a "localized" representation of the NSDate.
  • cutiko
    cutiko almost 14 years
    An NSDate object represents a point in time, independent of time zone etc... you never need to convert an NSDate to another... it is only when you serialize (convert to and from strings) that the time zone/locale, whether GMT or other comes into account. Howards answer is correct.
  • cutiko
    cutiko almost 14 years
    An NSDate represents a point in time, independant of a time zone. Your object localDate represents the same point as gmtDate. When you go to convert it to a string you would still need to use a DateFormatter on both, and get the same results.
  • cutiko
    cutiko almost 14 years
    @Donna: The latest NSDateFormatter uses the UTS#35 standard. unicode.org/reports/tr35/tr35-6.html#Date_Format_Patterns . It will not work with the C style %d syntax.
  • Ben Challenor
    Ben Challenor almost 13 years
    @Akusete other serialization points are UIDatePicker and NSCalendar.
  • PSC
    PSC over 12 years
    Old thread, but I also encourage using Howard's approach instead of messing with the date itself as some of the other suggestions do. Worth noting is that the "description" of an NSDate is always in GMT. This implies that an NSLog(@"%@", [NSDate date]) always shows the given date in GMT as well.
  • Tomer Even
    Tomer Even over 12 years
    NSTimeInterval gmtTimeInterval = [localDate timeIntervalSinceReferenceDate] - timeZoneOffset; is misleading if you are in the + side of the world then it should be NSTimeInterval gmtTimeInterval = [localDate timeIntervalSinceReferenceDate] + timeZoneOffset;
  • Joe Strout
    Joe Strout over 11 years
    I agree, the code in this example is incorrect and caused my a bug in my app. I then spent a fair amount of time digging into it, and now I understand what's going on. [NSDate date] gives you a date that is stored, internally, in GMT. If you NSLog(@"%@", localDate) you will see something like 2012-12-06 15:22:45 +0000; that "+0000" is indicating GMT. Moreover, the timeIntervalSinceReferenceDate value reflects the current number of seconds since 2001-01-01 in the GMT time zone, as I verified by doing the math. If you want a local time interval, you'd have to ADD the time zone offset.
  • Joe Strout
    Joe Strout over 11 years
    I'd like to elaborate on Olaf's comment by adding that not only does an NSDate description show the date/time in GMT, but the timeIntervalSinceReferenceDate reflects the number of seconds since 2001-01-01 in GMT (not in your local time zone), too.
  • penduDev
    penduDev over 9 years
    Let's say there's a server which says I only calculate and work on GMT times and don't entertain the concept of timezones. It'll basically make the same thing you are talking about. All the time zone handling can be done on client. Server works on a unique reference point.
  • Vikram Pote
    Vikram Pote over 8 years
    How should i do it in swift?
  • LavaSlider
    LavaSlider over 2 years
    Converting to GMT might be useful if what is really wanted is to store the date and time in a way that will not look different when the user has their phone in Delhi or New York. If you want it to be 2:00 PM, since it is important that it was two hours after noon, then always converting to GMT and always setting the serialization points to GMT will always have your application display 2:00 PM for the stored NSDate without having to store a timezone.