Почему 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.
Ответы
Ответ 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.