tags:

views:

736

answers:

2

Hi

I parse some values from an xml file. There is a @"25-12-2010'T'23:40:00"string with the time and date and there is a string with the GMT offset like this @"+0200". So the above time is the 25. of December 23:40:00 in timeZone +0200 GMT. (or 21:40 UTC) I have lots of these dates with different GMT offsets. I have to display these dates as they are, i.e. They must not be changed to fit the locale of the user. So if time 1: is 22:45 +0500 then that is what I must show the user, even if the user is in a different timezone.

I have all sorts of trouble with displaying, calculating and parsing these strings.

If I use a dateFormatter and dateFromString the user specific GMT info will be included in the resulting NSDate meaning the above will be saved as 23:40:00 +0100 GMT because that is my phones setting and maybe 23:40:00 −0400 on a user from new New York's phone.

When I subsequently do subtraction, addition and comparisons between these dates I have to keep the GMT offset around and everything gets worse if the phone switches locale settings, from when the date was parsed to when the date is displayed...

Is there a way for me to extract this date from the string as UTC, then save it as an interval instead of an actual (timezone dependent) date. I know that is how dates are always saved internally. But I can't figure out how to do it with the separate GMT string and taking into account the users locale.

Cheers

+1  A: 

Use NSDateFormatter's setTimeZone:. You will also need to store the time zone offsets separately from the NSDate to later display the times in these time zones again.

Ole Begemann
Hi Ole Thanks for the input.How would I use the setTimeZone? As I can see from the docs it is possible to set a timeZone on a formatter (by secondsFromGMT in my case) Then I have to format my dateformatter for each date Im displaying?The date is still saved as local time and all calculations I do between these dates would involve the GMT variable and reducing everything to UTC before doing any date manipulations.I guess writing a category on NSDate and doing the calculations by hand based on the GMT offset I have to save, would be easier.Or did I miss what you were referring to?
RickiG
No, you got it wrong. NSDate is not aware of time zones, it always stores dates in a time zone independent manner (as a span of time since a specific reference date). So your calculations wouldn't be affected. Now, whenever you have to parse a date or display one, you need to setup an NSDateFormatter and set its time zone to the correct one (i.e., the time zone the date to be parsed is in or the date should be displayed in, respectively).
Ole Begemann
A: 

Thank You Ole. I finally got my head around that NSDate and NSDateformatter are just abstract concepts and that a "date" is truly saved as "milliseconds or seconds since 1/1 2001" internally.

I did a "Proof of concept" to really understand it. Now it is suddenly very simple to write some categories on NSDate that makes sure that dates going in and coming out are correctly formatted, but all calculations are done on the raw UTC date.

- (void) testGMTDateParser {

    NSMutableArray *arrayDates = [NSMutableArray arrayWithCapacity:5];
    [self setParsedDates:arrayDates];

    NSMutableArray *arrayGMTOffsets = [NSMutableArray arrayWithCapacity:5];
    [self setParsedGMTOffsets:arrayGMTOffsets]; 

    NSString *date00    = @"2010-03-30T12:00:00";   
    NSString *GMT00     = @"-2";

    NSString *date01    = @"2010-03-30T12:00:00";   
    NSString *GMT01     = @"-1";

    NSString *date02    = @"2010-03-30T12:00:00";   
    NSString *GMT02     = @"+0";

    NSString *date03    = @"2010-03-30T12:00:00";   
    NSString *GMT03     = @"+1";

    NSString *date04    = @"2010-03-30T12:00:00";   
    NSString *GMT04     = @"+2";    

    NSArray *dateArray  = [NSArray arrayWithObjects:date00, date01, date02, date03, date04,nil];
    NSArray *GMTArray   = [NSArray arrayWithObjects:GMT00, GMT01, GMT02, GMT03, GMT04, nil];

    for (int i = 0; i < [dateArray count]; i++) {

        [self parseDateString:[dateArray objectAtIndex:i] withGMTString:[GMTArray objectAtIndex:i]];
    }   

}

Parse the Dates with regards to their respective GMT offset. This will make sure the UTC time saved internally is correct.

-(void) parseDateString:(NSString*) dateString withGMTString:(NSString*) GMTString {

    NSInteger hoursFromGMT      = [GMTString intValue]; 
    NSInteger secondsFromGMT    = (hoursFromGMT * 60 * 60);

    NSTimeZone *timeZone = [NSTimeZone timeZoneForSecondsFromGMT:secondsFromGMT];

    NSDateFormatter *dateFormatterGMTAware = [[NSDateFormatter alloc] init];
    [dateFormatterGMTAware setTimeZone:timeZone];
    [dateFormatterGMTAware setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss"];
    NSDate *date = [dateFormatterGMTAware dateFromString:dateString];
    [dateFormatterGMTAware release];

    [self.parsedDates addObject:date];
    [self.parsedGMTOffsets addObject:[NSNumber numberWithInt:secondsFromGMT]];
}

Set up the NSDateformatter to print out the saved dates with regards to GMT offset. all dates can now be manipulated as UTC with no regards to GMT.

-(void) printOutDates {

    for (int i = 0; i < [self.parsedDates count]; i++) {

        NSTimeZone *timeZone = [NSTimeZone timeZoneForSecondsFromGMT:[[parsedGMTOffsets objectAtIndex:i] intValue]];

        NSDateFormatter *dateFormatterGMTAware = [[NSDateFormatter alloc] init];
        [dateFormatterGMTAware setTimeZone:timeZone];
        [dateFormatterGMTAware setDateFormat:@"yyyy-MM-dd HH:mm:ss Z"];

        NSLog(@"%@ in Original GMT", [dateFormatterGMTAware stringFromDate:[parsedDates objectAtIndex:i]]);
        NSLog(@"%@ in Local GMT\n\n", [parsedDates objectAtIndex:i]);
    }
}

2010-03-30 18:50:31.284 TimeZonePOC[39830:207] 2010-03-30 12:00:00 -0200 in Original GMT 2010-03-30 18:50:31.285 TimeZonePOC[39830:207] 2010-03-30 16:00:00 +0200 in Local GMT

2010-03-30 18:50:31.287 TimeZonePOC[39830:207] 2010-03-30 12:00:00 -0100 in Original GMT 2010-03-30 18:50:31.287 TimeZonePOC[39830:207] 2010-03-30 15:00:00 +0200 in Local GMT

2010-03-30 18:50:31.289 TimeZonePOC[39830:207] 2010-03-30 12:00:00 +0000 in Original GMT 2010-03-30 18:50:31.289 TimeZonePOC[39830:207] 2010-03-30 14:00:00 +0200 in Local GMT

2010-03-30 18:50:31.290 TimeZonePOC[39830:207] 2010-03-30 12:00:00 +0100 in Original GMT 2010-03-30 18:50:31.292 TimeZonePOC[39830:207] 2010-03-30 13:00:00 +0200 in Local GMT

2010-03-30 18:50:31.292 TimeZonePOC[39830:207] 2010-03-30 12:00:00 +0200 in Original GMT 2010-03-30 18:50:31.294 TimeZonePOC[39830:207] 2010-03-30 12:00:00 +0200 in Local GMT

RickiG