Get NSDate from NSDate adjusted with timezone

Solution 1:

NSDate only represents an absolute point in time. It has no concept of timezone or calendar. When you create a NSDate instance it is just a number of seconds since January 1st 2001 GMT! It does not matter if you are in New York, Tokyo, Barcelona or Jerusalem.

At your example, you instance the NSDate based on GMT, but [date description] (used in NSLog) translates it into your local time. There you have the mismatch.

So there are two parts to consider:

1. NSDate creation using NSCalendar and NSTimeZone

If you are creating a date manually you should specify the calendar (2012 in Gregorian, but 5772 in Hebrew) and time zone (22PM London time, but 7AM Sydney time).

// Use the user's current calendar and time zone
NSCalendar *calendar = [NSCalendar currentCalendar];
[calendar setTimeZone: [NSTimeZone systemTimeZone]];

// Specify the date components manually (year, month, day, hour, minutes, etc.)
NSDateComponents *timeZoneComps=[[NSDateComponents alloc] init];
[timeZoneComps setHour:22];
[timeZoneComps setMinute:0];
[timeZoneComps setSecond:0];
// ... year, month, ...

// transform the date compoments into a date, based on current calendar settings
NSDate *date = [calendar dateFromComponents:timeZoneComps];

At this point date stores the exact point in time (in seconds) representing the current calendar.

2. NSDate output using NSDateFormatter

For a controlled output of your NSDate you need NSDateFormatter, which is used to convert dates into strings.

Based on Apple NSDateFormatter Class Reference documentation

There are many attributes you can get and set on a style date formatter, ... You are encouraged, however, not to change individual settings. Instead you should accept the default settings established on initialization and specify the format using setDateStyle:, setTimeStyle:

This is specially important for the output, which is different for every locale. By default NSDateFormatter observes the current user’s locale settings. So the same NSDate could be 22.11.2011 18:33:19, or Nov 22, 2011 6:33:19 PM, or 2011-11-22 下午6:33:19 or even २२-११-२०११ ६:३३:१९ अपराह्, all for the same input and with the same code.

And the code:

//  NSDate *date -> NSString *dateString 

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateStyle:NSDateFormatterMediumStyle];
[dateFormatter setTimeStyle:NSDateFormatterShortStyle];

// Medium style date, short style time => "Nov 23, 1937 3:30pm"
NSString *dateString = [dateFormatter stringFromDate:date];

Or you could transform it using the class method localizedStringFromDate:dateStyle:timeStyle:

I hope this clarifies the problem.

Solution 2:

[NSDate date] returns the date in GMT.

When you state:

That date translates into "2011-09-30 22:00:00" because of my timezone.

Is that from NSLog or NSDateFormatter? Don't rely in [date description] which NSLog uses, it takes into account your local timezone, use NSDateFormatter. NSDateFormatter has a setTimeZone method.

From Apple docs on [date description]:

The representation is not guaranteed to remain constant across different releases of the operating system. To format a date, you should use a date formatter object instead