Objective-C, How can I get the current date in UTC timezone?

88,490

Solution 1

NSDate *currentDate = [[NSDate alloc] init];

Now it is in UTC, (at least after using the method below)
To store this time as UTC (since refernce date 1970) use

double secsUtc1970 = [[NSDate date]timeIntervalSince1970];

Set Date formatter to output local time:

NSTimeZone *timeZone = [NSTimeZone defaultTimeZone];
// or Timezone with specific name like
// [NSTimeZone timeZoneWithName:@"Europe/Riga"] (see link below)
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setTimeZone:timeZone];
[dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"];
NSString *localDateString = [dateFormatter stringFromDate:currentDate];

Available NSTimeZone names

A NSDate object always uses UTC as time reference, but the string representation of a date is not neccessarily based on UTC timezone.

Please note that UTC is not (only) a timeZone, It is a system how time on earth is measured, how it is coordinated (The C in UTC stands for coordinated).
The NSDate is related to a reference Date of midnight 1.1.1970 UTC, altough slightly wrongly described by Apple as 1.1.1970 GMT.

In the original question the last word timeZone is not perfect.

Solution 2

You're overcomplicating things.

NSDates don't have time zones or calendars. [NSDate date] gets the current date, which is a measurement of a moment in history. If I run [NSDate date] in Europe at exactly the same time as you run it in America then we'll get exactly the same value.

How you print a date depends on the calendar and the time zone. So a date printed in the Gregorian calendar looks different from the same one printed in the Julian calendar. And a date printed in the UTC Gregorian calendar looks different from the same one printed in the PST Gregorian calendar. But they're still the same date.

So you want to jump straight to your dateFormatter2.

Solution 3

The accepted answer by Alex Wien is incorrect.

By default, NSDateFormatter adjusts the NSDate’s date-time value from UTC to the user's local time zone. To prevent that adjustment, tell the NSDateFormatter to use the time zone for UTC.

To verify results, google "current time utc".

My source code below should do the job, meaning get the current date-time as a string in ISO 8601 format in the UTC (Zulu) time zone signified by a Z on the end.

NSDate* datetime = [NSDate date];
NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]]; // Prevent adjustment to user's local time zone.
[dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"];
NSString* dateTimeInIsoFormatForZuluTimeZone = [dateFormatter stringFromDate:datetime];

You could put this logic in a pair of convenience methods somewhere in your app.

- (NSString*)now
{
    // Purpose: Return a string of the current date-time in UTC (Zulu) time zone in ISO 8601 format.
    return [self toStringFromDateTime:[NSDate date]];
}

…and…

- (NSString*)toStringFromDateTime:(NSDate*)datetime
{
    // Purpose: Return a string of the specified date-time in UTC (Zulu) time zone in ISO 8601 format.
    // Example: 2013-10-25T06:59:43.431Z
    NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]];
    [dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"];
    NSString* dateTimeInIsoFormatForZuluTimeZone = [dateFormatter stringFromDate:datetime];
    return dateTimeInIsoFormatForZuluTimeZone;
}

Example of usage…

NSString* now = [self now];

Or turn those minus signs into plus signs to use as class methods rather than instance methods…

NSString* now = [SomeClassNameHere now];

Tip: For better readability by humans, change that T in the format to a SPACE. For better interoperability by software, keep the T. The ISO 8601 spec tolerates a space but recommends keeping the T.


Tip: I've not tested, but… Some people say instantiating [NSDateFormatter][4] is expensive. If doing so often (such as in a loop) consider caching a single instance for re-use.

Solution 4

PLEASE SET UP Calendar Identifier !!!

I am not too late! Because I saw no one set up the Calendar Identifier. It is really important for worldwide users. Many users using a non-Gregorian calendar. They will get wrong year string. Especially, when you need store it into your own database. (We met this problem before)

NSCalendarIdentifierGregorian
NSCalendarIdentifierBuddhist
NSCalendarIdentifierChinese
NSCalendarIdentifierHebrew
NSCalendarIdentifierIslamic
NSCalendarIdentifierIslamicCivil
NSCalendarIdentifierJapanese
NSCalendarIdentifierRepublicOfChina
NSCalendarIdentifierPersian
NSCalendarIdentifierIndian
NSCalendarIdentifierISO8601

Code:

-(NSString *)getUTCFormateDate:(NSDate *)localDate
{
    NSCalendar *gregorianCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    NSTimeZone *timeZone = [NSTimeZone timeZoneWithName:@"UTC"];
    NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
    [dateFormatter setCalendar:gregorianCalendar];
    [dateFormatter setTimeZone:timeZone];
    [dateFormatter setLocale:locale];
    [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
    NSString *dateString = [dateFormatter stringFromDate:localDate];
    return dateString;
}  

Solution 5

Swift 3

let utcTimestamp = Date().timeIntervalSince1970
print("timeStamp = \(utcTimestamp)")

May following extension would be easier.

Swift 4: UTC/GMT ⟺ Local (Current/System)

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

}


// Try it
let utcDate = Date().toGlobalTime()
let localDate = utcDate.toLocalTime()

print("utcDate - (utcDate)")
print("localDate - (localDate)")
Share:
88,490
williamsandonz
Author by

williamsandonz

Updated on March 14, 2020

Comments

  • williamsandonz
    williamsandonz about 4 years

    I am trying:

    NSDate *currentDateInLocal = [NSDate date];
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:SS.SSS'Z'"];
    NSString *currentLocalDateAsStr = [dateFormatter stringFromDate:currentDateInLocal];
    
    NSDateFormatter * dateFormatter2 = [[NSDateFormatter alloc] init];
    NSTimeZone *timeZone = [NSTimeZone timeZoneWithName:@"UTC"];
    [dateFormatter2 setTimeZone:timeZone];
    [dateFormatter2 setDateFormat:@"yyyy-MM-dd'T'HH:mm:SS.SSS'Z'"];
    NSDate *currentDateInUTC = [dateFormatter2 dateFromString:currentLocalDateAsStr];
    

    but It's still does not represent the current UTC time, how can I achieve this?

    Thanks