2011-05-23 57 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]]);