NSDateComponents отсутствует 1 секунда из разницы 2 дат - PullRequest
3 голосов
/ 15 августа 2011

У меня действительно неприятная проблема, которая, кажется, не имеет никакого смысла. Я пытаюсь получить количество лет между двумя датами. Вот мой код.

// 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

Даты начала и окончания выглядят одинаково сохраненными за 10 лет между мной, но по какой-то причине я пропускаю 1 секунду времени. Кто-нибудь знает почему?

Заранее спасибо!

ДОБАВЛЕНО

Вот способ, которым я инициализировал и сохранил 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 ]

1 голос
/ 15 августа 2011

Я создал простой проект с двумя UIDatePickers в одном ViewController. Я инициализировал каждый UIDatePicker для контрольной даты и установил метод действия для расчета разницы между датами двух UIDatePicker каждый раз, когда один из них изменяется. Я вставил ваш код в этот метод, а затем протестировал его в iPhone Simulator. В результате ваш код выдает ровно 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 инициализируются на дату, когда они были созданы (включая часы, минуты, секунды и т. Д., Даже если вы указываете только год, месяц и день в средстве выбора).

Возможно ли, что вы вводите это несоответствие другим способом? Возможно, вы делаете какие-то другие вычисления или манипуляции с датой?

EDIT:

В коде, который вы добавили, вы должны ссылаться на конечную дату из начальной даты, а не из другого объекта даты. Я знаю, что вы сказали, что это не имеет значения, но лучше использовать startdate, чем предполагать, что сегодня и startdate будут иметь одинаковое значение.

Другая вещь, которую стоит рассмотреть, это ваши setStartDate: и setEndDate: методы. В этих методах установки я бы рекомендовал округлять до 0 любой точности, которая вам не нужна. Если вы не позволяете пользователю устанавливать что-либо более точное, чем день, то установите более высокую точность на 0. Таким образом, у вас не останется часов, минут или секунд между любыми двумя датами.

0 голосов
/ 19 августа 2011

После долгих попыток поработать с различными сценариями, я решил эту проблему.

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 секунду.

Спасибо всем, кто помог направить меня на правильный путь!

0 голосов
/ 15 августа 2011

Я не могу воспроизвести это на 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;
  }
}
...