2011-05-23 58 views
2

我有一段過去確實有用的代碼(至少我認爲它的確如此,否則問題早已被認出)。自從幾個星期以來,可能是自DST以來,它開始產生不正確的結果。DST(神祕失蹤的兩小時)的時區問題

這段代碼應該生成一個NSDate對象,指向給定日期周的第一天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); 

今天是五月的第24屆所以最後一行應打印像

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

但它確實打印以下

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

這顯然是錯誤的。五月二十二日是星期天。現在,爲了讓事情奇怪,當我再次改變setHour:0

[compsCurrentDate setHour:2]; 

我的猜測是,有什麼東西錯了時區的結果是正確的。但花了半天的時間在Apple文檔上,谷歌和stackoverflow我無法弄清楚問題是什麼。也許我使用了錯誤的關鍵字,或者我是唯一一個遇到這個問題的人。

每一條信息都非常感謝!請讓我知道你在想什麼!謝謝!

回答

3

既然沒有人能回答我繼續我的研究和發現的NSData文檔中一個簡單而致命的細節:description方法試圖打印NSDateNSString默認情況下,當使用被稱爲「默認」 NSLocale確定格式和時區。所以關於我的代碼的一切都是正確的,我試圖修復的真正問題是在其他地方,我已經做到了這一點星期一..我應該RTFM更激烈;)

下面的代碼行打印我的時區的正確時間:

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

然而,我的研究過程中,我發現了一些有趣的片段基本上做同樣的事情(雖然輸出是「錯誤」吧,這就是爲什麼我沒有簡單地替代礦)。考慮到所有這些,我的嘗試正在工作,但有點顛簸。我發現最容易和強大的來自蘋果文檔本身,也可以在不同的網站上找到:

/* 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]]); 

最後,爲了完成這樣的:一個片斷如何計算最後天本週的。

// 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]]);