Поведение NSDate при сохранении в plist

Я создаю дату из [дата NSdate] и сохраняю ее в plist. Вот как я создаю дату

- (void)applicationWillResignActive:(UIApplication *)application
{
    NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
   // [gregorian setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]];


    NSDateComponents *weekdayComponents = [gregorian components:(NSDayCalendarUnit | NSYearCalendarUnit | NSMonthCalendarUnit  | NSMinuteCalendarUnit)fromDate:[NSDate date]];
    NSInteger day    = [weekdayComponents day];
    NSInteger month  = [weekdayComponents month]; 
    NSInteger year   = [weekdayComponents year];

    NSDateComponents *timeZoneComps=[[NSDateComponents alloc] init];
    [timeZoneComps setDay:day];
    [timeZoneComps setMonth:month];
    [timeZoneComps setYear:year];
    [timeZoneComps setHour:00];
    [timeZoneComps setMinute:00];
    [timeZoneComps setSecond:01];    


    NSDate *date = [gregorian dateFromComponents:timeZoneComps];

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);

    NSString *filePath = [[paths objectAtIndex:0] stringByAppendingPathComponent:@"file.plist"];

    NSMutableDictionary *d = [NSMutableDictionary new];
    [d setObject:date forKey:@"my-date"];

    [d writeToFile:filePath atomically:YES];
}

Я проверил несколько случаев

Случай 1: без установки часового пояса для объекта NSCalendar григорианского выше (по умолчанию он будет использовать локальный часовой пояс) и установки часового пояса в устройстве для Индии, я сохранил дату в plist, и вот что я получил

NSLog даты показывает CurrentDate:2014-07-08 18:30:01 +0000

введите здесь описание изображения

Случай 2. Теперь часовой пояс устройства устанавливается на Сан-Хосе, США

NSLog даты показывает 2014-07-09 07:00:01 +0000

введите здесь описание изображения

Случай 3: установка часового пояса объекта NSCalendar, григорианского выше на «UTC» и установка часового пояса в устройстве в Индию, это то, что я получил в plist

NSLog даты показывает 2014-07-09 00:00:01 +0000

введите здесь описание изображения

Случай 4. Установка времени на Сан-Хосе, США

NSLog даты показывает 2014-07-09 00:00:01 +0000

введите здесь описание изображения

Кто-нибудь может объяснить мне, что происходит во всех этих случаях.

С уважением Ранджит.


person Ranjit    schedule 09.07.2014    source источник
comment
+1 хорошо структурированный вопрос. Получаете ли вы ту же дату/время в консоли, когда вы регистрируете объект даты, используя: NSLog(@"date=%@", date);?   -  person trojanfoe    schedule 09.07.2014
comment
Спасибо. В каком случае?\   -  person Ranjit    schedule 09.07.2014
comment
Вышеприведенный вызов NSLog() будет использовать [NSDate description] для печати даты, которая является датой в формате UTC. Таким образом, вы доказали влияние установки дат с определенными часовыми поясами и сохранения их в формате UTC, поэтому даты меняются в plist.   -  person trojanfoe    schedule 09.07.2014
comment
@trojanfoe, когда часовой пояс UTC, а часовой пояс устройства - Сан-Хосе, почему в plist это 5:30:01 утра, я могу понять для региона Индии, потому что смещение это UTC + 5:30.   -  person Ranjit    schedule 09.07.2014
comment
Эээ, я не понимаю, если честно. Возможно, в вашем коде ошибка (у вас одинаковое время и для Индии, и для Калифорнии, так что здесь что-то не так).   -  person trojanfoe    schedule 09.07.2014
comment
хорошо, @trojanfoe, можешь объяснить мне время в первых двух случаях?   -  person Ranjit    schedule 09.07.2014
comment
@trojanfoe Для полного понимания требуется немного времени, но следует помнить, что часовой пояс, указанный NSCalendar, будет использоваться при расчете окончательного объекта NSDate. Первые два являются неявными, а вторые два явными. Однако последней строкой всегда будет индийское стандартное время.   -  person borrrden    schedule 09.07.2014
comment
В продолжение этого комментария я полагаю, что понимаю, почему он должен выводить по-разному, но, вероятно, есть обстоятельства, связанные с тем, что он всегда выводит стандартное индийское время вместо часового пояса локального устройства (возможно, оно кешируется во время запуска приложения и т. д. )   -  person borrrden    schedule 09.07.2014
comment
Привет @borrrden, спасибо за подробную информацию, я проверил, удалив приложение и снова запустив его, но и тогда я получил те же результаты, поэтому я думаю, что ваше предположение не соответствует действительности.   -  person Ranjit    schedule 09.07.2014
comment
@HotLicks, так что ты предлагаешь?   -  person Ranjit    schedule 09.07.2014
comment
@trojanfoe, если вы думаете, что я допустил какую-либо ошибку в своем коде, если у вас есть время, проверьте, пожалуйста, и дайте мне знать, какие результаты вы получите   -  person Ranjit    schedule 09.07.2014
comment
Я смотрю на это снова. Что неясно, так это то, каким был исходный объект NSDate. Вы должны иметь NSLogged вместе с дампом даты plist. Я думаю, что plist сохраняется как UTC, но вы регистрируете другое время UTC.   -  person Hot Licks    schedule 09.07.2014
comment
@HotLicks, нет, я показал все 4 случая, с UTC и без UTC   -  person Ranjit    schedule 09.07.2014
comment
Вы изменяли свой код каждый раз, поэтому мы не знаем, что это было для данного случая. И у вас нет с каждым моментальным снимком plist NSLog вашего объекта NSDate, поэтому мы знаем, что такое NSDate на самом деле.   -  person Hot Licks    schedule 09.07.2014
comment
хорошо, я обновлю свой вопрос для журналов   -  person Ranjit    schedule 09.07.2014
comment
@HotLicks, проверьте мой обновленный вопрос   -  person Ranjit    schedule 09.07.2014
comment
Ага! То, что вы видите, это, вероятно, время UTC в plist, которое преобразуется в местное время вашего Mac с помощью функции отображения plist.   -  person Hot Licks    schedule 09.07.2014
comment
Давайте продолжим обсуждение в чате.   -  person Ranjit    schedule 09.07.2014
comment
@HotLicks, если это так, можете ли вы проверить на своей машине и сообщить мне, получите ли вы такие же результаты?   -  person Ranjit    schedule 09.07.2014
comment
@HotLicks Хорошая мысль. Откройте plist в текстовом редакторе, если можете, и посмотрите, как он действительно сохраняется. Редактор plist может преобразовывать его из числа в строку по запросу.   -  person borrrden    schedule 10.07.2014


