Search code examples
iosnsdateformatternsformatter

NSDateFormatter Returning Unexpected Time Values


Can anyone explain to me why the following code returns inconsistent time values? I've been getting incorrect results when trying to create an NSDate object from a user specified date/time string and I've put together the following code below to illustrate the problem.

// Create two strings containing the current date and time
NSDateFormatter * dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:@"yyyy-MM-dd"];

 NSDateFormatter * timeFormat = [[NSDateFormatter alloc] init];
 [timeFormat setDateFormat:@"HH:mm:ss a"];
 timeFormat.AMSymbol = @"AM";
 timeFormat.PMSymbol = @"PM";
 timeFormat.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"EDT"];

 NSDate * now = [[NSDate alloc] init];
 NSString *theDate = [dateFormat stringFromDate:now];
 NSString *theTime = [timeFormat stringFromDate:now];

 NSLog(@"The current date/time is (GTM): %@", now);
 NSLog(@"The current date/time is (EDT): %@ %@", theDate, theTime);

 // Combine the date and time strings
 NSMutableString * theDateTime = [[NSMutableString alloc] init];
 theDateTime = [theDateTime stringByAppendingString:theDate];
 theDateTime = [theDateTime stringByAppendingString:@" "];
 theDateTime = [theDateTime stringByAppendingString:theTime];

 // Define the formatter to parse the combined date and time string
 NSDateFormatter * dateFormatter=[[NSDateFormatter alloc] init];
 [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss a"];
 dateFormatter.AMSymbol = @"AM";
 dateFormatter.PMSymbol = @"PM";
 dateFormatter.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"EDT"];

 // Create an NSDate object using the combined date and time string
 NSDate * theDateTimeObject=[dateFormatter dateFromString:theDateTime];
 NSString * theDateTimeString=[dateFormatter stringFromDate:theDateTimeObject];

 // Print the results
 NSLog(@"theDateTimeObject (GMT) = %@", theDateTimeObject);
 NSLog(@"theDateTimeString (EDT) = %@", theDateTimeString);

This code produces the following output:

  The current date/time is (GMT): 2015-09-29 22:28:10 +0000
  The current date/time is (EDT): 2015-09-29 18:28:10 PM
  theDateTimeObject (GMT) = 2015-09-29 16:28:10 +0000
  theDateTimeString (EDT) = 2015-09-29 12:28:10 PM

Clearly something is going wrong when the combined date and time string gets parsed by the date formatter to create the NSDate object. It seems to not understand the input time zone and returns a time in GMT that is several hours off what it should be (i.e. +4 hours). I've set the time zone to be "EDT", so not sure what else I can do to fix this problem, other than hard code an offset in the input, which I'd rather not do. Any help would be appreciated.


Solution

  • You are doing bad things by using both 24-hour format (HH) instead of 12-hour format (hh) and using AM/PM (a).

    Change both instances of HH in your formats to hh and you should get the expected results.

    You should also set the formatter's locale to the special locale en_US_POSIX to avoid issues with the device's 24-hour time setting.

    Side note: Your use of NSMutableString is all wrong. Try this:

    NSMutableString * theDateTime = [[NSMutableString alloc] init];
    [theDateTime appendString:theDate];
    [theDateTime appendString:@" "];
    [theDateTime appendString:theTime];
    

    or simply use:

    NSString *theDateTime = [NSString stringWithFormat:@"%@ %@", theDate, theTime];