NSDateComponents从2个日期的差异中缺失1秒

时间:2011-08-15 17:16:44

标签: iphone cocoa-touch nsdate nscalendar nsdatecomponents

有一个真正令人沮丧的问题似乎没有任何意义。我想要获得2个日期之间的年数。这是我的代码。

// Initialize variable to store calendar
NSCalendar *gregorian = [[NSCalendar alloc]  initWithCalendarIdentifier:NSGregorianCalendar];

// Break out date to year component
NSDateComponents *Components = [gregorian components:NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit
                                            fromDate:startDate
                                              toDate:endDate
                                             options:0];

// Debugging code
NSLog(@"Debug start date = %@",startDate);
NSLog(@"Debug end date = %@", endDate);
NSLog(@"Debug year = %d",[Components year]);
NSLog(@"Debug month = %d",[Components month]);
NSLog(@"Debug day = %d", [Components day]);
NSLog(@"Debug hours = %d",[Components hour]);
NSLog(@"Debug minutes = %d", [Components minute]);
NSLog(@"Debug seconds = %d", [Components second]);

[gregorian release];

// Check which component to extract and return value accordingly
// Defaults to month for now
if ([datecomponent isEqualToString:@"year"]) {
    return [Components year];
}
else {
    return [Components month];
}

开始日期和结束日期由UIDatePickers在其他地方设置。他们默认相隔10年。一旦我回到控制结束日期的UIDatePicker并将其移动到1年前。问题将开始出现。这是我将结束日期移回原始日期后我将看到的NSLog的示例。我应该看到其他地方的10年和0年,但我错过了1秒钟。

Debug start date = 2011-08-15 15:55:07 +0000
Debug end date = 2021-08-15 15:55:07 +0000
Debug year = 9
Debug month = 11
Debug day = 30
Debug hours = 23
Debug minutes = 59
Debug seconds = 59

它们之间的开始和结束日期看起来相同,但是由于某些原因,我错过了1秒的时间。有谁知道为什么?

提前致谢!

ADDED

这是我初始化和存储2个日期的方式。

开始日期在viewWillAppear方法中。

- (void)viewWillAppear:(BOOL)animated {
    if ([managedObject valueForKeyPath:self.keypath] != nil)
        [self.datePicker setDate:[managedObject
                                  valueForKeyPath:keypath] animated:YES];
    else
        [self.datePicker setDate:[NSDate date] animated:YES];
    [self.tableView reloadData];

    [super viewWillAppear:animated];

}

同样的类也用于我的结束日期,但是我在NSManagedObject的自定义子类中添加了以下代码: -

- (void)awakeFromInsert {
    [super awakeFromInsert];

    // Set default date of registration to be today's date
    self.startdate = [NSDate date];

    NSDate *today = [[NSDate alloc] init]; // I also tried to equate this to self.startdate but there is no difference
    NSCalendar *gregorian = [[NSCalendar alloc]     initWithCalendarIdentifier:NSGregorianCalendar];
    NSDateComponents *offsetComponents = [[NSDateComponents alloc] init];
    [offsetComponents setYear:10];
    self.enddate = [gregorian dateByAddingComponents:offsetComponents toDate:today     options:0];

}

这会造成任何问题吗?如果是,为什么调试会显示开始日期和结束日期,包括它们的时间完全相同?

3 个答案:

答案 0 :(得分:1)

我在一个ViewController中创建了一个带有两个UIDatePickers的简单项目。我将每个UIDatePicker初始化为参考日期,并设置一个操作方法,以便在每次更改其中一个UIDatePickers时计算两个UIDatePickers的日期之间的差异。我将您的代码插入到该方法中,然后在iPhone模拟器中对其进行测试。结果是您的代码输出正好10年:

2011-08-15 11:18:44.225 test[1004:b303] Debug start date = 2001-01-01 00:00:00 +0000
2011-08-15 11:18:44.225 test[1004:b303] Debug end date = 2011-01-01 00:00:00 +0000
2011-08-15 11:18:44.226 test[1004:b303] Debug year = 10
2011-08-15 11:18:44.226 test[1004:b303] Debug month = 0
2011-08-15 11:18:44.227 test[1004:b303] Debug day = 0
2011-08-15 11:18:44.227 test[1004:b303] Debug hours = 0
2011-08-15 11:18:44.227 test[1004:b303] Debug minutes = 0
2011-08-15 11:18:44.228 test[1004:b303] Debug seconds = 0

