Get UTC time and local time from NSDate object

149,894

Solution 1

The documentation says that the date method returns a new date set to the current date and time regardless of the language used.

The issue probably sits somewhere where you present the date using NSDateFormatter. NSDate is just a point on a time line. There is no time zones when talking about NSDate. I made a test.

Swift

print(NSDate())

Output: 2014-07-23 17:56:45 +0000

Objective-C

NSLog(@"%@", [NSDate date]);

Output: 2014-07-23 17:58:15 +0000

Result - No difference.

Solution 2

NSDate is a specific point in time without a time zone. Think of it as the number of seconds that have passed since a reference date. How many seconds have passed in one time zone vs. another since a particular reference date? The answer is the same.

Depending on how you output that date (including looking at the debugger), you may get an answer in a different time zone.

If they ran at the same moment, the values of these are the same. They're both the number of seconds since the reference date, which may be formatted on output to UTC or local time. Within the date variable, they're both UTC.

Objective-C:

NSDate *UTCDate = [NSDate date]

Swift:

let UTCDate = NSDate.date()

To explain this, we can use a NSDateFormatter in a playground:

import UIKit

let date = NSDate.date()
    // "Jul 23, 2014, 11:01 AM" <-- looks local without seconds. But:

var formatter = NSDateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss ZZZ"
let defaultTimeZoneStr = formatter.stringFromDate(date)
    // "2014-07-23 11:01:35 -0700" <-- same date, local, but with seconds
formatter.timeZone = NSTimeZone(abbreviation: "UTC")
let utcTimeZoneStr = formatter.stringFromDate(date)
    // "2014-07-23 18:01:41 +0000" <-- same date, now in UTC

The date output varies, but the date is constant. This is exactly what you're saying. There's no such thing as a local NSDate.

As for how to get microseconds out, you can use this (put it at the bottom of the same playground):

let seconds = date.timeIntervalSince1970
let microseconds = Int(seconds * 1000) % 1000 // chops off seconds

To compare two dates, you can use date.compare(otherDate).

Solution 3

Xcode 9 • Swift 4 (also works Swift 3.x)

extension Formatter {
    // create static date formatters for your date representations
    static let preciseLocalTime: DateFormatter = {
        let formatter = DateFormatter()
        formatter.locale = Locale(identifier: "en_US_POSIX")
        formatter.dateFormat = "HH:mm:ss.SSS"
        return formatter
    }()
    static let preciseGMTTime: DateFormatter = {
        let formatter = DateFormatter()
        formatter.locale = Locale(identifier: "en_US_POSIX")
        formatter.timeZone = TimeZone(secondsFromGMT: 0)
        formatter.dateFormat = "HH:mm:ss.SSS"
        return formatter
    }()
}

extension Date {
    // you can create a read-only computed property to return just the nanoseconds from your date time
    var nanosecond: Int { return Calendar.current.component(.nanosecond,  from: self)   }
    // the same for your local time
    var preciseLocalTime: String {
        return Formatter.preciseLocalTime.string(for: self) ?? ""
    }
    // or GMT time
    var preciseGMTTime: String {
        return Formatter.preciseGMTTime.string(for: self) ?? ""
    }
}

Playground testing

Date().preciseLocalTime // "09:13:17.385"  GMT-3
Date().preciseGMTTime   // "12:13:17.386"  GMT
Date().nanosecond       // 386268973

This might help you also formatting your dates:

enter image description here

Solution 4

a date is independant of any timezone, so use a Dateformatter and attach a timezone for display:

swift:

let date = NSDate()
let dateFormatter = NSDateFormatter()
let timeZone = NSTimeZone(name: "UTC")

dateFormatter.timeZone = timeZone

println(dateFormatter.stringFromDate(date))

objC:

NSDate *date = [NSDate date];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
NSTimeZone *timeZone = [NSTimeZone timeZoneWithName:@"UTC"];

[dateFormatter setTimeStyle:NSDateFormatterMediumStyle];
[dateFormatter setDateStyle:NSDateFormatterMediumStyle];
[dateFormatter setTimeZone:timeZone];       
NSLog(@"%@", [dateFormatter stringFromDate:date]);

Solution 5

let date = Date() 
print(date) // printed date is UTC 

If you are using playground, use a print statement to check the time. Playground shows local time until you print it. Do not depend on the right side panel of playground. enter image description here

This code gives date in UTC. If you need the local time, you should call the following extension with timezone as Timezone.current

 extension Date {

   var currentUTCTimeZoneDate: String {
        let formatter = DateFormatter()
        formatter.timeZone = TimeZone(identifier: "UTC")
        formatter.amSymbol = "AM"
        formatter.pmSymbol = "PM"
        formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"

        return formatter.string(from: self)
    }
}

For UTC time, use it like: Date().currentUTCTimeZoneDate

Share:
149,894
p0lAris
Author by

p0lAris

FFF — Fight for freedom. Fight it right.

Updated on May 07, 2020

