145

How do I convert a UTC NSDate to local timezone NSDate in Objective C or/and Swift?

Krunal
  • 77,632
  • 48
  • 245
  • 261
  • 14
    Dates certainly do have time zones. – Glenn Maynard Dec 03 '12 at 17:41
  • 1
    If it helps, think of temperatures. They can be expressed in Fahrenheit, Celsius, or Kelvin. But the information being expressed (the average movement of the molecules) has no intrinsic unit, although it is only meaningful to us when expressed in some unit. – software evolved Jan 15 '13 at 04:13
  • 7
    @DaveDeLong NSDate does have a timezone. From the NSDate class reference: "This method returns a time value relative to an absolute reference date—the first instant of 1 January 2001, GMT." Note the clear and specific reference to GMT. – Murray Sagal Mar 20 '13 at 08:13
  • 3
    I disagree. NSDate does NOT have a timezone. To specify the timezone for the NSDate, you use an NSCalendar object or an NSDateFormatter object. If you create an NSDate from a string that has no timezone specified, then the NSDate will assume that the string is in GMT time. – Rickster Dec 03 '13 at 02:04
  • 1
    @MurraySagal Just because that one particular method returns a time value relative to a date in a specific timezone it doesn't mean that NSDate models a date as being relative to a timezone. – eremzeit Nov 07 '14 at 08:58
  • @eremzeit Sure. But here's the quote again this time including the sentence that comes before it. "The sole primitive method of NSDate, timeIntervalSinceReferenceDate, provides the basis for all the other methods in the NSDate interface. This method returns a time value relative to an absolute reference date—the first instant of 1 January 2001, GMT." NSDate objects are anchored to GMT. More discussion here if you're interested: http://stackoverflow.com/questions/2615833/objective-c-setting-nsdate-to-current-utc#comment22025839_2615833 – Murray Sagal Nov 07 '14 at 14:46
  • 3
    @Murray I believe you are mistaken. Just because NSDates are relative to a reference date that the Apple docs format for us in GMT, does not mean NSDates intrinsically have timezones, other than perhaps a default way of interpreting times when no timezone is specified. The documentation could have just as easily said the absolute reference date was 1 Jan 2001 02:00 Budapest time. They are thereby just as much anchored to any timezone as GMT. See this answer http://stackoverflow.com/a/8866731/558352 – Bradley Thomas Sep 05 '16 at 20:36

15 Answers15

142
NSTimeInterval seconds; // assume this exists
NSDate* ts_utc = [NSDate dateWithTimeIntervalSince1970:seconds];

NSDateFormatter* df_utc = [[[NSDateFormatter alloc] init] autorelease];
[df_utc setTimeZone:[NSTimeZone timeZoneWithName:@"UTC"]];
[df_utc setDateFormat:@"yyyy.MM.dd G 'at' HH:mm:ss zzz"];

NSDateFormatter* df_local = [[[NSDateFormatter alloc] init] autorelease];
[df_local setTimeZone:[NSTimeZone timeZoneWithName:@"EST"]];
[df_local setDateFormat:@"yyyy.MM.dd G 'at' HH:mm:ss zzz"];

NSString* ts_utc_string = [df_utc stringFromDate:ts_utc];
NSString* ts_local_string = [df_local stringFromDate:ts_utc];

// you can also use NSDateFormatter dateFromString to go the opposite way

Table of formatting string parameters:

https://waracle.com/iphone-nsdateformatter-date-formatting-table/

If performance is a priority, you may want to consider using strftime

https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man3/strftime.3.html

Community
  • 1
  • 1
