Search code examples
iosobjective-cxcodensdatensdateformatter

Timezone issue when date display in UI(show 1 day lesser) in Objective C


I am facing one problem, which is related to different timezone.

In UI I have set the date with 3/11/18

leaveEndDate -> 3/11/18

in service I get result.

leaveEndDate = "2018-03-11T06:00:00Z";

But when I display the date in UI, its showing "3/10/18" but actual result should be "3/11/18"

It display 1 day lesser in the application.

I have change the Time Zone is -> Washington, DC - United States and it should work for all timezones.

  1. Approach

    //Adjust the dates.

            NSDate* originalDateValue = [self valueForKey:actualKey];
    
            NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
            dateFormatter.dateFormat = @"yyyy-MM-dd HH:mm:ss Z"; // tried formatter-> @"yyyy-MM-dd'T'HH:mm:ss'Z'"; // yyyy-MM-dd'T'HH:mm:ss.SSSSSSZ
            dateFormatter.timeZone = [NSTimeZone timeZoneWithName:@"UTC"];
            NSString *dateString = [dateFormatter stringFromDate:originalDateValue];
    
            dateFormatter.timeZone = [NSTimeZone localTimeZone];
    
            NSDate * actualDate = [dateFormatter dateFromString:dateString];
    
            [self setValue:actualDate forKey:actualKey];
    
  2. Another approach which I used is:

//Adjust the dates.

NSDate* originalDateValue = [self valueForKey:actualKey];
NSDate* adjustedDateValue = [self.class adjustDate:originalDateValue forTimezone:[self timeZoneName]];

    +(NSDate*)adjustDate:(NSDate*)originalDateValue forTimezone:(NSString*)timezoneName
    {

    if([originalDateValue isEqual:[NSNull null]]) return nil;

    NSTimeInterval timeInterval = ([[NSTimeZone timeZoneWithName:timezoneName] secondsFromGMTForDate:originalDateValue] - [[NSTimeZone localTimeZone] secondsFromGMTForDate:originalDateValue]);

    NSDate* adjustedDateValue = [originalDateValue initWithTimeInterval:timeInterval sinceDate:originalDateValue]; //[originalDateValue dateByAddingTimeInterval:timeInterval];

    return adjustedDateValue;
    }
  1. Third approach

    NSDate* originalDateValue = [self valueForKey:actualKey];
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    dateFormatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ss.SSSZ";
    [dateFormatter setLocale:[NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"]];
    NSString *dateString = [dateFormatter stringFromDate:originalDateValue];
    NSDate* adjustedDateValue = [dateFormatter dateFromString:dateString];
    

Any help?


Solution

  • originalDateValue is always being set to UTC time for the date you are giving it. NSDate works on UTC time since you aren't specifying a timezone. dateFormatter is converting the input you're giving it to your localtime, which is several hours behind. Since you don't specify a time, it's setting the time to 00:00:00 midnight, so when converting fro UTC to Washington DC, you're adjusting the timezone several hours behind.

    You must adjust the source date according to the offset from UTC to localTimeZone:

    NSInteger sourceUTCOffset = [sourceTimeZone secondsFromGMTForDate:originalDateValue];
    NSInteger destinationUTCOffset = [localTimeZone secondsFromGMTForDate:originalDateValue];
    NSTimeInterval interval = destinationUTCOffset - sourceUTCOffset;
    
    NSDate destinationDate = [initWithTimeInterval:interval sinceDate:originalDateValue];
    

    Then operate on destinationDate the way you have already provided.