Why is my NSDate timezone incorrect? - ios

Here's the code:
NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:#"UTC"]];
[dateFormatter setDateFormat:#"yyyy-MM-dd'T'HH:mm:ss'Z'"];
NSDate* newTime = [dateFormatter dateFromString:#"2011-10-19T12:22:07Z"];
[dateFormatter setTimeZone:[NSTimeZone systemTimeZone]];
[dateFormatter setDateFormat:#"dd-MMM-yyyy HHmm"];
NSString* finalTime = [dateFormatter stringFromDate:newTime];
The problem:
I'm in Toronto (EST, GMT-5). My final time SHOULD show 0722, I'm seeing 0822. Inspecting the objects I can see that newTime is '2011-10-19 08:22:07 EDT'. I'm not sure why that happens but it persists onto the finalTime string despite setting the dateFormatter time zone to systemTimeZone. I assume systemTimeZone is EDT then? Any insight into why this happens or how I can correct it would be greatly appreciated.
Thanks in advance.

You're currently in Toronto EST. This time report you are getting back is showing EDT. Which is Eastern Daylight Time. Make sure you subtract an hour for daylight savings time since it's EDT not EST.
I'm out right now so I can't test this code but I think this should work:
NSDate *currentDate = [NSDate date];
NSTimeZone *currentZone = [NSTimeZone localTimeZone];
if ([currentZone isDaylightSavingTimeForDate:currentDate]) {
//adjust the time by 1 hour here
}

A few things:
Don't set the timezone on the date formatter. And then remove the quotes around the Z in the format string. This will allow the date formatter to determine the timezone from the actual date string.
The output of 0822 is correct for your system timezone because you were on day light savings time on October 19th. On that date you were GMT-4, not GMT-5. In Canada, in 2011, DST ended on November 6th.

Related

Convert 12 hr to 24

I'm converting 12 hour date to 24 here, but it failed to get perfect time.
Here is code :
NSString *dateStr = #"2016-08-12T04:10:14.915Z";
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"yyyy-MM-dd'T'hh:mm:ss.SSS'Z'"];
[dateFormat setTimeZone:[NSTimeZone localTimeZone]];
NSDate *date = [dateFormat dateFromString:dateStr];
and my final date is
2016-08-11 22:40:14 +0000
How ?
The NSDate object that you are getting is GMT. In France GMT -2, if I run your code I have a time of 02:10.
Am I correct assuming your GMT offset is -5:30 ?
NSDate objects don't have time zones; they represent an absolute
moment in time. However, when you ask one for its description (by
printing it in an NSLog, e.g.), it has to pick a time zone. The most
reasonable "default" choice is GMT. If you're not in GMT yourself, the
date will seem to be incorrect, by the amount of your own offset.
You should always use an NSDateFormatter, setting its timezone to
yours, before displaying a date.
Don't trust what NSLog or the debbuger are telling you about a NSDate.
use
NSString dateAsString = [dateFormat stringFromDate:date];
to check your date :)

Convert NSString to NSDate Using NSDateFormatter

trying to convert NSString to NSDate
NSString *startDateForCal='09-03-2016 08:00:00 AM'
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat: #"dd-MM-yyyy HH:mm:ss a"];
NSDate * EventStart = [dateFormatter dateFromString: startDateForCal];
But getting mixed result as "2016-03-09 18:30:00 +0000" returning date as correct but time didn't match with string It would be welcome any suggestions
Thank you
it should be
[dateFormatter setDateFormat: #"dd-MM-yyyy hh:mm:ss a"];
i.e. no capital HH for hour. HH return the Hour in 24 format
For more details Click now
and regarding the error in date,
since you have set the time format wrong( as HH instead of hh), it took the time as 12:00 AM and showed it in GMT timezone(IST - 5 and half hours, so in your case 12:00 AM - 5:30 = 18:30 of previous day), i guess you haven't set the locale properly.
setting the locale(in swift),
dateFormatter.locale = NSLocale(localeIdentifier:"en_IN")
Your question makes no sense. Your goal was to obtain an NSDate from an NSString. You did that, and you did it successfully.
How you discover what that NSDate is, is a completely different matter. It is represented to you by default (in the console) in a certain time zone and format. But that is irrelevant; it is still the same date, and it is the correct date.

How does NSDate seem to know it's TimeZone?

I'm somewhat confused about how these two NSDate objects seem to know which timezone they are in. I was under the impression that an NSDate object only stored a point in time and no information about the timezone.
I'm creating and logging two dates like this:
NSString* timeString = #"6:04 PM";
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setLocale:[NSLocale localeWithLocaleIdentifier:#"en_US_POSIX"]];
[dateFormatter setDateFormat:#"h:mm a"];
NSDate *time = [dateFormatter dateFromString:timeString];
NSDateFormatter *currentFormatter = [[NSDateFormatter alloc] init];
[currentFormatter setTimeStyle:NSDateFormatterLongStyle];
NSLog(#"%#", [currentFormatter stringFromDate:time]);
NSLog(#"%#", [currentFormatter stringFromDate:[NSDate date]]);
This produces the output:
18:04:00 GMT
11:12:36 BST
How does it know that the first date is GMT and the second is BST?
(It's British Summer Time here. Your mileage may vary in that respect)
You're right, NSDate doesn't have a time zone. Your results don't contradict that, because you're not printing the dates-- you're printing a subset of the date information produced by passing them through a date formatter. Your currentFormatter only returns time of day information, not date information. If you add this line:
[currentFormatter setDateStyle:NSDateFormatterLongStyle];
Then the results will look something like:
January 1, 2000 at 6:04:00 PM MST
September 30, 2015 at 11:14:39 AM MDT
In other words, they show up with different time zones because they're on different dates, and the time zone reflects what's in effect on that date. In my case it's currently MDT but on Jan 1 2000 it would have been MST.

What is the correct way of showing a timestamp in device timezone?

I've this timestamp : 1439353372
This was generated when one of our user (from Canada) sent me a message (in India).
Inside our app – He is seeing following time for that message : 2015-08-11 / 22:22pm and I'm seeing this 2015-08-12 / 09:52am. He's seeing this in his iPhone6 and I'm on iPhone6+ simulator.
I think this time is wrong – I'm having so much confusion regarding this timestamp/timezone and dates conversion.
Below is our code to convert timestamp to date and showing it in above format.
NSDateFormatter *df = [[NSDateFormatter alloc] init];
[df setDateFormat:#"yyyy-MM-dd"];
NSDate *date = [NSDate dateWithTimeIntervalSince1970:1439353372];
NSString *strDate = [df stringFromDate:date];
[df setDateFormat:#"HH:mm a"];
NSString *strTime = [df stringFromDate:date];
NSLog(#"%#",[NSString stringWithFormat:#"%# / %#", strDate, strTime]);
I'm not sure this is the correct way of showing date for particular timestamp in user's region?
What should I add in above code such that it'll always show us proper time as per our device time zone?
When you create the timestamp, add the local time zone:-
NSTimeZone *localTimeZone = [NSTimeZone systemTimeZone];
[df setTimezone: localTimeZone];
While retrieving the timestamp, do the same approach so that you get the proper date and time according to your time zone.
EDITED:-
This is how you add time zone to your datestamp, just found it from this Source as I don't have the time right now to write the code
NSDate* referenceDate = [NSDate dateWithTimeIntervalSince1970: 0];
NSTimeZone* timeZone = [NSTimeZone systemTimeZone];
int offset = [timeZone secondsFromGMTForDate: referenceDate];
int current = unix_timestamp - offset;
Ok, I've found that, the above date and time is correct. In GMT, if you convert above timestamp to NSDate you'll get following result: 2015-08-12 / 04:22pm. So for Canada timezone is GMT-6 (6 hours back from 2015-08-12 / 04:22pm time) and India is GMT+5.30 (5.30 hours ahead from 2015-08-12 / 04:22pm time). So the result in the question I asked is seems to be pure :)

iOS 7: Convert NSDate to string with custom timezone and get back new NSDate

I wish to modify current system time (set a custom NSTimeZone) and get back a new NSDate object.
The code I've made
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyy-MM-dd HH:mm:ss Z"];
NSLog(#"System time: %#", [dateFormatter stringFromDate:[NSDate date]]);
[dateFormatter setTimeZone:[NSTimeZone timeZoneWithName:#"Asia/Aqtobe"]];
NSString *dateString = [dateFormatter stringFromDate:[NSDate date]];
NSLog(#"Aqtobe time: %#", dateString);
The output
System time: 2014-02-05 10:00:46 +0000
Aqtobe time: 2014-02-05 15:00:46 +0500
But if I try to get new NSDate object from Aqtobe time:
NSLog(#"New NSDate: %#", [dateFormatter dateFromString:dateString]);
I get
New NSDate: 2014-02-05 10:02:40 +0000
Where I was wrong? Thanks in advance
NSDate always returns date in GMT +0:00.
So, it (NSDate object) always have correct converted value but in GMT +0:00.
So for using it as text you will always have to use same date formatter with same zone.
If you want to use date as string from date in other places (out of dateformatter object scope), it is better to make special method for conversion.
It is explained clearly below with example:
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.dateFormat = #"yyyy-MM-dd HH:mm:ss Z";
NSLog(#"System time: %#", [dateFormatter stringFromDate:[NSDate date]]);
[dateFormatter setTimeZone:[NSTimeZone timeZoneWithName:#"Asia/Aqtobe"]];
NSString *dateString = [dateFormatter stringFromDate:[NSDate date]];
NSLog(#"Aqtobe time: %#", dateString);
// date will always contain value in GMT +0:00
NSDate *date = [dateFormatter dateFromString:dateString];
NSLog(#"New NSDate (NSDate): %#", [dateFormatter stringFromDate:date]);
// converts date into string
NSLog(#"New NSDate (NSString): %#", [dateFormatter stringFromDate:date]);
For detailed explaination you can refer this question: Does [NSDate date] return the local date and time?
NSDate has many methods for comparing date such as isEqualToDate: (for a more detailed of the methods and usage you can see this SO question).
This method, that I took from here, will let you determine if date is between firstDate and lastDate.
- (BOOL)isDate:(NSDate *)date inRangeFirstDate:(NSDate *)firstDate lastDate:(NSDate *)lastDate {
return [date compare:firstDate] == NSOrderedDescending &&
[date compare:lastDate] == NSOrderedAscending;
}
I hope this is what you meant. If not please explain exactly what you're trying to do.
You can use NSDateComponents and NSCalendar to create a new date. From the Date and Time Programming Guide
Creating Dates with Time Zones
Time zones play an important part in determining when dates take
place. Consider a simple calendar application that keeps track of
appointments. For example, say you live in Chicago and you have a
dentist appointment coming up at 10:00 AM on Tuesday. You will be in
New York for Sunday and Monday, however. When you created that
appointment it was done with the mindset of an absolute time. That
time is 10:00 AM Central Time; when you go to New York, the time
should be presented as 11:00 AM because you are in a different time
zone, but it is the same absolute time. On the other hand, if you
create an appointment to wake up and exercise every morning at 7:00
AM, you do not want your alarm to go off at 1:00 PM simply because you
are on a business trip to Dublin—or at 5:00 AM because you are in Los
Angeles.
NSDate objects store dates in absolute time. For example, the date
object created in Listing 16 represents 4:00 PM CDT, 5:00 EDT, and so
on.
Listing 16 Creating a date from components using a specific time zone
NSCalendar *gregorian=[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar
[gregorian setTimeZone:[NSTimeZone timeZoneWithAbbreviation:#"CDT"]];
NSDateComponents *timeZoneComps=[[NSDateComponents alloc] init]; [timeZoneComps setHour:16];
//specify whatever day, month, and year is appropriate
NSDate *date=[gregorian dateFromComponents:timeZoneComps];
If you need to create a date that is independent of timezone, you can store the
date as an NSDateComponents object—as long as you store some reference
to the corresponding calendar.
In iOS, NSDateComponents objects can contain a calendar, a timezone,
and a date object. You can therefore store the calendar along with the
components. If you use the date method of the NSDateComponents class
to access the date, make sure that the associated timezone is
up-to-date.
Anyway, keep in mind that a date is a unique point in time. What you display to the user is different based on their locale and time zone.

Resources