Как получить значения NSCalendarComponent относительно часового пояса, отличного от GMT?

#ios #objective-c #nsdateformatter #nscalendar #nstimezone

#iOS #objective-c #nsdateformatter #nscalendar #nstimezone

Вопрос:

Почему следующие отмеченные утверждения терпят неудачу? Я просто запускал этот модульный тест на хосте в Центральной Европе. Следовательно NSCalendar.currentCalendar.timeZone , это CEST, то есть GMT 0200. NSDateComponents возвращает этот часовой пояс, но другие его значения (для года и т.д.), По-видимому, относятся к GMT. Как я могу получить значения, относящиеся к CEST?

 - (void)test {
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    dateFormatter.dateFormat = @"yyyy-MM-dd'T'HH:mmZZZ";
    dateFormatter.timeZone   = [NSTimeZone timeZoneWithAbbreviation:@"CEST"];
    XCTAssertEqual(2 * 60 * 60, dateFormatter.timeZone.secondsFromGMT, @"");

    NSDate *time = [dateFormatter dateFromString:@"2014-01-01T00:00 0200"]; // midnight on a Wednesday

    NSCalendar *calendar = NSCalendar.currentCalendar; // i.e. CEST
    XCTAssertEqual(2 * 60 * 60, calendar.timeZone.secondsFromGMT, @"");

    NSDateComponents *components = [calendar components: NSYearCalendarUnit |
                                                         NSMonthCalendarUnit |
                                                         NSDayCalendarUnit |
                                                         NSWeekdayCalendarUnit |
                                                         NSHourCalendarUnit |
                                                         NSMinuteCalendarUnit |
                                                         NSTimeZoneCalendarUnit
                                               fromDate:time];

    XCTAssertEqual(components.year, 2014, @""); // fails with 2013
    XCTAssertEqual(components.month, 1, @""); // fails with 12
    XCTAssertEqual(components.day, 1, @""); // fails with 31
    XCTAssertEqual(components.weekday, 4, @""); // fails with 3 (Tuesday)
    XCTAssertEqual(components.hour, 0, @""); // fails with 23
    XCTAssertEqual(components.minute, 0, @""); // succeeds
    XCTAssertEqual(components.timeZone.secondsFromGMT, 2 * 60 * 60, @""); // succeeds (CEST)
}
 

Ответ №1:

NSCalendar.currentCalendar.timeZone сейчас CEST или GMT 02, потому что в вашем часовом поясе сейчас действует летнее время. Но в 2014-01-01 летнее время не было активным. Поэтому все преобразования для этой даты выполняются со смещением GMT 01.

Итак, вот что происходит в вашем случае:

  • Строка «2014-01-01T00:00 0200» преобразуется в NSDate «2013-12-31 22:00:00 0000″, потому что вы явно указываете смещение GMT » 0200″ во входной строке. Таким образом, установка dateFormatter.timeZone значения «CEST» не имеет никакого эффекта.
  • В NSDate «2013-12-31 22:00:00 0000» преобразуется в компоненты даты, используя ваш текущий календарь. Поскольку смещение по Гринвичу для этой даты равно «GMT 0100», вы получаете компоненты даты, соответствующие «2013-12-31 23:00:00 0100».

Если вы выполняете вычисления с помощью

 NSDate *time = [dateFormatter dateFromString:@"2014-01-01T00:00 0100"];
 

затем тест завершается успешно.