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

Почему NSDateFormatter возвращает nil для этих 4 часовых поясов?

Попробуйте запустить это в iOS6 (не тестировали pre iOS6):

NSDateFormatter *julianDayDateFormatter = nil;
julianDayDateFormatter = [[NSDateFormatter alloc] init];
[julianDayDateFormatter setDateFormat:@"g"];

for (NSString *timeZone in [NSTimeZone knownTimeZoneNames]) {
    julianDayDateFormatter.timeZone = [NSTimeZone timeZoneWithName: timeZone];
    NSDate *date = [julianDayDateFormatter dateFromString:[NSString stringWithFormat:@"%d", 2475213]];
    if (date == nil)
        NSLog(@"timeZone = %@", timeZone);
}

и вы получите следующий вывод:

America/Bahia
America/Campo_Grande
America/Cuiaba
America/Sao_Paulo

Может ли кто-нибудь объяснить, почему эти четыре часовых пояса ведут себя так же, как NSDateFormatter, установленный в julian day numbers? Все остальные часовые пояса делают NSDateFormatter возвращением действительных NSDates.

4b9b3361

Ответ 1

У меня есть подозрение. Только подозрение, но довольно сильное.

Это значение представляет собой 19 октября 2064 года. В бразильских часовых поясах наблюдается летнее время, начинающееся с местной полуночи - что, когда их часы идут вперед, такой самой полночь не существует. 19 октября - один из этих переходов.

Вот пример кода, использующего Noda Time, мой .NET API даты/времени. Он проверяет, является ли начало дня в каждом часовом поясе, о котором он знает, на самом деле полночь:

using System;
using NodaTime;

class Test
{
    static void Main()
    {
        var localDate = new LocalDate(2064, 10, 19);
        var provider = DateTimeZoneProviders.Tzdb;
        foreach (var id in provider.Ids)
        {
            var zone = provider[id];
            var startOfDay = zone.AtStartOfDay(localDate).LocalDateTime.TimeOfDay;
            if (startOfDay != LocalTime.Midnight)
            {
                Console.WriteLine(id);
            }
        }
    }
}

Это создает очень похожий список:

America/Bahia
America/Campo_Grande
America/Cuiaba
America/Sao_Paulo
Brazil/East

Я подозреваю, что Бразилия/Восток может быть псевдонимом для Америки /Sao _Paolo, поэтому он не входит в ваш список.

В любом случае, чтобы вернуться к вашему юлианскому вопросу - я подозреваю, что форматировщик всегда хочет вернуть NSDate *, который находится в местной полночь. Этого не существует для 19 октября 2064 года в этих часовых поясах... следовательно, он возвращает ноль. Лично я бы предложил, чтобы он возвращал значение 1am, но эй...

Ответ 2

Кредиты для Джона Скита для того, чтобы поставить меня на правильный путь. Тем не менее, я просто хочу уточнить его ответ в контексте iOS.

Когда вы запрашиваете NSDateFormatter для преобразования числа юлианских дней в NSDate, вы можете указать только целые числа (как правило, вы можете указать десятичную часть для часов/минут/сек дня) в строке, подлежащей анализу. Поскольку Apple демаркирует юлианские дни в полночь (в отличие от полудня в астрономии, читайте здесь: http://www.unicode.org/reports/tr35/#Date_Field_Symbol_Table), а некоторые средние ночи просто не существуют (спасибо, что указали, что вне @JonSkeet) NSDateFormatter идентифицирует, что этот конкретный момент времени не существует в этом часовом поясе и возвращает нуль.

Для записи iOS5 не ведет себя так, и я согласен с Джоном Скитом, что NSDateFormatter должен вернуть NSDate, скорректированный для DST, вместо nil, поскольку этот конкретный юлианский день фактически существует! Я подал ошибку с Apple.