Подтвердить что ты не робот

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

Написание 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];
Running this through the debugger, date ends up nil! I'm assuming it has something to do with my date format string.

How can I fix it to correctly parse the date string?

A thought would be to make the Z in the date format literal, a la setting the date format to yyyy-MM-dd'T'HH:mm:ss.SSS'Z'.

That would work, except when the Z is parsed as a literal, the date loses offset information, and so is ambiguous, and therefore interpreted to be local time.

For example, if the string to parse was 2009-08-11T06:00:00.000Z (6:00 zulu time) it would be interpreted as 6:00 local time, and an incorrect offset would then be applied. It would then be parsed as 2009-08-11T06:00:00.000-600 (12:00 zulu time) with the offset depending on the user offset.

Thanks!
4b9b3361

Ответ 1

У меня тоже была эта проблема, я не уверен, что это ошибка 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];

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

Ответ 2

В большинстве ответов вам предлагается относиться к "Z" как к буквальному персонажу. Не делайте этого!

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

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

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

"- 8: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 при разборе строки.

Bonus:

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

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

Ответ 3

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

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

Ответ 4

Нет необходимости манипулировать строкой. Просто установите часовой пояс на 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

Ответ 5

Этот метод можно использовать для получения даты с 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]];

}

Ответ 6

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

Ответ 7

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