#iphone #objective-c #nsdate #nsdateformatter
#iPhone #objective-c #nsdate #nsdateformatter
Вопрос:
У меня есть NSString (пример. «2011-04-12 19:23:39»), и что я сделал, чтобы отформатировать его в NSDate, было следующим:
[inputFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
NSDate *date = [inputFormatter dateFromString:newDateString];
но то, что он выводит, когда я записываю дату в nsdate, это:
2011-04-12 23:23:39 0000
это примерно через 4 часа. Я что-то пропустил? Возможно, проблема с часовым поясом?
Комментарии:
1. Находитесь ли вы в часовом поясе GMT-4?
Ответ №1:
Короче говоря, ответ заключается в том, что дата возвращается по Гринвичу, если не указано иное. Вы можете установить свой часовой пояс, чтобы получить правильную дату. Если вы планируете использовать дату в приложении для установки чего-либо (например, времени локального уведомления или события), вам нужно будет сделать что-то особенное с датой, потому что, если вы установите дату в iPhone, она будет установлена как время GMT и будет отключена на несколько часов. (в вашем случае 4 часа). Я делаю именно то, что только что описал в одном из своих приложений.
Я запутался, пытаясь заставить это работать правильно, не отключая часы. Разобраться с этим было непросто, но сейчас это работает. Я скопировал, вставил и отредактировал свой код, чтобы поделиться. Опять же, это грязно, но это работает! pickerChanged получает свою информацию из UIDatePicker
Используя приведенный ниже код. Чтобы ответить на ваш вопрос, вы можете остановиться на «destinationDate». Это вернет вам исправленное время для вашего текущего часового пояса. Я просто предоставил дополнительную информацию на случай, если вы пытались где-то использовать дату в телефоне.
ПРИМЕЧАНИЕ: для краткого примера я включил напоминание о событии в ту же функцию, что и datepicker, вы не захотите этого делать, иначе у вас будет множество напоминаний, устанавливаемых каждый раз, когда колесо прокручивается в datepicker.
Код приведен ниже.
- (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:amp;err];
if (err == noErr) {
//no error, but do not show alert because we do that below.
}
}
Ответ №2:
NSDateFormatter использует текущий часовой пояс устройства при создании объекта NSDate. NSDate сохраняет дату / время в формате GMT. Поэтому по умолчанию NSLog выводит дату / время в формате GMT 0. Итак, с вашим кодом все в порядке. Теперь, если вы хотите вывести NSDate в свой текущий часовой пояс, вам придется использовать объект NSDateFormatter.
Ответ №3:
В ваших данных и программе форматирования даты отсутствует спецификатор часового пояса. Итак, что-то вроде этого:
[inputFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ssZ"];
Будет работать — Z является спецификатором часового пояса и будет анализировать как числовые смещения, так и коды часового пояса. Хотя в вашем случае, поскольку ваша вводимая дата не содержит информации о часовом поясе, это не сработает.
Ваша правильная строка времени должна быть похожа на «2011-04-12 19:23:39 -0400» или «2011-04-12 19: 23: 39 EST».
В зависимости от того, откуда вы получаете свою дату, вам следует исправить это, чтобы получить полную дату, если вы не можете этого сделать, вам придется согласовать смещения часовых поясов с сервером или просто «жестко запрограммировать» смещение часовых поясов и добавить это количество секунд к вашей NSDate.
Ответ №4:
Дата регистрируется как дата UTC, что видно по 0000
в конце. Формат даты, который вы используете для анализа строки, предполагает ваш местный часовой пояс, который предположительно на 4 часа отстает от UTC с переходом на летнее время и стандартными -5 часами.
Ответ №5:
Используется -[NSDateFormatter setTimeZone:]
для предоставления программе форматирования даты информации о часовом поясе. Вы можете использовать местный часовой пояс или, если у вас есть фиксированный часовой пояс, связанный с информацией о дате, я рекомендую создать часовой пояс с именем (например, «Америка / Восток»), а не с сокращением (например, «EST» или «EDT»), поскольку название не вводит в действие переход на летнее время, но использует правильное смещение перехода на летнее время для этой даты в этом часовом поясе.