7

I want to convert a NSDate from one timezone to another.

Here is my code:

NSDate* convertTime(NSDate* fromDate, NSTimeZone* fromTimeZone, NSTimeZone* toTimeZone) {
    if (fromTimeZone == toTimeZone) {
        return fromDate;
    }

    NSCalendarUnit val = NSCalendarUnitYear| NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour| NSCalendarUnitMinute | NSCalendarUnitSecond | NSCalendarUnitTimeZone;
    NSCalendar* dupCal =  [[NSCalendar currentCalendar] copy];

    [dupCal setTimeZone:toTimeZone];
    NSDateComponents *dupComponents = [dupCal components:val fromDate:fromDate];

    return [dupComponents date]; // <- Why return nil?

}

int testTimeZone() {
    NSDate* res = convertTime([NSDate date], [NSTimeZone defaultTimeZone], [NSTimeZone timeZoneWithName:@"America/New_York"]);
    NSLog(@"convertTime: %@", res);
    return 0;

}

In the output window, I can see this print out:

2014-02-15 11:15:18.040 MyApp[28742:70b] convertTime: (null)

For some reason return [dupComponents date]; always return nil, even though I can clearly see in the debugger that it is properly initialised. It contains the values I expect.

Printing description of dupComponents:
<NSDateComponents: 0x100112260>
    TimeZone: America/New_York (EST) offset -18000
    Calendar Year: 2014
    Month: 2
    Leap month: no
    Day: 14
    Hour: 19
    Minute: 19
    Second: 29

Why it is the case?

Anthony Kong
  • 37,791
  • 46
  • 172
  • 304
  • 1
    `[[NSCalendar currentCalendar] copy]` copy is unnecessary. Also why are you using "C" functions and not ObjectiveC methods? – zaph Feb 15 '14 at 00:38
  • @Zaph The timezone change is only temporary and local. I do not want to change the `currentCalendar`. – Anthony Kong Feb 15 '14 at 01:06
  • 1
    `[NSCalendar currentCalendar]` creates a new calendar so this is creating a new calendar, then making a copy of there new calendar and then the new calendar deallocates. It really does pay to study Objective-C memory management. – zaph Feb 15 '14 at 01:10
  • Actually convertTime... does return a date. – zaph Feb 15 '14 at 01:13
  • 1
    NSDate merely represents a moment in time; it does not include any time zone information. So if your function was working correctly, it would always return the same NSDate object that was passed in, because both represent the same moment in time. Time zones are needed when displaying an NSDate in a human-readable format. – Darren Feb 15 '14 at 03:03

1 Answers1

27

I find out the solution.

I need to set a calendar object to NSDateCompoent object before calling date:

NSDateComponents *dupComponents = [dupCal components:val fromDate:fromDate];

[dupComponents setCalendar:dupCal]; // THIS IS THE SOLUTION

return [dupComponents date]; 
Anthony Kong
  • 37,791
  • 46
  • 172
  • 304