【问题标题】:NSDateComponents components:fromDate and Time ZonesNSDateComponents 组件:fromDate 和 Time Zones
【发布时间】:2011-03-24 01:38:43
【问题描述】:

我有一个方法,它通过将小时和秒组件分解为 NSDate 组件来提取 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]];

我的问题是我在转换过程中损失了一个小时。我怀疑这是由于时区造成的,但据我所知,传入的日期和使用的日历都是 GMT。

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

2010-08-02 08:00:00 +0100

我希望小时数为 8,分钟数为 0,但实际上我的小时数是 7。

我的系统时间是格林威治标准时间,因此上面的 NSDate 目前是英国夏令时的 +0100。

【问题讨论】:

    标签: iphone objective-c nsdatecomponents


    【解决方案1】:

    还请记住,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);
    

    控制台输出:

    [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
    

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

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

    输出:

    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
    

    请注意当地小时和分钟的变化,但“今天的日期:”部分仍反映 GMT。有点误导程序员,如果你问我的话。

    【讨论】:

      【解决方案2】:

      问题是,GMT 不等于英国夏令时。日期2010-08-02 08:00:00 +0100 等于2010-08-02 07:00:00 GMT,因此您应该期待 7 小时。

      【讨论】:

        【解决方案3】:

        我同意 aqua。这是非常具有误导性的,并导致我几天都在用头撞屏幕。它的工作原理如下: [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;
        }
        

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

        【讨论】:

        • 因此,如果我只想将现在的时间与 2 个无日期的开始和结束时间进行比较,则测试失败,因为现在的时间也早于现在的日期,而其他两个时间将使用基础创建2000年。那么在这种情况下如何比较?
        • 我认为转换组件->日期考虑了日历的时区。如果您使用相同的日历,您应该能够进行无损双向转换。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-12-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-12-12
        • 1970-01-01
        相关资源
        最近更新 更多