slf
  • 22,595
  • 11
  • 77
  • 101
  • probably worth mentioning you can use formatter to read dates back in from strings as well – slf Sep 08 '11 at 18:41
  • 34
    @DaveDeLong that's all well and good if you're just displaying the date as a string. But there are perfectly valid reasons for doing time zone conversions on a date. For example, if you want to default the date on a UIDatePicker using setDate:. Dates returned by web services often are UTC, but represent an event in the user's local time zone, like a TV listing. Passing in an unconverted date will display the incorrect time in the picker. – Christopher Pickslay Oct 16 '11 at 04:31
  • You use this same method to read dates in from strings. Formatter does the conversion to and from UTC for you. – slf Oct 17 '11 at 13:19
  • Dates don't just matter for 'human consumption' they also matter for web services that might expect the date in the local format (summertime here in blighty). – Diziet Apr 24 '12 at 14:49
  • Above code works perfectly for creating and handling NSStrings. But if want to create event in calendar using event kit so that event will be created as per local time zone, this code won't work. what changes do i've to make such that it works.....? – Satyam Jun 09 '12 at 16:10
  • @Satyamsvv EKEvent has a startDate property, just set that – slf Jun 11 '12 at 22:06
  • +22 for a wrong answer? @Dave: Nope. For example, aggregating events day by day in the user's local time. – Glenn Maynard Jul 19 '12 at 20:27
  • @GlennMaynard it's not wrong; this is how you format a date for displaying it according to a different timezone. If you need to group dates by their local day, then you can get an `NSCalendar`, set its timezone to the one you care about, and start converting dates to `NSDateComponents` and comparing their `day`. – Dave DeLong Jul 19 '12 at 20:49
  • @Dave: It's plainly a wrong answer. The question asked how to get an NSDate; he didn't ask anything about formatting it. This answer is irrelevant to the question. – Glenn Maynard Jul 19 '12 at 20:59
  • 5
    @GlennMaynard I disagree. The essence of this answer is that no conversion to the `NSDate` object is necessary, which is correct. Conversion to a timezone happens when the date is formatted, not when it is created, because dates don't have timezones. – Dave DeLong Jul 19 '12 at 21:21
  • @DaveDeLong: No, it only says how to convert a date to a string. Suggesting that the OP might want to make an NSCalendarDate instead would have been fine, but this answer didn't even hint at that. – Glenn Maynard Jul 20 '12 at 21:19
  • 1
    @GlennMaynard ... except that `NSCalendarDate` is deprecated. – Dave DeLong Jul 20 '12 at 22:25
  • 1
    Also note this: http://oleb.net/blog/2011/11/working-with-date-and-time-in-cocoa-part-2/ where it says "GMT != UTC" – huggie Aug 16 '12 at 00:37
  • @slf How can the string date for EST be made to NSDate for EST? – NiKKi Apr 13 '16 at 15:01
  • @NiKKi I think you are looking for the lowercase `z` refer to the links I added to the post – slf Apr 13 '16 at 16:26
107

EDIT When i wrote this I didn't know I should use a dateformatter which is probably a better approach, so check out slf's answer too.

I have a webservice that returns dates in UTC. I use toLocalTime to convert it to local time and toGlobalTime to convert back if needed.

This is where I got my answer from:

https://agilewarrior.wordpress.com/2012/06/27/how-to-convert-nsdate-to-different-time-zones/

@implementation NSDate(Utils)

-(NSDate *) toLocalTime
{
  NSTimeZone *tz = [NSTimeZone defaultTimeZone];
  NSInteger seconds = [tz secondsFromGMTForDate: self];
  return [NSDate dateWithTimeInterval: seconds sinceDate: self];
}

-(NSDate *) toGlobalTime
{
  NSTimeZone *tz = [NSTimeZone defaultTimeZone];
  NSInteger seconds = -[tz secondsFromGMTForDate: self];
  return [NSDate dateWithTimeInterval: seconds sinceDate: self];
}

