NSDateComponents组件:fromDate和Time Zones

mmc*_*omb 11 iphone objective-c nsdatecomponents

我有一种方法,通过将其分解为NSDateComponents,将小时和第二组分从NSDate中提取出来.我的代码如下......

unsigned hourAndMinuteFlags = NSHourCalendarUnit | NSMinuteCalendarUnit;
NSCalendar* calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
[calendar setTimeZone:[NSTimeZone timeZoneWithName:@"GMT"]];
NSDateComponents* travelDateTimeComponents = [calendar components:hourAndMinuteFlags fromDate:travelDate];
NSString* hours = [NSString stringWithFormat:@"%02i", [travelDateTimeComponents hour]];
NSString* minutes = [NSString stringWithFormat:@"%02i", [travelDateTimeComponents minute]];
Run Code Online (Sandbox Code Playgroud)

我的问题是我在转换中损失了一个小时.我怀疑它是由时区引起的,但据我所知,日期传入和使用的日历都是GMT.

例如,如果我传入以下NSDate对象(这是[NSDate description]的日志)...

2010-08-02 08:00:00 +0100
Run Code Online (Sandbox Code Playgroud)

我希望我能获得8小时和0分钟,但实际上我的工作时间是7小时.

我的系统时间是GMT,因此上面的NSDate目前是英国夏令时的+0100.

aqu*_*qua 15

另外请记住,NSDate对象总是根据GMT显示时间,而从该日期开始拉动的组件会被timeZoneWithName零件改变.

例:

NSDate *today = [NSDate date];
NSLog(@"Today's date: %@",today);

unsigned hourAndMinuteFlags = NSHourCalendarUnit | NSMinuteCalendarUnit;
NSCalendar* calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
[calendar setTimeZone:[NSTimeZone timeZoneWithName:@"GMT"]];
NSDateComponents* travelDateTimeComponents = [calendar components:hourAndMinuteFlags fromDate:today];
NSString* hours = [NSString stringWithFormat:@"%02i", [travelDateTimeComponents hour]];
NSString* minutes = [NSString stringWithFormat:@"%02i", [travelDateTimeComponents minute]];

NSLog(@"Calendar: %@",calendar);
NSLog(@"Travel Components: %@",travelDateTimeComponents);
NSLog(@"Hours: %@",hours);
NSLog(@"Minutes: %@",minutes);
Run Code Online (Sandbox Code Playgroud)

控制台输出:

[Session started at 2011-01-23 12:59:17 -0700.]
2011-01-23 12:59:19.755 testttt[5697:207] Today's date: 2011-01-23 19:59:19 +0000
2011-01-23 12:59:19.756 testttt[5697:207] Calendar: <__NSCFCalendar: 0x4b2ca70>
2011-01-23 12:59:19.757 testttt[5697:207] Travel Components: <NSDateComponents: 0x4b2de20>
2011-01-23 12:59:19.757 testttt[5697:207] Hours: 19
2011-01-23 12:59:19.758 testttt[5697:207] Minutes: 59
Run Code Online (Sandbox Code Playgroud)

现在,如果我们改变时区......

NSDate *today = [NSDate date];
NSLog(@"Today's date: %@",today);

unsigned hourAndMinuteFlags = NSHourCalendarUnit | NSMinuteCalendarUnit;
NSCalendar* calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
[calendar setTimeZone:[NSTimeZone timeZoneWithName:@"MST"]];
NSDateComponents* travelDateTimeComponents = [calendar components:hourAndMinuteFlags fromDate:today];
NSString* hours = [NSString stringWithFormat:@"%02i", [travelDateTimeComponents hour]];
NSString* minutes = [NSString stringWithFormat:@"%02i", [travelDateTimeComponents minute]];

NSLog(@"Calendar: %@",calendar);
NSLog(@"Travel Components: %@",travelDateTimeComponents);
NSLog(@"Hours: %@",hours);
NSLog(@"Minutes: %@",minutes);
Run Code Online (Sandbox Code Playgroud)

输出:

2011-01-23 13:05:29.896 testttt[5723:207] Today's date: 2011-01-23 20:05:29 +0000
2011-01-23 13:05:29.897 testttt[5723:207] Calendar: <__NSCFCalendar: 0x4e10020>
2011-01-23 13:05:29.897 testttt[5723:207] Travel Components: <NSDateComponents: 0x4e0f6d0>
2011-01-23 13:05:29.898 testttt[5723:207] Hours: 13
2011-01-23 13:05:29.898 testttt[5723:207] Minutes: 05
Run Code Online (Sandbox Code Playgroud)

请注意当地时间和分钟如何变化,但"今天的日期:"部分仍然反映了GMT.如果你问我,有点误导程序员.


Ole*_*ann 5

问题是,GMT不等于英国夏令时.日期2010-08-02 08:00:00 +0100等于2010-08-02 07:00:00 GMT7小时是你应该期待的结果.


小智 5

我同意阿库娅的观点。这是非常具有误导性的,导致我好几天都用头撞屏幕。它的工作原理如下: [NSDate date] 始终返回当前日期。因此,在上面的示例中,它将是 2010-08-02 08:00:00。当我们转换为 NSDateComponents 时,实际时间会丢失并转换为一组不再包含时区的整数(小时、年等)。

当转换回 NSDate 对象时,它将获取年、月、日等的值,并将其提供给您相对于 GMT 的值,因此会损失一小时。这只是框架中决定的方式。我所做的如下:

+(NSDateComponents *)getComponentFromDate:(NSDate *)date {

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

    unsigned unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit | NSWeekdayCalendarUnit | NSDayCalendarUnit;
    NSDateComponents* components = [gregorian components:unitFlags fromDate:date];

    NSTimeZone* timeZone = [NSTimeZone localTimeZone];
    if(timeZone.isDaylightSavingTime) components.hour = ((int)timeZone.daylightSavingTimeOffset/3600);

    [gregorian release];

    return components;
}
Run Code Online (Sandbox Code Playgroud)

这将为我提供一个四舍五入到当前日期的组件的“更正”版本,当传递到日历以检索日期时,该版本将始终设置为作为参数传递的日期当天的 00:00:00。