您是否在使用之前将UIDatePickers初始化为同一时间?默认情况下,UIDatePickers初始化为创建日期(包括小时,分钟,秒等,即使您只在选择器中显示年,月和日)。

您是否有可能以其他方式介绍这种差异?也许你在约会时正在做一些其他的计算或操作?

编辑:

在您添加的代码中,您应该从startdate引用enddate,而不是从另一个日期对象引用enddate。我知道你说它没有什么区别,但是使用startdate比使用startdate更好,而不是假设今天和startdate具有相同的值。

要考虑的另一件事是您的setStartDate:setEndDate:方法。在那些setter方法中,我建议将您不需要的任何精度舍入到0。如果您不允许用户设置比日期更精确的任何内容,则将更高精度设置为0.这样,您将不会在任何两个日期之间留下超过数小时,分钟或秒数。

答案 1 :(得分:0)

我无法在10.7上重现这一点。你在构建什么SDK?

2011-08-15 13:51:44.262 test[9420:707] Debug start date = 2011-08-15 15:55:07 +0000
2011-08-15 13:51:44.263 test[9420:707] Debug end date = 2021-08-15 15:55:07 +0000
2011-08-15 13:51:44.263 test[9420:707] Debug year = 10
2011-08-15 13:51:44.264 test[9420:707] Debug month = 0
2011-08-15 13:51:44.264 test[9420:707] Debug day = 0
2011-08-15 13:51:44.265 test[9420:707] Debug hours = 0
2011-08-15 13:51:44.265 test[9420:707] Debug minutes = 0
2011-08-15 13:51:44.266 test[9420:707] Debug seconds = 0

请注意,这里没有理由提取日,小时,分钟和秒。另外,如果datecomponent不是year,那么在您的情况下,这将返回0。我假设你真的意味着它返回120?或者你是以不同的方式使用它?

这是我的完整程序(适用于10.7,命令行模板):

int main (int argc, const char * argv[]) {
  @autoreleasepool {
    // Initialize variable to store calendar
    NSDate *startDate = [NSDate dateWithString:@"2011-08-15 15:55:07 +0000"];
    NSDate *endDate = [NSDate dateWithString:@"2021-08-15 15:55:07 +0000"];

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

    // Break out date to year component
    NSDateComponents *components = [gregorian components:NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit
                                                fromDate:startDate
                                                  toDate:endDate
                                                 options:0];

    // Debugging code
    NSLog(@"Debug start date = %@",startDate);
    NSLog(@"Debug end date = %@", endDate);
    NSLog(@"Debug year = %ld",[components year]);
    NSLog(@"Debug month = %ld",[components month]);
    NSLog(@"Debug day = %ld", [components day]);
    NSLog(@"Debug hours = %ld",[components hour]);
    NSLog(@"Debug minutes = %ld", [components minute]);
    NSLog(@"Debug seconds = %ld", [components second]);

//    [gregorian release];
    return 0;
  }
}

答案 2 :(得分:0)

在对各种场景进行了相当多的修补之后,这就是我解决问题的方法。

1)由于找到日期之间差异的代码由几个独立的各方检查确定,我已将其作为问题来源消除。

2)我删除了任何试图修改我的应用中日期的代码,这些代码本来就不应该存在。

3)我现在在创建开始日期和结束日期时初始化时间,以确保它们不是基于我在数据库中创建条目时的任意时间。

以下是初始化开始日期的代码段。

NSDate *now = [NSDate date];
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *settomidnight = [calendar components:NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit fromDate:now];
[settomidnight setHour:0];
[settomidnight setMinute:0];
[settomidnight setSecond:0];
startdate = [calendar dateFromComponents:settomidnight];

有了这个,我从NSLog看到时间现在设置为16:00 +0000(转换到我的时区后对我来说是午夜)。问题现在消失了,我不再失去1秒钟。

感谢所有帮助我指导正确道路的人!