@end
gyozo kudor
  • 6,284
  • 10
  • 53
  • 80
  • 28
    Don't do this. NSDates are always in UTC. This just confuses the issue. – JeremyP Aug 31 '12 at 09:49
  • 13
    This can be very useful for the "webservice" case noted above. Let's say you have a server that stores events in UTC and the client wants to ask for all events that happened today. To do this, the client needs to get the current date (UTC/GMT) and then shift it by its timezone offset before sending it to the server. – Taylor Lafrinere Oct 01 '12 at 10:57
  • @JeremyP It would be more accurate to say that NSDates are always in GMT. From the NSDate class reference: "This method returns a time value relative to an absolute reference date—the first instant of 1 January 2001, GMT." Note the clear and specific reference to GMT. There is a technical difference between GMT and UTC but that is mostly irrelevant to the solutions most people are looking for. – Murray Sagal Mar 20 '13 at 08:16
  • The best and most reusable solution for my problem :). Thanks a lot :) – Pawan Sharma Nov 26 '13 at 07:07
  • 3
    Would be nice to note where you copied the code from: https://agilewarrior.wordpress.com/2012/06/27/how-to-convert-nsdate-to-different-time-zones/ – aryaxt Mar 25 '15 at 18:24
  • 2
    @aryaxt you are right, i'm sorry. I honestly didn't remember where I copied from when I posted the answer. – gyozo kudor Mar 26 '15 at 07:41
  • I was looking for an answer like this that didn't require you to set an nsdateformatter! thanks @gyozokudor – Daniel Ran Lehmann Jun 14 '15 at 21:37
  • This will probably cause some issues around daylight savings - the offset used in transforming to local may be different than the one used in transforming back into global. – alex-i Sep 22 '15 at 08:40
49

The easiest method I've found is this:

NSDate *someDateInUTC = …;
NSTimeInterval timeZoneSeconds = [[NSTimeZone localTimeZone] secondsFromGMT];
NSDate *dateInLocalTimezone = [someDateInUTC dateByAddingTimeInterval:timeZoneSeconds];
Sendoa
  • 4,705
  • 5
  • 27
  • 21
  • 3
    This answer feels more portable. The answer below assumes the timezone is fixed at runtime whereas the answer above derives the timezone from the platform. – bleeckerj Jul 07 '14 at 05:54
  • 10
    Very helpful. One addition, `secondsFromGMTForDate` should be used if you want to account for daylight saving. See [Apple Docs](https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSTimeZone_Class/index.html#//apple_ref/occ/instm/NSTimeZone/secondsFromGMTForDate:) – Sergey M Dec 15 '14 at 02:33
  • 1
    This fails to take into account DST changes. – lkraider Nov 17 '16 at 18:12
39

Swift 3+: UTC to Local and Local to UTC

extension Date {

    // 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)
    }

    // 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)
    }
}
Krunal
  • 77,632
  • 48
  • 245
  • 261
26

If you want local Date and time. Try this code:-

NSString *localDate = [NSDateFormatter localizedStringFromDate:[NSDate date] dateStyle:NSDateFormatterMediumStyle timeStyle:NSDateFormatterMediumStyle];
Mohd Iftekhar Qurashi
  • 2,385
  • 3
  • 32
  • 44
  • Great answer! This will grab the current date. An adaptation of this which uses a date string would be to replace `[NSDate date]` with `[NSDate dateWithNaturalLanguageString:sMyDateString]`. – Volomike Jan 20 '16 at 19:29
7

Convert your UTC date to Local Date

