NSDate Format выводит неверную дату - PullRequest
8 голосов
/ 03 июня 2011

У меня есть строка NSString (например, «2011-04-12 19:23:39»), и я отформатировал ее для NSDate:

[inputFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];

NSDate *date = [inputFormatter dateFromString:newDateString];

но что он выводит, когда я пишу nslog, это дата:

2011-04-12 23:23:39 + 0000

, что составляет около 4 часов. Я что-то пропустил? Возможно, проблема с часовым поясом?

Ответы [ 5 ]

5 голосов
/ 03 июня 2011

Короче, ответ: дата возвращается по Гринвичу, если не указано иное. Вы можете установить часовой пояс, чтобы получить правильную дату. Если вы планируете использовать дату в приложении, чтобы установить что-либо (например, местное время уведомления или событие), вам нужно будет сделать что-то особенное с датой, потому что если вы установите дату в iPhone, она будет установлена ​​как время по Гринвичу и будет отключена. на несколько часов. (в вашем случае 4 часа). Я делаю именно эту вещь, которую я только что описал в одном из моих приложений.

Я сделал беспорядок, пытаясь заставить это работать правильно, не имея нерабочих часов. Это была огромная PITA, чтобы понять, но она работает сейчас. Я скопировал, вставил и отредактировал свой код, чтобы поделиться им. Опять же, это грязно, но это работает! PickerChanged получает информацию от UIDatePicker

Используя код ниже. Чтобы ответить на ваш вопрос, вы можете остановиться на «destinationDate». Это вернет вам исправленное время для вашего текущего часового пояса. Я только что предоставил дополнительный случай, когда вы пытались использовать дату где-нибудь в телефоне.

ПРИМЕЧАНИЕ: для быстрого примера я поместил напоминание о событии в ту же функцию, что и указатель даты, вы НЕ захотите делать это, иначе у вас будет много напоминаний, установленных каждый раз, когда колесо прокручивается в указателе даты.

Код ниже.

 - (void)pickerChanged:(id)sender
    {

        NSLog(@"value: %@",[sender date]);

        NSDate* date= [sender date]; 
        NSDateFormatter *formatter=[[[NSDateFormatter alloc]init]autorelease]; 
        [formatter setDateFormat:@"MM/dd/yyyy hh:mm:ss a"];
        [formatter setTimeZone:[NSTimeZone systemTimeZone]];

        [formatter setTimeStyle:NSDateFormatterLongStyle]; 

        NSString *dateSelected =[formatter stringFromDate:date]; 

        NSString *timeZone = [dateSelected substringFromIndex:12];



    NSTimeZone* destinationTimeZone = [NSTimeZone systemTimeZone];

    //here we have to get the time difference between GMT and the current users Date (its in seconds)
        NSInteger destinationGMTOffset = [destinationTimeZone secondsFromGMTForDate:date];

    //need to reverse offset so its correct when we put it in the calendar
        correctedTimeForCalendarEvent = destinationGMTOffset + (2*(-1*destinationGMTOffset));

    //date to enter into calendar (we will use the correctedTimeForCalendarEvent to correct the time otherwise it will be off by a few hours )
       NSDate * destinationDate = [[[NSDate alloc] initWithTimeInterval:destinationGMTOffset sinceDate:date] autorelease];
        NSDate * dateForReminder = destinationDate;
        // return destinationDate;
        NSLog(@"value: %@ - %@",destinationDate,dateForReminder);

//DO NOT put this code in this same function this is for a quick example only on StackOverflow
//otherwise you will have reminders set everytime the users scrolled to a different time
    //set event reminder
    //make sure to import EventKit framework

        EKEventStore *eventDB = [[[EKEventStore alloc] init]autorelease];
        EKEvent *myEvent  = [EKEvent eventWithEventStore:eventDB];
        NSString * eventTitle = [NSString stringWithFormat:@"%@ - %@",app.dealerBusinessName,serviceOrComments.text];
        myEvent.title = eventTitle;

    //double check date one more time
        NSLog(@"value: %@",destinationDate);

    //set event time frame (1 hour) the "initWithTimeInterval" is where we account for the users timezone by adding the correctedTime from GMT to the calendar time ( so its not off by hours when entering into calendar)
        myEvent.startDate = [[[NSDate alloc] initWithTimeInterval:correctedTimeForCalendarEvent sinceDate:destinationDate ]autorelease];
        myEvent.endDate   = [[[NSDate alloc] initWithTimeInterval:3600 sinceDate:myEvent.startDate]autorelease];
        myEvent.allDay = NO;

    //set event reminders 1 day and 1 hour before
        myAlarmsArray = [[[NSMutableArray alloc] init] autorelease];
        EKAlarm *alarm1 = [EKAlarm alarmWithRelativeOffset:-3600]; // 1 Hour
        EKAlarm *alarm2 = [EKAlarm alarmWithRelativeOffset:-86400]; // 1 Day
        [myAlarmsArray addObject:alarm1];
        [myAlarmsArray addObject:alarm2];
        myEvent.alarms = myAlarmsArray;



        [myEvent setCalendar:[eventDB defaultCalendarForNewEvents]];

        NSError *err;

        [eventDB saveEvent:myEvent span:EKSpanThisEvent error:&err]; 

        if (err == noErr) {
            //no error, but do not show alert because we do that below.
        }

    }
2 голосов
/ 03 июня 2011

NSDateFormatter использовать текущий часовой пояс устройства при создании объекта NSDate.NSDate хранит дату / время в GMT.Поэтому по умолчанию NSLog будет выводить дату / время в GMT + 0.Так что с вашим кодом все в порядке.Теперь, если вы хотите вывести NSDate в текущий часовой пояс, вам придется использовать объект NSDateFormatter.

1 голос
/ 03 июня 2011

Используйте -[NSDateFormatter setTimeZone:], чтобы предоставить форматеру даты информацию о часовом поясе. Вы можете использовать местный часовой пояс, или если у вас есть фиксированный часовой пояс, связанный с информацией о дате, я рекомендую создать часовой пояс с именем (например, «Америка / Восток»), а не с аббревиатурой (например, «EST» или «EDT»), поскольку название не заставляет переходить на летнее время, а использует правильное смещение для летнего времени для этой даты в этом часовом поясе.

1 голос
/ 03 июня 2011

Дата регистрируется как дата UTC, которую можно увидеть по +0000 в конце.Формат даты, который вы используете для анализа строки, предполагает ваш местный часовой пояс, который предположительно на 4 часа отстает от UTC с переходом на летнее время и стандартными -5 часами.

1 голос
/ 03 июня 2011

В ваших средствах форматирования данных и даты пропущен спецификатор TimeZone. Так что-то вроде этого:

[inputFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ssZ"];

Будет работать - Z - это указатель часового пояса, который будет анализировать как числовые смещения, так и коды часовых поясов. Хотя в вашем случае, поскольку ваша дата ввода не имеет информации о TimeZone, она не будет работать.

Ваша правильная строка времени должна выглядеть как "2011-04-12 19:23:39 -0400" или "2011-04-12 19:23:39 EST"

В зависимости от того, откуда вы получаете свою дату, вы должны исправить это, чтобы получить полностью определенную дату, если вы не можете этого сделать, вам придется согласовать смещения часового пояса с сервером или просто «жестко кодировать» смещение часового пояса и добавьте это количество секунд к вашей NSDate.

...