Formato NSDate saindo da data errada

Eu tenho um NSString (ex. “2011-04-12 19:23:39”), e o que eu fiz para formatá-lo para um NSDate foi o seguinte:

[inputFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"]; NSDate *date = [inputFormatter dateFromString:newDateString]; 

mas o que sai quando eu nslog a data é esta:

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

que é cerca de 4 horas de folga. Existe algo que eu perdi? Possivelmente um problema de fuso horário?

NSDateFormatter usa o fuso horário do dispositivo atual quando criou o object NSDate. NSDate armazena a data / hora em GMT. Portanto, por padrão, o NSLog emitirá a data / hora em GMT + 0. Então, não há nada de errado com o seu código. Agora, se você deseja produzir o NSDate para o seu fuso horário atual, você terá que usar um object NSDateFormatter.

A resposta, em suma, é a data está sendo retornada GMT, a menos que especificado de outra forma. Você pode definir seu fuso horário para obter a data correta. Se você planeja usar a data no app para definir qualquer coisa (como localNotification time ou Event), você precisará fazer algo especial com a data, pois se você definir a data no iPhone, ela será definida como GMT e desativada. por algumas horas. (no seu caso 4 horas). Eu faço exatamente isso que acabei de descrever em um dos meus apps.

Eu fiz uma bagunça de tentar fazer com que isso funcionasse corretamente sem que as horas acabassem. Foi um enorme PITA para descobrir, mas está funcionando agora. Copiei, colei e editei meu código para compartilhar. Mais uma vez, é confuso, mas funciona! O pickerChanged está recebendo suas informações de um UIDatePicker

Usando o código abaixo. Para responder à sua pergunta, você pode parar em “destinationDate”. Isso retornará a você o horário correto para seu fuso horário atual. Eu apenas forneci o extra caso você estivesse tentando usar a data no telefone em algum lugar.

NOTA: para um exemplo rápido eu coloquei o lembrete de events na mesma function que o datepicker, você não vai querer fazer isso caso contrário você terá um monte de lembretes definidos toda vez que a roda rola no datepicker.

O código está abaixo.

  - (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. } } 

Seus dados e formatador de data omitem o especificador TimeZone. Então, algo assim:

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

Funcionaria – o Z é o especificador de fuso horário e analisará os deslocamentos numéricos e os códigos de fuso horário. Embora, no seu caso, a data de input não tenha informações de fuso horário, isso não funcionará.

Sua seqüência de tempo correta deve ser como “2011-04-12 19:23:39 -0400” ou “2011-04-12 19:23:39 EST”

Dependendo de onde você obtém sua data, você deve corrigir isso para produzir uma data totalmente qualificada, se você não puder fazer isso, terá que concordar com as compensações de fuso horário com o servidor ou simplesmente com “código rígido” de um fuso horário e adicionar esse número de segundos para o seu NSDate.

A data está sendo registrada como uma data UTC pode ser vista pelo +0000 no final. O formato de data que você está usando para analisar a string assume seu fuso horário local, que é presumivelmente 4 horas após UTC com horário de verão e o padrão -5 horas.

Use -[NSDateFormatter setTimeZone:] para fornecer o formatador de data com informações de fuso horário. Você pode usar o fuso horário local ou se tiver um fuso horário fixo associado às informações de data, eu recomendo criar o fuso horário com o nome (como “América / Leste”) em vez da abreviação (como “EST” ou “EDT”), já que o nome não força a economia de horário em vigor, mas usa o deslocamento de horário de verão correto para essa data nesse fuso horário.