-(NSString *)getLocalDateTimeFromUTC:(NSString *)strDate
{
    NSDateFormatter *dtFormat = [[NSDateFormatter alloc] init];
    [dtFormat setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
    [dtFormat setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]];
    NSDate *aDate = [dtFormat dateFromString:strDate];

    [dtFormat setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
    [dtFormat setTimeZone:[NSTimeZone systemTimeZone]];

    return [dtFormat stringFromDate:aDate];
}

Use Like This

NSString *localDate = [self getLocalDateTimeFromUTC:@"yourUTCDate"];
Vvk
  • 4,031
  • 29
  • 51
6

Here input is a string currentUTCTime (in format 08/30/2012 11:11) converts input time in GMT to system set zone time

//UTC time
NSDateFormatter *utcDateFormatter = [[[NSDateFormatter alloc] init] autorelease];
[utcDateFormatter setDateFormat:@"MM/dd/yyyy HH:mm"];
[utcDateFormatter setTimeZone :[NSTimeZone timeZoneForSecondsFromGMT: 0]];

// utc format
NSDate *dateInUTC = [utcDateFormatter dateFromString: currentUTCTime];

// offset second
NSInteger seconds = [[NSTimeZone systemTimeZone] secondsFromGMT];

// format it and send
NSDateFormatter *localDateFormatter = [[[NSDateFormatter alloc] init] autorelease];
[localDateFormatter setDateFormat:@"MM/dd/yyyy HH:mm"];
[localDateFormatter setTimeZone :[NSTimeZone timeZoneForSecondsFromGMT: seconds]];

// formatted string
NSString *localDate = [localDateFormatter stringFromDate: dateInUTC];
return localDate;
Ashwin Kumar
  • 622
  • 4
  • 7
4
//This is basic way to get time of any GMT time.

NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"hh:mm a"];  // 09:30 AM
[formatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:1]]; // For GMT+1
NSString *time = [formatter stringFromDate:[NSDate date]];  // Current time
Linh Nguyen
  • 2,006
  • 1
  • 20
  • 16
3

Convert the date from the UTC calendar to one with the appropriate local NSTimeZone.

2

I write this Method to convert date time to our LocalTimeZone

-Here (NSString *)TimeZone parameter is a server timezone

-(NSString *)convertTimeIntoLocal:(NSString *)defaultTime :(NSString *)TimeZone
{
    NSDateFormatter *serverFormatter = [[NSDateFormatter alloc] init];
    [serverFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:TimeZone]];
    [serverFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
    NSDate *theDate = [serverFormatter dateFromString:defaultTime];
    NSDateFormatter *userFormatter = [[NSDateFormatter alloc] init];
    [userFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
    [userFormatter setTimeZone:[NSTimeZone localTimeZone]];
    NSString *dateConverted = [userFormatter stringFromDate:theDate];
    return dateConverted;
}
imjaydeep
  • 878
  • 1
  • 11
  • 34
1

Since no one seemed to be using NSDateComponents, I thought I would pitch one in... In this version, no NSDateFormatter is used, hence no string parsing, and NSDate is not used to represent time outside of GMT (UTC). The original NSDate is in the variable i_date.

NSCalendar *anotherCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:i_anotherCalendar];
anotherCalendar.timeZone = [NSTimeZone timeZoneWithName:i_anotherTimeZone];

NSDateComponents *anotherComponents = [anotherCalendar components:(NSCalendarUnitEra | NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond | NSCalendarUnitNanosecond) fromDate:i_date];

// The following is just for checking   
anotherComponents.calendar = anotherCalendar; // anotherComponents.date is nil without this
NSDate *anotherDate = anotherComponents.date;

i_anotherCalendar could be NSCalendarIdentifierGregorian or any other calendar. The NSString allowed for i_anotherTimeZone can be acquired with [NSTimeZone knownTimeZoneNames], but anotherCalendar.timeZone could be [NSTimeZone defaultTimeZone] or [NSTimeZone localTimeZone] or [NSTimeZone systemTimeZone] altogether.

It is actually anotherComponents holding the time in the new time zone. You'll notice anotherDate is equal to i_date, because it holds time in GMT (UTC).

techniao
  • 151
  • 1
  • 9
1

Please use this code.

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss"]; 
[dateFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]];
NSDate *date = [dateFormatter dateFromString:@"2015-04-01T11:42:00"]; // create date from string

[dateFormatter setDateFormat:@"EEE, MMM d, yyyy - h:mm a"];
[dateFormatter setTimeZone:[NSTimeZone localTimeZone]];
NSString *timestamp = [dateFormatter stringFromDate:date];
incredever
  • 231
  • 1
  • 2
  • 11
