How to get/convert UTC date from local Date in OSX? - objective-c

I need to get UTC date by specified NSDate.
The problem is that utcDate doesn't calculates properly if date was in daylight saving period.
Here is a code I use:
NSDate *localDate = [updatesInfo objectForKey:#"date"];
NSTimeInterval timeZoneOffset = [[NSTimeZone defaultTimeZone] secondsFromGMT];
NSTimeInterval gmtTimeInterval = [localDate timeIntervalSinceReferenceDate] - timeZoneOffset;
NSDate *utcDate = [NSDate dateWithTimeIntervalSinceReferenceDate:gmtTimeInterval];
UPD:
I read localDate from /Library/Receipts/InstallHistory.plist It's an OSX file which contains all application's installation history.
https://www.dropbox.com/s/3pc178avr4pj7uj/1.png?dl=0

NSDate is in UTC. Always.
The code that you posted seems to indicate that your "updatesInfo" contains an incorrect NSDate. Or at least you think it contains an incorrect date.
You may have made a mistake when you created the date. As a partial workaround, you can try using secondsFromGMTForDate: which will be correct most of the time, except for some dates very close to the point where DST changed (because the date you have isn't correct). You can improve on that:
NSTimeInterval timeZoneOffset = [[NSTimeZone defaultTimeZone] secondsFromGMTForDate:localDate];
NSDate* betterDate = [localDate dateByAddingTimeInterval: -timeZoneOffset];
timeZoneOffset = [[NSTimeZone defaultTimeZone] secondsFromGMTForDate:betterDate];
NSDate* utcDate = [localDate dateByAddingTimeInterval: -timeZoneOffset];

A property list file stores a date in UTC. If you open the file in a plain text
editor you will see something like
<key>date</key>
<date>2014-07-08T09:30:15Z</date>
which is "2014-07-08 09:30:15 UTC". Therefore
NSDate *date = [updatesInfo objectForKey:#"date"];
should contain the correct date and there is no need to adjust that for your local
time zone.
But note that the Xcode property list editor displays the date stored in the property list file according to your local time zone. And if you edit a date field in Xcode,
it will be translated back to UTC for storage in the plist file.

Related

DateTime conversion in iOS when device's timezone change

I get time in EDT from my server in format yyyy-MM-ddTHH:mm:ss for instance 2014-05-21T09:30:00. I convert these to NSDate and save in sqlite on iphone using code below
NSString *strDate = #"2014-05-21T09:30:00";
NSDateFormatter *df = [[NSDateFormatter alloc] init];
[df setTimeZone:[NSTimeZone timeZoneWithName:#"EDT"]];
[df setDateFormat:#"yyyy-MM-dd'T'HH:mm:ss"];
NSDate *date = [df dateFromString:strDate];
It works fine until I change the timezone on the device. If I change time on device time gets messed up. Any idea what am I doing wrong here?
Device's timezone is Eastern and I save 8:00AM
I change device's timezone to Pacific and time changes to 5:00AM
I have an update process that updates all datetime values again and it goes back to 8AM
I now change device's timezone to Eastern and time goes to 11AM
I run the update process again and time goes back to 8AM
How can I save these times so no matter which timezone users is in, they always see eastern time.
Thanks,
D.
NSDate itself doesn't know about timezone; it's just a simple wrapper around a double value, which represents the number of seconds since some fixed time (I think Jan 1 2001 or something) UTC.
What you need is a NSDateFormatter, similar to the one you use to parse the date, to transform the NSDate into an NSString using the EDT timezone.

IOS6 Incorrect TimeZone while converting date from string to NSDate

My date is in the format
2013-07-16T07:40:36.939-04:00
When I convert it into a NSDate
the date is in the format IST or GMT +5:30 as I am in India. How should I make it use -4:00 as the timezone and display EST or PDT as per the number. if I use zzz, it returns GTM+5:30 and zzzz returns Indian Standard Time. This is my way
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyy-MM-dd'T'HH:mm:ss.SSSzzz"];
NSDate *date = [dateFormatter dateFromString:strDate];
You need to set the formatted locale to en_US_POSIX to force it to use the supplied timezone instead of the system timezone:
[dateFormatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:#"en_US_POSIX"]];
You're parsing the date string correctly (in iOS 6 and later; this is not date format recognized in iOS 5 which recognizes -0400 or GMT-04:00, but not -04:00). Unfortunately, NSDate objects do not have a "time zone", so that information is not captured by the NSDateFormatter.
If you really want to capture the original timezone, I think you may have to manually parse the string for those last few characters (the -04:00), determine the timezone offset from that, and store this in a separate field and when outputting the date, use this separate time zone offset to set the timeZone property of your date formatter accordingly. Or if you really want to represent the original date, you could reformat this ISO8601 date string as human-friendly string and keep this pretty string (as well as the NSDate object, presumably).
BTW, splitting hairs, but you might want to be wary about assuming that -04:00 will represent EDT because (a) it depends upon the time of the year; and (b) there are other timezones that are also -04:00 (e.g. there are a bunch of South American timezones that are also -04:00).
Generally apps avoid this problem altogether by (a) converting the date strings to NSDate objects; and (b) output these NSDate objects using the timezone and locale of the device that the app is running on.

NSDateformatter Converting date to string

I am having the following date and time 2013-04-25 10:42:44 +0000. When i convert the above date to string, i am getting the output as 2013-04-25 16:12:44. Following is the code i am using to convert the date to string
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];
dateFormatter.timeZone = [NSTimeZone systemTimeZone];
[dateFormatter setDateFormat:#"yyyy-MM-dd HH:mm:ss"];
NSString *dateStr= [dateFormatter stringFromDate:date]];
NSLog(#"dateStr--%#",dateStr);
This gets asked over and over (but is difficult to find via search).
When you log an NSDate object, you will always get the date in UTC format. This is how the description method of NSDate is currently implemented.
As long as the difference you are seeing can be accounted for based on your local timezone relative to UTC, then what you are seeing it correct and expected behavior.
BTW - there is no reason to set the date formatter's timezone to the "system" timezone. This is already done by default. Same for the locale. Only set the timezone or locale if you want something different from the current values.
I guess it's a timezone issue. Set your formatters time zone to GMT:
dateFormatter.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
I assume the variable date gets initialized via [NSDate date].
Maybe the quite extensive answer in the follwing topic is helpful here, too.
Does [NSDate date] return the local date and time?

Remove time from NSDate object and save it in NSDate not in string?

There are lot of questions about date and time, but my question is a bit different.
Why NSDate comes with times added to it?
Why can not time be removed from NSDate? I can remove the time but it needs to be saved in String, Why it is not allowed to save it in NSDate?
NSDate actually stores a number of seconds from reference date (Jan 1, 2001). Everything rest are calendar calculations based on this amount of seconds. If you truncate time components and store result as 'NSDate' you will have different dates on different time zones.
You should consider using NSDateFormatter to convert NSDate values to string. Use:
[formatter setDateStyle:NSDateFormatterMediumStyle];
[formatter setTimeStyle:NSDateFormatterNoStyle];
to setup date formatter to ignore time.
Is this what you were looking for?
func dayOf(date: NSDate) -> NSDate {
return NSCalendar.currentCalendar().dateBySettingHour(0, minute: 0, second: 0, ofDate: date, options: NSCalendarOptions())!
}
A reusable way to solve this problem in swift is writing an extension on NSDate to trim the time off of the object.
import Foundation
extension NSDate {
func trimTime() -> NSDate {
let cal = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)!
let components = cal.components([.Day, .Month, .Year], fromDate: self)
return cal.dateFromComponents(components)!
}
}
This is not possible to remove TimeStamp from NSDate. NSDate is always packed with timestamp.
NSDate is based on the UTC time zone. If it is 1AM in US, it will be 12:30 PM in some other country and the date will be different. It will become trouble to get who entered when if different dates are there. So to make the date consistent timestamp-ing is required.
EDIT:
UTC update as suggested by Zaph :)
tiemstamp as suggested by Daij-Djan
NSDate is a presentation way of time stamp, you can get different date with different timezone of the same NSDate object, so you cannot just save the "date" part of NSDate object, that's not the way NSDate works.
If you don't want time present in date string, just format it without time.
My suggestion is save time stamp in your database, if you need to find certain date, use a range query, that way you can deal with timezone problem.
Timezone function is hard to implement with date field.

NSDateFormatter dateFromString returns incorrect date [duplicate]

This question already has answers here:
Get NSDate from NSDate adjusted with timezone
(2 answers)
Closed 9 years ago.
I am trying to use NSDateFormatter in my app which takes a date string and formats it to an NSDate so that I can do Date Comparisons, however I am finding when I use dateFromString and format it the date is losing one day.
NSString *dateString = #"02-06-2012";
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"dd-MM-yyyy"];
NSDate *dateFromString = [[NSDate alloc] init];
dateFromString = [dateFormatter dateFromString:dateString];
NSLog(#"My Date = %#", dateFromString);
[dateFormatter release];
This outputs to the console:
My Date = 2012-06-01 23:00:00 +0000
Try adding this lines to your code,
[dateFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:#"GMT+0:00"]];
or
[dateFormatter setTimeZone:[NSTimeZone timeZoneWithName:#"GMT"]];
SWIFT update :
Code from quetion,
let dateString = "02-06-2012"
var dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "dd-MM-yyyy"
var dateFromString : NSDate = dateFormatter.dateFromString(dateString)!
println("My Date \(dateFromString)")
And Solution ,
dateFormatter.timeZone = NSTimeZone(name: "GMT")
OR
dateFormatter.timeZone = NSTimeZone(abbreviation: "GMT+0:00")
I don't believe that Dhruv's answer is correct. In fact, it's not clear there's any problem at all. You just seem to have an incorrect expectation of what should happen and/or interpretation of what's happening.
NSDate represents a moment in time. This moment does not have one unique name. It will be known by different names in different places and under different naming systems (time zones, calendars). NSDate doesn't deal with any of this, except lamely in its -description method, where it has to produce a string representation of that moment.
Second, a string like "02-06-2012" doesn't specify a precise moment in time. First of all, it's just a date with no time information, so NSDateFormatter just defaults to the first moment for that date. Second, it doesn't specify the time zone. The first moment of the calendar day is a different moment in each time zone. Unless you specify a time zone with -setTimeZone: or the string itself carries time zone information, NSDateFormatter assumes that any date strings you ask it to parse are in the current time zone.
So, your dateFromString object represents the first moment of the specified date, 02-06-2012, in your time zone. I expect this is what you wanted. However, you then got confused by the way that NSDate describes itself when logged. As I said, NSDate has to pick some "name" (string representation) for the moment it represents and which name it picks is fairly arbitrary. These days it is picking the name that the moment is known by in UTC. I gather from the log output shown in your question that you are located at UTC+0100. So, the date may look like it's one day earlier but it really is the same moment you specified. In other words, "2012-06-01 23:00:00 +0000" and "2012-06-02 00:00:00 +0100" are two equivalent names for exactly the same moment in time. You just aren't used to seeing the first one and misinterpreted it.
The lesson is that you have to stop relying on NSDate's self-description to be in any particular time zone. Really, you have to not rely on anything about it, since it's not documented. In fact, the docs for -[NSDate description] state, "The representation is not guaranteed to remain constant across different releases of the operating system."
Dhruv's solution seems to help merely because it causes NSDateFormatter and -[NSDate description] to agree on the time zone. But that's unreliable. It wouldn't work on Snow Leopard, for example, because -[NSDate description] used the local time zone instead of UTC in that version of the frameworks.
More importantly, though, it alters the actual moment represented by the NSDate object you get from NSDateFormatter's interpretation of your date string. I suspect you really want that to have a specific meaning – you want the string to be interpreted as being in the local time zone – and his solution thwarts your intent.
tl;dr: you were getting the date you wanted all along; don't rely on -[NSDate description]; don't use Dhruv's solution