Search code examples
objective-cnsdatensdateformatternstimezone

NSDate and NSDate stringFromDate are inconsistent


I am trying to convert a mysql datetime field to another timezone. The conversion seems correct when I print the date object, however when I print the date as a string the time is incorrect. Source code and output are below.

Source:

edited - print original interval in seconds and string, add timezones

interval = [NSNumber numberWithDouble: seconds];
NSLog(@"interval in ms: %@",interval); 
self.dateStamp = [[NSDate alloc] initWithTimeIntervalSince1970:seconds/1000];


if(![currentZone.name isEqualToString: timezone]){          //need to convert
    NSDateFormatter *fromTZ = [[NSDateFormatter alloc]init];
    [fromTZ setTimeZone:currentZone];
    [fromTZ setDateFormat:@"hh:mm yyyy-MM-dd"];
    NSLog(@"original date: %@",[fromTZ stringFromDate:self.dateStamp]);
    NSDateFormatter *toTZ = [[NSDateFormatter alloc]init];
    [toTZ setTimeZone:spotZone];
    [toTZ setDateFormat:@"hh:mm yyyy-MM-dd"];
    NSString *tempdate = [fromTZ stringFromDate:self.dateStamp];
    NSDate *toDate = [toTZ dateFromString:tempdate];
    NSLog(@"Date: %@",toDate);
    NSLog(@"Date String: %@", [toTZ stringFromDate:toDate]);
}

Output:

interval in ms: 1384193573000

original date: 01:12 2013-11-11 //date in current timezone: America/Phoenix

Date: 2013-11-11 08:12:00 +0000 //date in new timezone: America/New York

Date String: 01:12 2013-11-11


Solution

  • Your server sends the time 1384193573000 (in milliseconds) since 1.1.1970, but not with respect to GMT as it is usually done, but with respect to a different time zone, "America/Phoenix" in your example.

    Therefore you have to add a correction first, which is the difference between "America/Phoenix" and GMT:

    NSTimeInterval serverTime = 1384193573000/1000.;
    NSTimeZone *fromZone = [NSTimeZone timeZoneWithName:@"America/Phoenix"];
    NSTimeInterval diff = [fromZone secondsFromGMTForDate:[NSDate dateWithTimeIntervalSince1970:0]];
    NSDate *dateStamp = [NSDate dateWithTimeIntervalSince1970:(serverTime - diff)];
    

    This was the crucial step. dateStamp is now a "proper" NSDate object representing the time sent from the server. What remains is to display the date. That is done as in the above comments and the other answer. For example:

    NSTimeZone *toZone = [NSTimeZone timeZoneWithName:@"America/New_York"];
    NSDateFormatter *toTZ = [[NSDateFormatter alloc]init];
    [toTZ setTimeZone:toZone];
    [toTZ setDateFormat:@"HH:mm yyyy-MM-dd"];
    NSString *result = [toTZ stringFromDate:dateStamp];
    
    // result = 20:12 2013-11-11