Разница между настройкой часового пояса в NSCalendar с использованием `localTimeZone` по сравнению с использованием` timeZoneWithAbbreviation` с различными значениями - PullRequest
0 голосов
/ 15 декабря 2018

Я настроил свой телефон (реальное устройство, а не симулятор) на работу в Лондоне, Великобритания, который соответствует Гринвичу.

Когда я устанавливаю часовой пояс на NSCalendar с помощью localTimeZone, он дает мне времяотключено на 1 минуту и ​​15 секунд по сравнению с тем, если я установил его с помощью [NSTimeZone timeZoneWithAbbreviation:@"GMT"].Разве оба не должны давать мне один и тот же результат, если мой часовой пояс уже установлен по Гринвичу?

Еще одна вещь, которую я замечаю, заключается в том, что, если я устанавливаю точки останова, NSDate, созданный с использованием localTimeZone, проверяется через точку останова.выключен на 1 минуту и ​​15 секунд, но NSLog печатает правильное время (точка останова показывает: 0000-12-30 09:01:15 UTC, но NSLog печатает сб 30 декабря 09:00:00 0000):

enter image description here

Но когда я использую [NSTimeZone timeZoneWithAbbreviation:@"GMT"], точка останова показывает правильное время, но NSLog выводит неверное время на 1 минуту и ​​15 секунд (точка останова показывает:0000-12-30 09:00:00 UTC, но NSLog печатает сб 30 декабря 08:58:45 0000):

enter image description here

Вот мой кодс точкой останова и выводом NSLog в комментариях рядом с ним:

NSLog(@"Timezone: %@",[NSTimeZone localTimeZone]);//Timezone: Local Time Zone (Europe/London (GMT) offset 0)

    NSLocale *locale = [NSLocale currentLocale];
    NSCalendar *myCalendar = [NSCalendar currentCalendar];
    [myCalendar setLocale:locale];
    [myCalendar setTimeZone:[NSTimeZone localTimeZone]];
    NSLog(@"TZ: %@",myCalendar.timeZone);//TZ: Local Time Zone (Europe/London (GMT) offset 0)

    NSDateFormatter *timeFormatter = [NSDateFormatter new];
    [timeFormatter setDateFormat:@"h:mm a"];
    [timeFormatter setLocale:locale];
    [timeFormatter setTimeZone:[NSTimeZone localTimeZone]];

    NSDateComponents* dateComps = [myCalendar components:NSCalendarUnitHour|NSCalendarUnitMinute fromDate:[timeFormatter dateFromString:@"9:00 AM"]];
    NSDate *myDate1 = [myCalendar dateFromComponents:dateComps];//Breakpoint shows: 0000-12-30 09:01:15 UTC


    NSLog(@"myDate1: %@",myDate1); // myDate1: Sat Dec 30 09:00:00 0000

    //----------------Explicitly specified timeZoneWithAbbreviation GMT:


    NSCalendar *myCalendarExplicitGMT = [NSCalendar currentCalendar];
    [myCalendarExplicitGMT setLocale:locale];
    [myCalendarExplicitGMT setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"GMT"]];
    NSLog(@"TZ: %@",myCalendarExplicitGMT.timeZone);//TZ: GMT (GMT) offset 0

    NSDateComponents* dateCompsUsingExplicitGMT = [myCalendarExplicitGMT components:NSCalendarUnitHour|NSCalendarUnitMinute fromDate:[timeFormatter dateFromString:@"9:00 AM"]];
    NSDate *myDate2 = [myCalendarExplicitGMT dateFromComponents:dateCompsUsingExplicitGMT];//Breakpoint shows: 0000-12-30 09:00:00 UTC


    NSLog(@"myDate2: %@",myDate2); // myDate2: Sat Dec 30 08:58:45 0000

1 Ответ

0 голосов
/ 16 декабря 2018

Во время вычислений вы получаете NSDateComponents со значениями часов и минут.Вы в порядке к этому моменту.Однако, чтобы использовать с ним NSDateFormatter, вы затем конвертируете в NSDate (так как этого требует NSDateFormatter).NSDate - это абсолютный момент времени, поэтому для его конвертации требуется полностью указанная дата.Вместо того, чтобы возвращать nil, он использует значения по умолчанию (ноль) для любых полей, отсутствующих в NSDateComponents.Таким образом, он использует год 1 (и фактически корректируется назад, в 1 г. до н.э.).Когда вы делаете это, вы видите год, напечатанный как «0000».

Когда вы используете явный часовой пояс GMT, вы явно указываете смещения, и они работают в основном так, как ожидалось.Однако, когда NSDate отформатирован с использованием местного часового пояса, т. Е. Европы / Лондона, для вас, он будет применять любые исторические изменения, которые произошли в этом часовом поясе, так как именно это говорит «Европа / Лондон». Система часовых поясов IANA , которую использует NSTimeZone, имеет довольно полную историю всех изменений часовых поясов, начиная с создания самой системы часовых поясов.Они игнорируют часовые пояса, которые приходили и уходили до 1970 года или около того, но они пытаются отследить историю часовых поясов, которые у них есть, и вернуться к своим истокам.Похоже, что для Лондона они впервые использовали GMT еще в 1847 году как стандартное время (до того, как была создана система полного часового пояса).До этого, тем не менее, они (и все остальные) использовали «Местное среднее время», которое было естественным временем в месте расположения этого города - так что для города на некотором расстоянии друг от друга их время будет отличаться на четыре минуты (1440 минут вдень, деленный на 360 градусов долготы для Земли, получает четыре минуты на градус).Так, до 1847 года они использовали «Лондонское среднее время», которое немного отличалось от «Гринвичского среднего времени».Глядя на исходный файл tzdata "europe", они дают это описание, которое они нашли в 1994 Independent статье:

'An old stone obelisk marking a forgotten terrestrial meridian stands
beside the river at Kew. In the 18th century, before time and longitude
was standardised by the Royal Observatory in Greenwich, scholars observed
this stone and the movement of stars from Kew Observatory nearby. They
made their calculations and set the time for the Horse Guards and Parliament,
but now the stone is obscured by scrubwood and can only be seen by walking
along the towpath within a few yards of it.'

I have a one inch to one mile map of London and my estimate of the stone's
position is 51° 28' 30" N, 0° 18' 45" W. The longitude should
be within about ±2". The Ordnance Survey grid reference is TQ172761.

[This yields GMTOFF = -0:01:15 for London LMT in the 18th century.]

Итак, они рассчитывают до 1847 года, Лондон (и, таким образом,Часовой пояс "Европа / Лондон") был смещен на одну минуту и ​​пятнадцать секунд от GMT, и он будет соответствующим образом корректировать ваше время.Поскольку ваша NSDate рассчитана на 1 год до н.э., это определенно задолго до 1847 года, так что вы получите эту корректировку.Когда я пробовал America / New_York таким же образом, он отличался от чистого GMT-5 на 3:58.

Поэтому короткий ответ таков: когда вы выполняете преобразование дат с использованием современных часовых поясов, вас лучше обслуживают.сохраняя современные компоненты даты также современными.Например, если вы позволите году вернуться к Второй мировой войне, вы начнете применять двойное летнее время, которое Лондон имел во время войны, а с 1800-х и ранее вы начнете пользоваться системой времени, которая сводила железнодорожные компании с ума ;-).Другой вариант, как вы видели, это использовать NSTimeZones, которые не являются историческими, но имеют предсказуемое смещение.NSLog (), тем не менее, использует метод описания NSDate, который, в свою очередь, будет использовать текущий (исторический) часовой пояс и всегда получит эти довольно произвольные смещения в древние годы.

...