0

You can try this one:

NSDate *currentDate = [[NSDate alloc] init];
NSTimeZone *timeZone = [NSTimeZone defaultTimeZone];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateStyle:NSDateFormatterLongStyle];
[dateFormatter setTimeStyle:NSDateFormatterLongStyle];
[dateFormatter setTimeZone:timeZone];
[dateFormatter setDateFormat:@"ZZZ"];
NSString *localDateString = [dateFormatter stringFromDate:currentDate];
NSMutableString *mu = [NSMutableString stringWithString:localDateString];
[mu insertString:@":" atIndex:3];
 NSString *strTimeZone = [NSString stringWithFormat:@"(GMT%@)%@",mu,timeZone.name];
 NSLog(@"%@",strTimeZone);
kalpesh satasiya
  • 799
  • 8
  • 18
0

Solution for SwiftDate library:

// Take date by seconds in UTC time zone
var viewModelDate: Date = DateInRegion(seconds: Double(backendModel.scheduledTimestamp)).date 

...

// Convert date to local timezone and convert to string by format rule.
label.text = viewModelDate.convertTo(region: .current).toFormat(" EEE MM/dd j:mm") 
Bimawa
  • 3,535
  • 2
  • 25
  • 45
-2

Convert UTC time to current time zone.

call function

NSLocale *locale = [NSLocale autoupdatingCurrentLocale];

NSString *myLanguageCode = [locale objectForKey: NSLocaleLanguageCode];
NSString *myCountryCode = [locale objectForKey: NSLocaleCountryCode];

NSString *rfc3339DateTimeString = @"2015-02-15 00:00:00"];
NSDate *myDateTime = (NSDate*)[_myCommonFunctions _ConvertUTCTimeToLocalTimeWithFormat:rfc3339DateTimeString LanguageCode:myLanguageCode CountryCode:myCountryCode Formated:NO];

Function

-NSObject*)_ConvertUTCTimeToLocalTimeWithFormat:rfc3339DateTimeString     LanguageCode:(NSString *)lgc CountryCode:(NSString *)ctc Formated:(BOOL) formated
{
    NSDateFormatter *sUserVisibleDateFormatter = nil;
    NSDateFormatter *sRFC3339DateFormatter = nil;

    NSTimeZone *timeZone = [NSTimeZone defaultTimeZone];

    if (sRFC3339DateFormatter == nil)
    {
        sRFC3339DateFormatter = [[NSDateFormatter alloc] init];

        NSLocale *myPOSIXLocale = [[NSLocale alloc] initWithLocaleIdentifier:[NSString stringWithFormat:@"%@", timeZone]];

        [sRFC3339DateFormatter setLocale:myPOSIXLocale];
        [sRFC3339DateFormatter setDateFormat:@"yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'"];
        [sRFC3339DateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
    }

    // Convert the RFC 3339 date time string to an NSDate.
    NSDate *date = [sRFC3339DateFormatter dateFromString:rfc3339DateTimeString];

    if (formated == YES)
    {
        NSString *userVisibleDateTimeString;

        if (date != nil)
        {
            if (sUserVisibleDateFormatter == nil)
            {
                sUserVisibleDateFormatter = [[NSDateFormatter alloc] init];
                [sUserVisibleDateFormatter setDateStyle:NSDateFormatterMediumStyle];
                [sUserVisibleDateFormatter setTimeStyle:NSDateFormatterShortStyle];
            }

            // Convert the date object to a user-visible date string.
            userVisibleDateTimeString = [sUserVisibleDateFormatter stringFromDate:date];

            return (NSObject*)userVisibleDateTimeString;
        }
    }

    return (NSObject*)date;
}
Meet Doshi
  • 4,241
  • 10
  • 40
  • 81
Alan10977
  • 973
  • 1
  • 9
  • 7