2011-05-23 3 views
2

J'ai un morceau de code qui a fonctionné dans le passé (du moins je pense que c'était le cas car sinon le problème aurait été reconnu plus tôt). Depuis quelques semaines, pourrait être depuis DST, il a commencé à produire des résultats incorrects.Fuseau horaire Problème avec DST (le mystérieux manquant deux heures)

Cet extrait est censé générer un objet NSDate se référant au premier jour de la semaine des dates données à 00: 00h.

NSCalendar *gregorianCalender = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease]; 
NSDate *firstDayDate; 

unsigned yearAndWeek = NSTimeZoneCalendarUnit | NSYearCalendarUnit | NSWeekCalendarUnit; 

// retrieve the components from the current date 
NSDateComponents *compsCurrentDate = [gregorianCalender components:yearAndWeek fromDate:date]; 

[compsCurrentDate setWeekday:2]; // Monday 
[compsCurrentDate setHour:0]; 
[compsCurrentDate setMinute:0]; 
[compsCurrentDate setSecond:0]; 

// make a date from the modfied components 
firstDayDate = [gregorianCalender dateFromComponents:compsCurrentDate]; 

NSLog(@"MONDAY: %@", firstDayDate); 

Aujourd'hui est le 24 mai donc la dernière ligne devrait imprimer quelque chose comme

MONDAY: 2011-05-23 00:00:00 +0000 

mais il imprime vraiment la

suivante
MONDAY: 2011-05-22 22:00:00 +0000 

ce qui est évidemment faux. Le 22 mai était dimanche dernier. Maintenant, pour faire des choses étranges, le résultat est correct à nouveau quand je change la setHour:0 à

[compsCurrentDate setHour:2]; 

Je pense, qu'il ya quelque chose de mal sur les fuseaux horaires. Mais après avoir passé une demi-journée sur la documentation d'Apple, google et stackoverflow je n'ai pas pu comprendre quel est le problème. Peut-être que j'utilise les mauvais mots-clés ou que je suis le seul à avoir ce problème.

Toutes les informations sont très appréciées! S'il vous plait, faite moi part de votre avis! Je vous remercie!

Répondre

3

Puisque personne n'a pu répondre que je continuais mes recherches et a découvert un détail simple mais fatale dans la documentation de NSData: la méthode description qui est appelé en essayant d'imprimer la NSDate comme NSString par défaut utilise un « défaut » NSLocale pour déterminer le format et le fuseau horaire. Donc tout ce qui concerne mon code était correct, le vrai problème que j'ai essayé de résoudre était ailleurs et je l'ai déjà fait lundi. Je devrais RTFM plus intense;)

La ligne de code suivante imprime l'heure correcte pour mon fuseau horaire :

NSLog(@"MONDAY: %@", [firstDayDate descriptionWithLocale:[NSLocale systemLocale]]); 

Néanmoins, au cours de mes recherches, je découvre quelques extraits intéressants faisant essentiellement la même chose (bien que la sortie était « mauvaise » et, voilà pourquoi je ne remplacerai pas seulement le mien). Prenant tous en considération ma tentative fonctionne mais un peu cahoteuse. Le plus facile et robuste, j'ai trouvé provient de la documentation Apple lui-même et peut également être trouvé sur différents sites:

/* VERSION FROM APPLE DOKU */ 
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; 

// Get the weekday component of the current date 
NSDateComponents *weekdayComponents = [gregorian components:NSWeekdayCalendarUnit fromDate:date]; 

/* 
Create a date components to represent the number of days to subtract from the current date. 
The weekday value for Monday in the Gregorian calendar is 2, so subtract 2 from the number of days to subtract from the date in question. (If today's Sunday, subtract 0 days.) 
*/ 
NSDateComponents *componentsToSubtract = [[NSDateComponents alloc] init]; 
[componentsToSubtract setDay: 0 - ([weekdayComponents weekday] - 2)]; 

NSDate *beginningOfWeek = [gregorian dateByAddingComponents:componentsToSubtract toDate:date options:0]; 

/* 
Optional step: 
beginningOfWeek now has the same hour, minute, and second as the original date (today). 
To normalize to midnight, extract the year, month, and day components and create a new date from those components. 
*/ 
NSDateComponents *components = 
[gregorian components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) 
      fromDate: beginningOfWeek]; 
beginningOfWeek = [gregorian dateFromComponents:components]; 

NSLog(@"MONDAY: %@", [beginningOfWeek descriptionWithLocale:[NSLocale systemLocale]]); 

Enfin, pour compléter ceci: un extrait comment calculer la dernière jours de la semaine en cours.

// reuse the "first day" to calculate the last day 
NSDate *endOfLastWeek = [whateveryourobject andmethodiscalled]; 

NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; 

/* 
endOfLastWeek now is monday in the current week so create date components to add one week to the current date 
*/ 
NSDateComponents *componentsToAdd = [[NSDateComponents alloc] init]; 
[componentsToAdd setWeek:1]; 

NSDate *endOfWeek = [gregorian dateByAddingComponents:componentsToAdd toDate:endOfLastWeek options:0]; 

NSLog(@"SUNDAY: %@", [endOfWeek descriptionWithLocale:[NSLocale systemLocale]]); 
Questions connexes