Comments

  • p0lAris
    p0lAris about 4 years

    In objective-c, the following code results in the UTC date time information using the date API.

    NSDate *currentUTCDate = [NSDate date]
    

    In Swift however,

    let date = NSDate.date()
    

    results in local date and time.

    I have two questions:

    1. How can I get UTC time and local time (well date gives local time) in NSDate objects.
    2. How can I get precision for seconds from the NSDate object.

    EDIT 1: Thanks for all the inputs but I am not looking for NSDateFormatter objects or string values. I am simply looking for NSDate objects (however we cook them up but that's the requirement).
    See point 1.

  • Hot Licks
    Hot Licks almost 10 years
    One thing to note is that if you examine a date value using the debugger it's apt to be shown in local time, while if you use po to display it while debugging (or simply use NSLog) it will always be shown in UTC.
  • zaph
    zaph almost 10 years
    Actually the time is based on GMT.
  • p0lAris
    p0lAris almost 10 years
    Thanks for that. Apparently, playground shows me local time for some reason. Maybe it's just a bug (IDK). I am simply querying let x = NSDate.date().
  • zaph
    zaph almost 10 years
    Actually the date is based on GMT. If it was not based on a specific time zone it could not be displayed as another time zone.
  • p0lAris
    p0lAris almost 10 years
    Thanks. Also, as I mentioned, I want to compare dates, etc. So I want to have these two time values typed using the NSDate type. Is there a way to do that. NSFormatter doesn't solve any purpose.
  • Steven Fisher
    Steven Fisher almost 10 years
    dateA.compare(dateB);
  • Steven Fisher
    Steven Fisher almost 10 years
    Comparing dates is easy, I've added that. But as your question was regarding the different date you saw, explaining why you saw different dates was important. And NSDateFormatter is the best way to do that. :)
  • Steven Fisher
    Steven Fisher almost 10 years
    Not a bug; just the way it is. You haven't specified the time zone or format, so you get whatever. My guess is that it's current time zone, US medium date format, and US short time format.
  • Daij-Djan
    Daij-Djan almost 10 years
    it is not GMT based I am afraid. If anything you can call it UTC based but for me UTC = zulu time = no timezone. In short the difference UTC vs .GMT is that with GMT, some DaylightSavings time is connected
  • p0lAris
    p0lAris almost 10 years
    @StevenFisher I think I have clearly mentioned this - comparing NSDate objects is easy. I just don't want to deal with NSFormatter or other stuff. So if I can package both utc datetime and local datetime in NSDate objects, it will be easier for me. Please re-read the main question.
  • p0lAris
    p0lAris almost 10 years
    Reiterating: I just want two date objects - one that is responsible for utc time, one for local time (however possible). I understand NSDate but I just don't care about that. I simply want two of these dates packaged as NSDate objects rather than strings or NSFormatter/NSDateFormatter.
  • zaph
    zaph almost 10 years
    Where did you get information "GMT, some DaylightSavings time is connected". Perhaps you are thinking of BST?
  • zaph
    zaph almost 10 years
    From the Apple docs: "the first instant of 1 January 2001, GMT." That is not a unix timestamp which has an epoch of 1 January 1970. UTC did replace GMT and for most purposes, UTC is used interchangeably with GMT.
  • Daij-Djan
    Daij-Djan almost 10 years
    yes that wrong of me and I did remember it wrongly but GMT is not UTC and the date has no timezone ;)
  • Daij-Djan
    Daij-Djan almost 10 years
    UTC is MOSTLY the same as GMT - as I remember it!
  • Steven Fisher
    Steven Fisher almost 10 years
    Again: There's no such thing as a local or UTC NSDate. Compare the two NSDate; it will do what you want. I suggest reading this again, because it sounds like you're still missing the point. :)
  • Hot Licks
    Hot Licks almost 10 years
    You can, of course, put any date/time you want in an NSDate object. It can represent Martian time if you wish. But then you're responsible for keeping track of what it means and being very careful to never use it in a way where the "normal" meaning will be assumed.
  • skymook
    skymook over 9 years
    Yes, not a bug. The description of the NSDate object will show local time zone on your current device in the log, but all dates are GMT or UTC in reality. You settings will then show the log of the date set to the timezone you are in. Which is correct. If I was not at GMT lets say (GMT +1 hour), then the date would show 2014-07-23 16:56:45 +0000 (GMT or UTC) in the log after I created it. In reality, this is 2014-07-23 17:56:45 +0000 (my local timezone). Just imagine they are stored in GTM or UTC and change depending on your timezone.
  • Daij-Djan
    Daij-Djan about 9 years
    That string is what YOU get. By chance :) no formatter and The Output is based on The Locale of The debugger.
  • Ali
    Ali about 9 years
    It's not about the string , it's about getting current date time , and by just instantiating the NSDate as I said YOU will get the current datetime too.
  • Daij-Djan
    Daij-Djan about 9 years
    your string is your local time and that what ticket is about is: "in objective-c, the following code [X} results in the UTC date time information, in swift it results in local date and time. {X}" ==> the debuggers date formatter
  • Steven Fisher
    Steven Fisher almost 9 years
    This in no way answers the question (or, for that matter, shows the fundamental assumptions behind the question are invalid).
  • Jake T.
    Jake T. almost 7 years
    @skymook if the UTC date is 2014-07-23 16:56:45 +0000, the local date is actually 2014-07-23 17:56:45 +0100, the +0100 represents the offset from the UTC time.
  • abhimuralidharan
    abhimuralidharan almost 7 years
    This will give the current timeZone date.Not UTC.
  • mfaani
    mfaani almost 7 years
    is there anyway to ditch the +0000 and still keep the seconds?
  • Steven Fisher
    Steven Fisher almost 7 years
    Just format it how you like. You shouldn't be relying on the date's description anyway.
  • C0D3
    C0D3 about 4 years
    I don't think this answer answers the question asked here. The question asked is how to get a UTC date in iOS and how to get precision seconds from a Date() object.