Ответы (2)


Это из-за того, как вы обращаетесь с NSDate. Как только вы преобразуете что-то в NSDate, вы потеряете всю информацию о часовом поясе, и когда вы запишете ее в plist, она будет записана в вашем текущем часовом поясе, поскольку она будет преобразована обратно в строку. Итак, давайте пройдемся по сценариям один за другим.

Все сценарии следуют этому потоку NSDate -> NSDateComponents -> NSDate -> String

1) NSDate: 2014-07-09 XX:XX:XX IST -> NSDateComponents 2014-07-09 00:00:01 IST -> NSDate 2014-07- 09 00:00:01 IST -> 09 июля 2014 г. 00:00:01

2) NSDate: 2014-07-09 XX:XX:XX PST -> NSDateComponents 2014-07-09 00:00:01 PST -> NSDate 2014-07- 09 12:30:01 IST -> 09 июля 2014 г. 12:30:01

3) NSDate: 2014-07-09 XX:XX:XX UTC -> NSDateComponents: 2014-07-09 00:00:01 UTC -> NSDate: 2014- 07-09 05:30:01 IST -> 09 июля 2014 г. 5:30:01

4) То же, что и 3, так как вы вручную указали часовой пояс

Просто помните, что NSDate не важны часовые пояса. Это просто момент времени. 2014-07-09 00:00:01 UTC и 2014-07-09 05:30:01 IST — это точное время в термины NSDate (426556801 секунд впереди 01.01.2001 00:00:00 по Гринвичу). Причина, по которой они различаются в plist, заключается в том, что вы выбираете (неявно) представление местного времени вашего NSDate. Если вам нужно больше контроля, используйте NSDateFormatter.

РЕДАКТИРОВАТЬ Если подумать, вы могли бы возразить, что результаты должны быть другими, но способ, которым NSDate выводит в plist, является проприетарным, поэтому похоже, что по какой-то причине он продолжает использовать стандартное индийское время. Предположения могут включать, возможно, то, что вы не убили свое приложение между установкой часового пояса или чем-то еще.

ВТОРОЕ РЕДАКТИРОВАНИЕ На самом деле меня интересует, что содержит необработанный plist. Вы используете редактор для его просмотра, и он может преобразовывать его в местное время вашего Mac при отображении.

person borrrden    schedule 09.07.2014
comment
Привет @borrrden, спасибо за подробную информацию, я проверил, удалив приложение и снова запустив его, но и тогда я получил те же результаты, поэтому я думаю, что ваше предположение не соответствует действительности. - person Ranjit; 09.07.2014
comment
вы говорите, что для большего контроля используйте NSDateFromatter, но при чем здесь это, потому что я сохраняю только даты, я не конвертировал их в строки - person Ranjit; 09.07.2014

NSDate представляет собой абсолютный момент времени и не имеет ничего общего с часовыми поясами. То, что вы видите и регистрируете, — это NSDate описание, которое довольно произвольно в разных ситуациях и полезно только для отладки в соответствии с Документы Apple

Представление полезно только для отладки.

Существует несколько вариантов получения форматированной строки для даты, в том числе: средства форматирования даты (см. NSDateFormatter и Руководство по форматированию данных), а также методы NSDate descriptionWithLocale:, dateWithCalendarFormat:timeZone: и descriptionWithCalendarFormat:timeZone:locale:

Таким образом, вы можете сохранить свой NSDate, поскольку он не зависит от информации о часовом поясе, и использовать NSCalendar или NSDateFormatter для выполнения всех преобразований, необходимых вашему приложению.

person spassas    schedule 09.07.2014
comment
То есть вы имеете в виду, что если мое приложение используется пользователем из США, то список будет содержать 5:30:01 для дат, которые он/она хранит? - person Ranjit; 09.07.2014
comment
Не обязательно, но для вас это не имеет никакого значения. NSDate всегда будет указывать на один и тот же момент времени. Итак, как я писал выше, вы просто извлекаете его и переводите в нужный формат с использованием NSCalendarили NSDateFormatter. - person spassas; 09.07.2014
comment
Итак, вы говорите, что не имеет значения, содержит ли plist 5:30:01 или 12:30:01, верно? потому что второй случай 12:30:01 - person Ranjit; 09.07.2014
comment
Я думаю, что ответ @borrrden очень хорошо обобщает. - person spassas; 09.07.2014