Objective-c NSDateFormatter timezone reverts to GMT - objective-c

I am playing about with some timezone calculations and I have noticed quite an annoying error which is causing me problems.
If I create a date, use NSDateformatter to convert it to a certain time zone, retrieve that string, and then use dateformatter to convert the string back into a date object, it keeps reverting to my local GMT time.
Example
NSDate *date = [NSDate date];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyy-MM-dd HH:mm:ss zzz"];
[dateFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:#"COT"]];
NSString *str = [dateFormatter stringFromDate:date];
NSLog(#"%#", str);
//prints 2015-02-04 10:33:45 GMT-5
NSDate *newDate = [dateFormatter dateFromString:str];
NSLog(#"%#", newDate);
//Prints 2015-02-04 15:33:45 +0000
Why does it keep reverting back to GMT? I need that date object to accurately reflect the time zone I have set the dateformatter to for some testing purposes, so this is quite a frustrating issue.
Any help would be much appreciated

I believe that the problem is that NSDate itself (i.e. the value you're logging at the end) doesn't have a time zone - it's just a moment in time. You're specifying the time zone *when formatting the value using stringFromDate*, and you're still using that when you *parse* the value back to anNSDate... but theNSDate` value itself doesn't remember the time zone.
To give a different example, imagine you had an IntegerFormatter for NSInteger, which let you say whether you wanted to format and parse in hex or decimal. You could format the decimal value 16 to 0x10, and then parse that value back... but the NSInteger wouldn't "remember" that it was parsed from hex. It's exactly the same here - the time zone plays a part in the parsing (at least when the value itself doesn't specify the time zone) but it isn't part of the result in itself.
I need that date object to accurately reflect the time zone
Then you need to keep the time zone separately alongside the NSDate, basically... (Looking at the documentation, it sounds like NSCalendarDate did what you want, but that's deprecated.)

Related

nsdate from picker to string and back to date, eventually passed to another controller

uidate picker has proper user zone set.
NSDate *date= Uidatepicker.date;
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateStyle:NSDateFormatterMediumStyle];
[dateFormatter setTimeZone:[NSTimeZone localTimezone]];
//show correct date and time
NSString *string=[dateFormatter stringFromDate:date];
//back to date
NSDate *outDate=[dateFormatter dateFromString:string];
The outdate is passed to another controller and eventually used to query db using time since 1970. The date used in the query has +4 hours (GMT time). I think it should have localtime. I know the NSdate has no timezone but I need the correct time for the db query. The db seems to have correct time since 1970 (based on local time). I am converting to string to check in this case as time is off by +4 hours.
Any suggestions and appreciate your help.

Convert to NSDate from NSString: How to ignore the timezone

I am converting an NSString with a date format of 2012-06-30 into an NSDate using the following code:
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyy-MM-dd"];
NSDate *date = [dateFormatter dateFromString:dateString];
When omitting [dateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]] the value in NSString is 2012-06-29 23:00:00 plus some automatically added time zone information, which indicates that the the system has some assumptions about the current time zone.
The conversion works fine when I set the time zone with the method above.
However, what would happen if the user is in a different time zone?
How can I make sure that iOS parses just the date as it is and does not add any time information?
The data will not change, timezones dont affect that date itself, it just affect the date presentation, so a date that says 13:00 GMT will have the same presentation of a date that is 14:00 GMT +1
You shouldnt care about the timezones, instead for date conversion to the current time zone of the device use
[dateFormatter setTimeZone:[NSTimeZone systemTimeZone]];
This will set the time zone of the device

6 hours being added to NSDate object when using NSDateFormatter

I am trying to format a date object and I am noticing on the string I am passing in; 6 hours is being added to my time. This seems to be associating my date time object to GMT.
My code:
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"yyyy-MM-dd h:mm:ss a"];
[formatter setTimeZone:[NSTimeZone systemTimeZone]];
NSDate *date = [formatter dateFromString:#"2012-02-01 03:38:12 AM"];
NSLog(#"%#", date);
The result is:
2012-02-01 09:38:12 +0000
I have tried this with and without the setTimeZone and it does not matter. Any ideas on why this is displaying as GMT time?
Thanks,
Flea
The date that your formatter creates is not associated with any timezone, but the description method of NSDate (which is what NSLog uses for the output) converts any date to UTC. You would have to use another (or the same) date formatter's stringFromDate: method to print it with a different time zone.
All NSDates are absolute times, meaning that 3:00 AM central time in the United States is 9 AM UTC. I suspect that your systemTimeZone is central time in the United States.
NSLog always shows times in UTC.
If you want to see, as a string, what the time is in your time zone, then you can use the same date formatter stringFromDate: method, and make the you set the time zone of the date formatter to that time zone.
NSLog date formatting is an annoyance because it leads to the kind of confusion you are experiencing.

Convert NSDate from GMT+0 (London) to User's TimeZone

I have a NSString (date) retrieved from my MySQL database which is in GMT +000 (London) and its format is like this: 12/05/2011 5:21:29 PM.
I would like to know how I could convert it to the user's time zone so that if the user was in china for example, it would be that date in the chinese time zone.
Use setTimeZone: on your input NSDateFormatter. (Internally, NSDates are time zone agnostic.)
E.g.:
// The default time zone for a formatter is the time zone of the user's locale
NSDateFormatter *localFormatter = [[NSDateFormatter alloc] init];
[localFormatter setDateStyle:NSDateFormatterShortStyle];
[localFormatter setTimeStyle:NSDateFormatterMediumStyle];
NSDateFormatter *gmtFormatter = [[NSDateFormatter alloc] init];
[gmtFormatter setDateFormat:#"MM/dd/yyyy h:mm:ss a"];
[gmtFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
NSDate *date = [gmtFormatter dateFromString:gmtDateString];
NSString *locallyFormattedDate = [localFormatter stringFromDate:date];
[localFormatter release];
[gmtFormatter release];
Although…I don't think this takes DST into account if the DST setting during the specified time is different than the current setting.
Use initWithTimeInterval:sinceDate: to make a date object that adds/subtracts hours. It will be in seconds, so 3 hours ahead would be initWithTimeInterval:10800 sinceDate:(originalDate). The format that would be given if you called -description on that object would be given as (from Apple Documentation)
A string representation of the
receiver in the international format
YYYY-MM-DD HH:MM:SS ±HHMM, where ±HHMM
represents the time zone offset in
hours and minutes from GMT (for
example, “2001-03-24 10:45:32 +0600”).
So it would include the time interval.
EDIT:
Sorry I was using the wrong init method, that is the one you are looking for, initWithTimeInterval:sinceDate:. You make a new NSDate that adds or subtracts the number of seconds that the timezone is ahead/behind.

Keep original time zone with NSDateFormatter

I have strings like 2011-01-19T20:30:00-5:00 and I'd like to parse them into an NSDate but I want to keep the original time zone.
NSDateFormatter *dateFormatter = [NSDateFormatter new];
[dateFormatter setDateFormat: #"yyyy-MM-dd'T'HH:mm:ssZ"];
NSLog(#"%#", [dateFormatter dateFromString: dateString]);
[dateFormatter release];
That snippet gives me 2011-01-20 02:30:00 +0100 which is also correct but I wish to keep the original time zone -0500 instead of my local time zone +0100 in the NSDate.
First of all, you should be aware that NSDate objects don't store anything related to their locales or timezones, and internally they're essentially represented as a number of seconds since the first instant of 1 January 2001, GMT.
If you are able to the timezone for the string in an NSTimezone object, just do the following before doing dateFromString:
[dateFormatter setTimeZone:timezoneForString];
and you'll be set.
If you're unable to get an NSTimezone and all you have is a string "2011-01-19T20:30:00-5:00", there isn't a very good way to get to an NSTimezone from the -5:00, since there isn't always an unambiguous way to get a timezone ID (e.g., "America/Los_Angeles") or timezone name (e.g., "Pacific Daylight Time") from an UTC offset. So you'd have to write your own code to manually extract the offset, store it, and add it to the time before displaying it.