I am fetching data from the server and part of that data is time. Time is stored in UTC in my DB so what I'm returning is also in UTC. For example: 2014-05-22 05:12:40
Further, I am using the DateTools to show the time difference on the device like X hours ago or X minutes ago etc....
The problem is that when the UTC time coming from the server is compared to the local time there is a huge difference. Something that should say X seconds ago says X hours ago because of the time difference.
Question
How can I convert the date coming from the server to the local time zone set on the device?
This is what I'm doing right now:
#date_formatter = NSDateFormatter.alloc.init
#date_formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
#date_from_server = "2014-05-22 05:12:40"
#date = #date_formatter.dateFromString(#date_from_server)
#time.text = #date.shortTimeAgoSinceNow
I don't know how it is done in ruby motion but in Objective-C, it is done as follows :
1.) Create an instance of NSDateFormatter class
2.) Set a specific date format string of it, and also you set the specific time zone of it
3.) Get a date from the incoming string via the dateformatter instance
4.) Change the time zoneof the date formatter instance to the local time zone
5.) Convert the date obtained previously to the new time zone .
In Objective-C
NSDateFormatter* df = [[NSDateFormatter alloc] init];
[df setDateFormat:incomingDateFormat];
[df setTimeZone:incomingTimeZone]; // Can be set to #"UTC"
NSDate *date = [df dateFromString:incomingDateString];
[df setDateFormat:newDateFormat];
[df setTimeZone:newTimeZone]; //// Can be set to [NSTimeZone localTimeZone]
NSString *newDateStr = [df stringFromDate:date];
I believe the same can be done in Rubymotion too.
NSDateFormatter *formater = [[NSDateFormatter alloc] init];
formater.dateFormat = #"yyyy-MM-dd HH:mm:ss";
NSString *datestr = #"2014-05-22 05:12:40";
formater.timeZone = [NSTimeZone localTimeZone];
NSDate *date = [[formater dateFromString:datestr] dateByAddingTimeInterval:formater.timeZone.secondsFromGMT];
NSDateFormatter *df=[[[NSDateFormatter alloc] init] autorelease];
// Set the date format according to your needs
[df setTimeZone:[NSTimeZone timeZoneWithName:#"America/Toronto"]];
//[df setDateFormat:#"MM/dd/YYYY HH:mm "] // for 24 hour format
[df setDateFormat:#"YYYY-MM-dd HH:mm:ss"];// for 12 hour format
Try this
Related
I have the need to store both local time as per users timezone and UTC time in a transaction table using core data
What I want is as follows
createDate should reflect the users local timezone, in this case I am in China so GMT+8
createDateUtc should represent the same timestamp but in UTC
I have tried various formatters but for some reason I cannot get the result I want
Here are my two formatters as you can see I tried using timezone as well but it still did not set the date to UTC.
NSDateFormatter *dateFormatterWithTz = [[NSDateFormatter alloc] init];
[dateFormatterWithTz setDateFormat:#"yyyy-MM-dd'T'HH:mm:ssZZZZZ"];
NSDateFormatter *dateFormatterUtc = [[NSDateFormatter alloc] init];
[dateFormatterUtc setDateFormat:#"yyyy-MM-dd'T'HH:mm:ssZZZZZ"];
//[dateFormatterUtc setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
here is how I create the date variables
NSDate *createdDateUtc = [NSDate date];
NSDate *createdDate = [NSDate dateWithTimeInterval:[[NSTimeZone systemTimeZone] secondsFromGMT] sinceDate:createdDateUtc];
Here is what the array looks like which is incorrect as you can see it created my Utc date as my local date and pushed the created date to tomorrow and still using the same time offset, the issue should be that my UTC date is set to local time but I cannot figure out how to make it UTC so that my created date gets calculated correctly from that
createdDate = "2016-12-25T03:19:38+08:00";
createdDateUtc = "2016-12-24T19:19:38+08:00";
you need to provide timeZone for date formater
for local timeZone try this
NSDateFormatter *formate =[[NSDateFormatter alloc] init];
[formate setTimeZone:[NSTimeZone localTimeZone]];
[formate setDateFormat:#"yyyy-MM-dd HH:mm:ss a"];
NSString *strToday =[formate stringFromDate:[NSDate date]];
and For UTC timezone set UTC timezone like this
NSDateFormatter *formate =[[NSDateFormatter alloc] init];
[formate setTimeZone:[NSTimeZone timeZoneWithName:#"UTC"]];
[formate setDateFormat:#"yyyy-MM-dd HH:mm:ss a"];
NSString *strToday =[formate stringFromDate:[NSDate date]];
hope this will help you.
I know this it the repeated question. I have reviewed many answers but still didn’t get any solution.
My question is,
How can I get the Time of Device if user have set it manually..?
I have implemented one chatting app. But in this app, I have issues of timings. If user have set manually time then how can we identify that.?
I want to get correct current UTC time. So using this, I can identify the difference between device time and UTC time.
If we are using, NSDate *currentDateAndTime = [NSDate date];, then it returns only UTC time according to device, not the current UTC time.
Is there any easy way to find out this solution?
Any help would be appreciated.
There is no trusted time source in iOS. You just operate with monotonic and non-monotonic time.
Monotonic time (or absolute time) represents the absolute elapsed wall-clock time since some arbitrary, fixed point in the past. The CACurrentMediaTime() or mach_absolute_time return monotonic time.
Non-monotonic time represents the machine's best-guess as to the current wall-clock, time-of-day time. It can jump forwards and backwards as the system time-of-day clock is changed. The [NSDate date] call returns it.
As an option, you can take the trusted date/time from the http Date response header. Then save it and current monotonic time(CACurrentMediaTime()) in the keychain.
Here is the way to get the current trusted time:
last known online time + (CACurrentMediaTime() - saved monotonic time)
Another solution would be to use NTP server.
This might solve your problem
NSDate * date = [NSDate date];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:#"UTC"]];
NSString *currentTime = [dateFormatter stringFromDate:date];
NSLog(#"current time is:%#",currentTime);
use this code it helps you
NSDate * datee = [NSDate date];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"];
NSString *localDateString = [dateFormatter stringFromDate:currentDate];
NSLog(#"%#",localDateString);
Use : NSDate *currentDateAndTime = [NSDate date];
This will get you the absolute date and time in GMT reference zone.
Try this:
swift:
let date = NSDate()
let dateFormatter = NSDateFormatter()
let timeZone = NSTimeZone(name: "UTC")
dateFormatter.timeZone = timeZone
println(dateFormatter.stringFromDate(date))
Obj-C:
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]);
You can use this code for getting current time:-
Swift 3
let date = Date()
let formatter = DateFormatter()
formatter.timeZone = TimeZone(abbreviation: "GMT+0:00") //Current time zone
formatter.dateFormat = "HH:MM a"
let currentTime: String = formatter.stringFromDate(date)
print("My Current Time is \(currentTime)")
Result **
Output : - "My Current Time is 11:05 AM\n"
I receive UTC date from server as 2015-10-07 17:43:11. I want to store this date in NSDate object. I do following code:
NSString *dateFromServer = #"2015-10-07 17:43:11";
NSDateFormatter *formatter = [NSDateFormatter new];
[formatter setDateFormat:#"yyyy-MM-dd HH:mm:ss"];
NSDate *date = [[NSDate alloc] init];
date = [formatter dateFromString:dateFromServer];
NSLog(#"%#", date);
This gives me result as:
2015-10-07 12:13:11 +0000
(I stay in GMT+05:30 zone). How can I store my UTC time (which I receive from the server)directly into the NSDate object?
There are 2 possible solutions:
1. Have the server send the time zone embedded in the date string:
"2015-10-07 17:43:11 UTC"
then parse it with the appropriate date format which will always give you the correct time zone.
2. Otherwise, you'll have to explicitly tell the formatter what is the time zone of the string or it'll use the current time zone of the device by default.
let dateFromServer = "2015-10-07 17:43:11"
let formatter = NSDateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
formatter.timeZone = NSTimeZone(abbreviation: "UTC")
if let date = formatter.dateFromString(dateFromServer) {
print(date) // "2015-10-07 17:43:11"
}
Note:
The NSDate object does not have a time zone - dates are universal and indicate a point in time. To display a date with a time zone you use a formatter to create a locale sensitive string.
Also there's no need to do this:
NSDate *date = [[NSDate alloc] init];
This creates a new date object with the current time. You're overriding this value in the next line.
Try like this ;
NSString *dateFromServer = #"2015-10-07 17:43:11";
NSDateFormatter *formatter = [NSDateFormatter new];
[formatter setDateFormat:#"yyyy-MM-dd HH:mm:ss"];
NSDate *date = [[NSDate alloc] init];
date = [formatter dateFromString:model.start_time];
NSLog(#"%#", date);
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 specifc Timezone: with name
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"];
NSString *localDateString = [dateFormatter stringFromDate:currentDate];
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.
You don't need to covert anything, you only need to consider how to display date in UI, because 2015-10-07 12:13:11 +0000 and 2015-10-07 17:13:11 UTC + 5 are the same NSDate instances.
So if you want to get string representation of the NSDate instance retrieved from server in your local timezone, Just do this.
NSDateFormatter * formatter = [NSDateFormatter new];
formatter.timeStyle = NSDateFormatterStyleMediumStyle;
formatter.dateStyle = NSDateFormatterStyleMediumStyle;
...
You can find more informations about how to format date/time in apple docs.
The output for the actual NSDate object (firstTime) is what I want it to be (the iOS device's time). The NSString object (secondTime) still seems to be showing the GMT time (which is 4 hours ahead of my local time, EST) even though I set the date formatter (df) to the localTimeZone. Why is it not working?
NSDateFormatter *df = [[NSDateFormatter alloc] init];
[df setDateFormat:#"HH:mm:ss"];
[df setTimeZone:[NSTimeZone localTimeZone]];
NSDate *firstTime = [NSDate dateWithTimeInterval:[[NSTimeZone localTimeZone] secondsFromGMT] sinceDate:[NSDate date]];
NSLog(#"%#", firstTime);
NSString *secondTime = [df stringFromDate:firstTime];
NSLog(#"%#", secondTime);
Output:
FIRST TIME: 2014-05-07 17:41:29 +0000, SECOND TIME: 13:41:29
One should let NSDate capture the real date/time, without trying to perform any timezone adjustment, and then let the NSDateFormatter format the string so that it's represented in the desired timezone.
So, looking at your code:
NSDateFormatter *df = [[NSDateFormatter alloc] init];
[df setDateFormat:#"HH:mm:ss"];
[df setTimeZone:[NSTimeZone localTimeZone]];
That's fine, though the setting of the timezone to the local timezone is unnecessary. Date formatters default to the current timezone.
But then you proceed to attempt to grab the current time, and adjust it:
NSDate *firstTime = [NSDate dateWithTimeInterval:[[NSTimeZone localTimeZone] secondsFromGMT] sinceDate:[NSDate date]];
NSLog(#"%#", firstTime);
While I understand why you attempted to do that, this is incorrect. No adjustment for timezone should be performed. So, that assignment of firstTime should be:
NSDate *firstTime = [NSDate date];
NSLog(#"%#", firstTime);
So, if you did this at 5:41pm (eastern), this NSLog will now report 2014-05-07 21:41:29 +0000, but that's correct (because the +0000 indicates that it's showing you the time in UTC/GMT/Zulu).
Then, if you want to display that in the local timezone, you can take this un-adjusted [NSDate date] and use it with your formatter, like you did in your question:
NSString *secondTime = [df stringFromDate:firstTime];
NSLog(#"%#", secondTime);
That will then report 17:41:29, like you expected it to.
An NSDate does not have a time zone. Read that five times until you understand it.
This:
[NSDate date]
Returns the date that means now. It does not have a time zone. It is not in GMT or in any other time zone. It does not have one. Your code:
[NSDate dateWithTimeInterval:[[NSTimeZone localTimeZone] secondsFromGMT] sinceDate:[NSDate date]];
Means a time that isn't now for any user outside GMT. I'll repeat that: your NSDate doesn't describe now. It's like sitting in San Francisco, looking at your watch which is set in the correct local time and it saying 12:00 then telling everybody "that means it is 4AM because we're 8 hours behind GMT".
As a result:
[df stringFromDate:firstTime]
Will build a string that will show a time that isn't now.
Stop thinking you're smarter than everybody that's ever worked at Apple and try this:
NSDateFormatter *df = [[NSDateFormatter alloc] init];
[df setDateFormat:#"HH:mm:ss"];
[df setTimeZone:[NSTimeZone localTimeZone]];
NSString *secondTime = [df stringFromDate:[NSDate date]];
NSLog(#"%#", secondTime);
So that says "give me a string of 'now' in the local time zone". Tell me: does it output the correct thing?
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
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.
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.
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.
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;
}
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)")
[NSDate date] is UTC. Maybe you get fooled by looking in the locals? Then it gets converted to your timezone.
If you see the value in the locals, you see it in local time, but if you print it in the console, you see it in UTC.
When you see '+0000' after the time, you know it is in UTC
Still another way to do it is like so in a C++ class in your Objective C project. (So, make a .mm file and build a C++ class with public and private parts, and stick this in the public part (unless you need it private).) Then, reference it like NSString *sNowUTC = MyClass::getUTCTimestamp();.
static NSString *getUTCTimestamp(){
time_t rawtime;
struct tm * timeinfo;
char buffer [80];
time (&rawtime);
timeinfo = gmtime (&rawtime);
// make format like "2016-06-16 02:37:00" for
// June 16, 2016 # 02:37:00 UTC time
strftime (buffer,80,"%F %T",timeinfo);
std::string sTime(buffer);
NSString *sUTC = #(sTime.c_str());
return sUTC;
}
This is what i used.
static func makeISO8601Date(isoDateString: String) -> Date {
let formatter = DateFormatter()
formatter.calendar = Calendar(identifier: .iso8601)
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
return formatter.date(from: isoDateString)
}
makeISO8601Date(isoDateString: "2017-12-31T23:59:59+00:00")