Nil NSDate при попытке получить дату из строки UTC по зулусскому времени

StackOverflow https://stackoverflow.com/questions/1263455

Вопрос

При написании приложения для iPhone на Objective-C у меня есть дата в строковой форме (в формате UTC, с Z в конце для обозначения нулевого смещения UTC или времени zulu), которую мне нужно разобрать в NSDate объект.

Немного кода:

NSDateFormatter* df = [[NSDateFormatter alloc]init];
[df setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSSZ"];
NSString* str = @"2009-08-11T06:00:00.000Z";
NSDate* date = [df dateFromString:str];
Запускаем это через отладчик, date заканчивается тем, что nil!Я предполагаю, что это как-то связано с моей строкой формата даты.

Как я могу это исправить, чтобы правильно разобрать строку даты?

Мысль состояла бы в том, чтобы сделать Z в литерале формата даты, аналогичном установке формата даты на yyyy-MM-dd'T'HH:mm:ss.SSS'Z'.

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

Например, если строка для анализа была 2009-08-11T06:00:00.000Z (6:00 по зулусскому времени), она была бы интерпретирована как 6:00 по местному времени, и тогда было бы применено неправильное смещение.Затем он будет проанализирован как 2009-08-11T06:00:00.000-600 (12:00 по времени зулу) со смещением, зависящим от смещения пользователя.

Спасибо!

Это было полезно?

Решение

У меня тоже была эта проблема, я не уверен, является ли это ошибкой API в коде Apple или моим непониманием, но я обошёл ее, используя смещения часов в строках даты.

Если вы измените код в своем примере на:

NSDateFormatter* df = [[NSDateFormatter alloc]init];
[df setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSSZ"];
NSString* str = @"2009-08-11T06:00:00.000-0700";   // NOTE -0700 is the only change
NSDate* date = [df dateFromString:str];

Теперь он проанализирует строку даты.Конечно, -07:00 — это мое смещение, вам придется изменить его на свое.Надеюсь это поможет.

Другие советы

Большинство ответов предполагают, что вы должны рассматривать букву "Z" как буквальный символ. Не делай этого!

Z на самом деле означает, что дата смещена на 0 по отношению к UTC (+0000).

Это соответствует формату часового пояса ISO8601:

Формат часового пояса ISO 8601:Постоянное, определенное смещение от UTC, которое всегда имеет один и тот же формат, за исключением самого UTC ("Z").

"-08:00"

"Z"

То, что вы хотите сделать, это использовать следующий формат для вашего NSDateFormatter:

 NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
                                  // 2013-11-18T23:00:00.324Z
                                  [formatter setTimeZone:[NSTimeZone localTimeZone]];
                                  [formatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"];
                                  return formatter;

Повторяя Z пять раз вы говорите программисту форматирования использовать ISO8601 при синтаксическом анализе строки.

Бонус:

  • Используйте от одного до трех Zs для формата RFC 822 GMT.
  • Используйте четыре Zs для локализованного формата GMT.

Для получения дополнительной информации проверьте это документ.

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

    [df setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"];

Нет необходимости манипулировать строкой.Просто установите часовой пояс на NSDateFormatter (и локаль, пока вы это делаете):

NSDateFormatter * formatter = [[NSDateFormatter alloc] init];
[formatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
[formatter setLocale:[NSLocale systemLocale]];
[formatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"];

И анализируйте строки даты по мере необходимости:

NSDate * value = [formatter dateFromString:@"2012-03-01T23:08:25.000Z"];
NSLog(@"%@", value); // prints 2012-03-01 23:08:25 +0000

Вы можете использовать этот метод, чтобы получить дату из UTC.

+ (NSDate*)getDateFromUTCDateTimeString:(NSString*)dateString {

NSDateFormatter *isoDateFormatter = [[NSDateFormatter alloc] init];

[isoDateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"];

[isoDateFormatter setTimeZone:[NSTimeZone  timeZoneWithAbbreviation:@"UTC"]];

NSDateFormatter *userFormatter = [[NSDateFormatter alloc] init];

[userFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];

[dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];

[dateFormatter setTimeZone:[NSTimeZone  timeZoneWithAbbreviation:@"UTC"]];

NSDate *date = [isoDateFormatter dateFromString:dateString];

return [dateFormatter dateFromString:[userFormatter stringFromDate:date]];

}

это может вам помочь..«Z» — это буквальный код часового пояса.попробуйте использовать «о» (букву, а не ноль).Буква «о» означает смещение UTC.Я столкнулся с этим некоторое время назад, надеюсь, это вам помогло.

-(NSDate*)dateFromZulu:(NSString*)str {
    if (str == nil) {
        NSLog(@"Error getting date");
        return [NSDate date];
    }

    NSDateFormatter *f = [[NSDateFormatter alloc] init];
    [f setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss Z"];
    NSDate *ret = [f dateFromString:[str stringByReplacingOccurrencesOfString:@"Z" withString:@" +0000"]];
    [f release];

    if (ret == nil) {
        ret = [NSDate date];
        NSLog(@"Error formatting date (%@)",str);       
    }   
    return ret;     
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top