NSDate dateFromString, как проанализировать «вокруг» UTC, GMT и локали пользователя? - PullRequest
3 голосов
/ 29 марта 2010

Я анализирую некоторые значения из файла XML. Есть строка @"25-12-2010'T'23:40:00" со временем и датой, а также строка со смещением по Гринвичу, например @ "+ 0200". Таким образом, вышеуказанное время - 25. декабря 23:40:00 в часовом поясе +0200 по Гринвичу. (или 21:40 UTC) У меня много таких дат с разными смещениями по Гринвичу. Я должен отобразить эти даты как они, т.е. они не должны быть изменены, чтобы соответствовать языку пользователя. Поэтому, если время 1: 22:45 +0500, то это то, что я должен показать пользователю, даже если пользователь находится в другом часовом поясе.

У меня всяческие проблемы с отображением, вычислением и анализом этих строк.

Если я использую dateFormatter и dateFromString, пользовательская информация о GMT будет включена в результирующее NSDate, означающее, что вышеупомянутое будет сохранено как 23:40:00 +0100 по Гринвичу, потому что это мои настройки телефона и, возможно, 23 : 40: 00 −0400 для пользователя с телефона из Нью-Йорка.

Когда я впоследствии делаю вычитание, сложение и сравнение между этими датами, я должен сохранять смещение по Гринвичу, и все становится хуже, если телефон переключает настройки локали, с момента, когда дата была проанализирована, до даты, когда она отображается ...

Можно ли мне извлечь эту дату из строки как UTC, а затем сохранить ее как интервал вместо фактической (зависящей от часового пояса) даты. Я знаю, что именно так даты всегда сохраняются внутри. Но я не могу понять, как это сделать с отдельной строкой GMT и с учетом языкового стандарта пользователей.

Приветствия

Ответы [ 2 ]

4 голосов
/ 30 марта 2010

Спасибо, Оле. Я наконец понял, что NSDate и NSDateformatter просто абстрактны концепции и что «дата» действительно сохраняется как «миллисекунды или секунды с 1 января 2001 года» внутри.

Я сделал «Доказательство концепции», чтобы действительно понять это. Теперь неожиданно очень просто записать некоторые категории в NSDate, которые гарантируют, что даты, входящие и выходящие, правильно отформатированы, но все вычисления выполняются в исходную дату UTC.

- (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]];
    }   

}

Разобрать даты по их смещению по Гринвичу. Это обеспечит сохранение времени UTC внутренне правильно.

-(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]];
}

Настройте NSDateformatter для печати сохраненных дат с учетом смещения по Гринвичу. все даты теперь можно манипулировать как UTC без учета времени по Гринвичу.

-(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 в оригинальном GMT 2010-03-30 18: 50: 31.285 TimeZonePOC [39830: 207] 2010-03-30 16:00:00 +0200 по местному времени по Гринвичу

2010-03-30 18: 50: 31.287 TimeZonePOC [39830: 207] 2010-03-30 12:00:00 -0100 в оригинальном GMT 2010-03-30 18: 50: 31.287 TimeZonePOC [39830: 207] 2010-03-30 15:00:00 +0200 по местному времени по Гринвичу

2010-03-30 18: 50: 31.289 TimeZonePOC [39830: 207] 2010-03-30 12:00:00 +0000 в оригинальном GMT 2010-03-30 18: 50: 31.289 TimeZonePOC [39830: 207] 2010-03-30 14:00:00 +0200 по местному времени по Гринвичу

2010-03-30 18: 50: 31.290 TimeZonePOC [39830: 207] 2010-03-30 12:00:00 +0100 в оригинальном GMT 2010-03-30 18: 50: 31.292 TimeZonePOC [39830: 207] 2010-03-30 13:00:00 +0200 по местному времени GMT

2010-03-30 18: 50: 31.292 TimeZonePOC [39830: 207] 2010-03-30 12:00:00 +0200 в оригинальном GMT 2010-03-30 18: 50: 31.294 TimeZonePOC [39830: 207] 2010-03-30 12:00:00 +0200 по местному времени по Гринвичу

4 голосов
/ 29 марта 2010

Используйте NSDateFormatter's setTimeZone:. Вам также нужно будет сохранять смещения часовых поясов отдельно от NSDate, чтобы позже снова отобразить время в этих часовых поясах.

...