Как искать NSDate?

У меня есть NSDate, который я хочу найти в своем предикате. Однако время может быть не 2009-12-06 00:00:00 +0000, а скорее похоже на 2009-12-06 3:05:90 +0000. Итак, как я могу найти любую дату, которая укладывается в рамки этого дня (24 часа).

Редактировать:

Это методы, связанные с сбоем:

Сбой происходит в this method, связанном с календарем. API-фреймворк

- (void) reactToTouch:(UITouch*)touch down:(BOOL)down
{
    ...
    if ([marks count] > 0) {
        if([[marks objectAtIndex: row * 7 + column] boolValue])
            [self.selectedImageView addSubview:self.dot];
        else
            [self.dot removeFromSuperview];
    }else{
        [self.dot removeFromSuperview];
    }
    ...
}

Этот график устанавливает дату графика и точки для даты, если есть данные для этой даты.

- (NSArray*)calendarMonthView:(TKCalendarMonthView *)monthView marksFromDate:(NSDate *)startDate toDate:(NSDate *)lastDate {    
    NSLog(@"calendarMonthView marksFromDate toDate");   

    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Session" inManagedObjectContext:self.managedObjectContext];
    [request setEntity:entity];
    [request setResultType:NSDictionaryResultType];
    [request setReturnsDistinctResults:YES];
    [request setPropertiesToFetch :[NSArray arrayWithObject:@"timeStamp"]];

    NSError *error;
    NSArray *objects = [managedObjectContext executeFetchRequest:request error:&error];
    NSArray *tempData = [objects valueForKey:@"timeStamp"];

    NSMutableArray * data1 = [NSMutableArray array];
    NSCalendar * gregorian = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease];
    [gregorian setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"GMT"]];
    NSUInteger flags = ( NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit );
    NSDateFormatter* formatter = [[[NSDateFormatter alloc] init] autorelease];
    [formatter setDateFormat:@"YYYY-MM-dd HH:mm:ss Z"];
    [formatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"GMT"]];

    [tempData enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
        NSDate * date = [gregorian dateFromComponents:[gregorian components:flags fromDate:obj]];
        [data1 addObject:[formatter stringFromDate:date]];
    }];
    self.data = data1;

    // Initialise empty marks array, this will be populated with TRUE/FALSE in order for each day a marker should be placed on.
    NSMutableArray *marks = [NSMutableArray array];

    // Initialise calendar to current type and set the timezone to never have daylight saving
    NSCalendar *cal = [NSCalendar currentCalendar];
    [cal setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];

    NSDateComponents *comp = [cal components:(NSMonthCalendarUnit | NSMinuteCalendarUnit | NSYearCalendarUnit | NSDayCalendarUnit | NSWeekdayCalendarUnit | NSHourCalendarUnit | NSSecondCalendarUnit) fromDate:startDate];

    NSDate *d = [cal dateFromComponents:comp];

    // Init offset components to increment days in the loop by one each time
    NSDateComponents *offsetComponents = [[NSDateComponents alloc] init];
    [offsetComponents setDay:1];    


    // for each date between start date and end date check if they exist in the data array
    while (YES) {
        // Is the date beyond the last date? If so, exit the loop.
        // NSOrderedDescending = the left value is greater than the right
        if ([d compare:lastDate] == NSOrderedDescending) {
            break;
        }

        // If the date is in the data array, add it to the marks array, else don't
        if ([data containsObject:[d description]]) {
            [marks addObject:[NSNumber numberWithBool:YES]];
        } else {
            [marks addObject:[NSNumber numberWithBool:NO]];
        }

        // Increment day using offset components (ie, 1 day in this instance)
        d = [cal dateByAddingComponents:offsetComponents toDate:d options:0];
    }

    [offsetComponents release];
    [request release];
    return [NSArray arrayWithArray:marks];
}

И, наконец, это метод, который мы придумали, который переходит к подробному просмотру при выборе даты:

- (void)calendarMonthView:(TKCalendarMonthView *)monthView didSelectDate:(NSDate *)d {
    NSLog(@"calendarMonthView didSelectDate");

    NSDateFormatter* formatter = [[[NSDateFormatter alloc] init] autorelease];
    [formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss Z"];
    [formatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"GMT"]];

    NSString * dateString = [formatter stringFromDate:d];

    if ( [data containsObject:dateString] ) 
    {
        NSDate * searchDate = [formatter dateFromString:dateString];
        NSCalendar * calendar1 = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease];
        NSDateComponents * dateComponents = [[[NSDateComponents alloc] init] autorelease];
        [dateComponents setDay:1];

        NSDate * searchDateEnd = [calendar1 dateByAddingComponents:dateComponents toDate:searchDate options:0];

        NSFetchRequest *request = [[NSFetchRequest alloc]init];
        NSEntityDescription *entity = [NSEntityDescription entityForName:@"Session" inManagedObjectContext:self.managedObjectContext];
        [request setEntity:entity];
        NSPredicate * predicate1 = [NSPredicate predicateWithFormat:@"timeStamp >= %@ AND timeStamp < %@", searchDate, searchDateEnd];
        [request setPredicate: predicate1];
        [request setFetchBatchSize:20];
        NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"timeStamp" ascending:NO];
        NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
        [request setSortDescriptors:sortDescriptors];
        NSError *error = nil; 
        NSArray *array = [managedObjectContext executeFetchRequest:request error:&error];
        NSLog(@"xxx array: %@", array);
        SessionViewController *sessionViewController = [[SessionViewController alloc] initWithNibName:@"SessionViewController" bundle:nil];
        self.selectedSession = (Session *)[array objectAtIndex:0];
        sessionViewController.selectedSession = self.selectedSession;

        NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; 
        [dateFormatter setDateFormat:@"MMM d, y"]; 
        NSString *dateString = [dateFormatter stringFromDate:selectedSession.timeStamp]; 
        sessionViewController.title = dateString;
        sessionViewController.hidesBottomBarWhenPushed = YES;
        [self.navigationController pushViewController:sessionViewController animated:YES];

        [sessionViewController release];
        [dateFormatter release];
        [sortDescriptor release];
        [request release];
        [sortDescriptors release];
    }
}

Редактировать:

Когда я регистрирую даты,

RawDate является прямым session.timeStamp, а dateString имеет формат даты [dateFormatter setDateFormat:@"eeee, MMM d, y"];

2011-06-27 20:13:44.936 Curl[18714:707] dateString: Monday, Jun 27, 2011
2011-06-27 20:13:44.941 Curl[18714:707] rawString: 2011-06-27 07:05:01 +0000
2011-06-27 20:13:44.961 Curl[18714:707] dateString: Thursday, Jun 23, 2011
2011-06-27 20:13:44.965 Curl[18714:707] rawString: 2011-06-23 08:12:49 +0000
2011-06-27 20:13:44.977 Curl[18714:707] dateString: Wednesday, Jun 22, 2011
2011-06-27 20:13:44.983 Curl[18714:707] rawString: 2011-06-22 21:23:08 +0000
2011-06-27 20:13:44.993 Curl[18714:707] dateString: Tuesday, Jun 21, 2011
2011-06-27 20:13:44.997 Curl[18714:707] rawString: 2011-06-22 03:23:51 +0000
2011-06-27 20:13:45.007 Curl[18714:707] dateString: Monday, Jun 20, 2011
2011-06-27 20:13:45.011 Curl[18714:707] rawString: 2011-06-21 01:03:53 +0000
2011-06-27 20:13:45.020 Curl[18714:707] dateString: Friday, Jun 17, 2011
2011-06-27 20:13:45.024 Curl[18714:707] rawString: 2011-06-18 01:03:53 +0000

person Jon    schedule 27.06.2011    source источник


Ответы (1)


Добавить день к searchDate можно с помощью NSDateComponents, используя приведенный ниже код.

NSCalendar       * calendar       = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease];

NSDateComponents * dateComponents = [[[NSDateComponents alloc] init] autorelease];
[dateComponents setDay:1];

NSDate * searchDateEnd = [calendar dateByAddingComponents:dateComponents
                                                   toDate:searchDate
                                                  options:0];

Добавьте это после того, как получите файл searchDate.

Вы также можете изменить предикат на

NSPredicate * predicate1 = [NSPredicate predicateWithFormat:@"timeStamp >= %@ AND timeStamp < %@", searchDate, searchDateEnd];

Не проверяйте равенство с верхним пределом.

Редактировать

Если вы посмотрите на код ниже,

if ([marks count] > 0) {
    if([[marks objectAtIndex: row * 7 + column] boolValue])
        [self.selectedImageView addSubview:self.dot];
    else
        [self.dot removeFromSuperview];
}

У вас нет проверок индекса, и, поскольку он, по-видимому, представляет значения, относящиеся к дням в месяце, я бы посоветовал вам проверить, есть ли действительное значение.

int size = [marks count];
if ((size > 0) && ((row * 7 + column) < size)) {
    if([[marks objectAtIndex: row * 7 + column] boolValue])
        [self.selectedImageView addSubview:self.dot];
    else
        [self.dot removeFromSuperview];
}
person Deepak Danduprolu    schedule 28.06.2011
comment
Спасибо, я думаю, это сработало, но я получаю сообщение об ошибке и вылетаю *** -[NSDateComponents release]: message sent to deallocated instance 0x5d834c0 после слов. Я обновляю вопрос с кодом, вы можете его проверить? - person Jon; 28.06.2011
comment
Удалите [dateComponents release]; и [calendar1 release];. Они уже выпущены автоматически. Или, если хотите, можете удалить сообщение autorelease. - person Deepak Danduprolu; 28.06.2011
comment
Неважно, я заметил, что вы сделали их автоматическими, вот почему. У меня все еще происходит сбой, когда я выбираю некоторые даты. - person Jon; 28.06.2011
comment
Он просто вылетает, когда я выбираю определенные даты, и говорит *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[NSArray objectAtIndex:]: index 35 beyond bounds [0 .. 34]' Однако это происходит только иногда. - person Jon; 28.06.2011
comment
Можете выложить журнал сбоев? При каком условии это происходит? Существует ли событие на эту дату? Это происходит в этом методе? или это происходит в другом методе? Я не вижу возможности доступа к индексу 35 в этом коде. - person Deepak Danduprolu; 28.06.2011
comment
Обновил мой ответ. Смотрите редактирование. Но почему вы получаете row и column, которые генерируют неправильный индекс? Есть ли пустые строки вверху, которые вы не учли? - person Deepak Danduprolu; 28.06.2011
comment
Спасибо Дипак, метод с if ([marks count] > 0) был написан не мной, а скорее частью структуры календаря библиотеки Tapku. - person Jon; 28.06.2011
comment
Я не могу быть уверен, поскольку я не использовал эту библиотеку раньше. Но разве это не должно быть [marks objectAtIndex:day]? - person Deepak Danduprolu; 28.06.2011
comment
хм, тогда это должно быть что-то не так с моим кодом, потому что это довольно популярный фреймворк, и я сомневаюсь, что в его коде что-то не так. - person Jon; 28.06.2011
comment
@ Джон, ты можешь изменить NSDateComponents *comp = [cal components:(NSMonthCalendarUnit | NSMinuteCalendarUnit | NSYearCalendarUnit | NSDayCalendarUnit | NSWeekdayCalendarUnit | NSHourCalendarUnit | NSSecondCalendarUnit) fromDate:startDate]; на NSDateComponents *comp = [cal components:(NSMonthCalendarUnit | NSYearCalendarUnit | NSDayCalendarUnit ) fromDate:startDate]; и проверить. Кроме того, попробуйте зарегистрировать startDate, endDate и все даты, которые вы повторяете в своем методе источника данных marksFromDate:toDate:? - person Deepak Danduprolu; 28.06.2011
comment
Я только что зарегистрировал массив self.data и получил data array: ( "2011-06-11 00:00:00 +0000", "2011-06-14 00:00:00 +0000", "2011-06-16 00:00:00 +0000", "2011-06-21 00:00:00 +0000", "2011-06-23 00:00:00 +0000", "2011-06-26 00:00:00 +0000" - person Jon; 28.06.2011
comment
Я также заметил, что иногда, когда я выбираю дату, дата, на которую она переходит в следующем представлении, не совпадает с той же датой, но это происходит только иногда. - person Jon; 28.06.2011
comment
НА САМОМ ДЕЛЕ, когда я комментирую код, который перемещает в новое представление, и просто делаю NSLog(@"the array: %@", array);, на выходе будут правильные даты. Кажется, я получаю сбой только при нажатии на представление, и он падает на if([[marks objectAtIndex: row * 7 + column] boolValue]) - person Jon; 28.06.2011
comment
Хорошо, еще одно обновление, я ограничил ошибку этой строкой: [self.navigationController pushViewController:sessionViewController animated:YES];. Когда я меняю анимацию с YES на NO, все работает нормально и сбоев нет. Знаете ли вы какой-нибудь способ обойти это, потому что без анимации это выглядит очень уродливо. - person Jon; 28.06.2011
comment
Я не уверен, что это ваша проблема. Поскольку у вас, похоже, проблема с выходом за пределы, это означает, что заполнение кода marks неверно. Я думаю, что вы делаете на одну дату меньше, чем необходимо в вашем методе calendarMonthView:marksFromDate:toDate:. Поэтому я попросил вас записывать даты, которые передаются в качестве аргументов — startDate и lastDate. - person Deepak Danduprolu; 28.06.2011
comment
Хорошо, я думаю, что, возможно, нашел проблему. Кажется, что-то не так с точки зрения часового пояса. Точки иногда смещены на один день. Он думает, что мы допустили ошибку с преобразованием даты, и иногда он отмечает один день вперед, а не фактический день. Это может быть как-то связано с GMT или чем-то еще. - person Jon; 28.06.2011
comment
Пожалуйста, посмотрите здесь stackoverflow.com/questions/6501032/ - person Jon; 28.06.2011
comment
Попробуйте записать даты, которые вы получаете из своей библиотеки, и посмотрите, соответствуют ли они вашим ожиданиям. Код, который мы ожидаем, GMT, тогда как библиотека может предоставлять нам данные в местном часовом поясе. - person Deepak Danduprolu; 28.06.2011
comment
Я имею в виду, что это может быть 2011-06-28 00:00:00 -08:00 PST. - person Deepak Danduprolu; 28.06.2011
comment
Да, когда я регистрирую даты, используя простой NSDateFormatter, они приходят с моим локальным временем и датой. Но вроде как в календаре отметки по Гринвичу, а не по местному времени? - person Jon; 28.06.2011
comment
Только что обновленный вопрос с журналом - person Jon; 28.06.2011
comment
Привет, Дипак, я думаю, что после того, как мы преобразовали числа, чтобы удалить интервалы времени, часа и секунды, нам нужно преобразовать их обратно в наш местный часовой пояс, чтобы он отображался в календаре для даты местного часового пояса, а не GMT. свидание. Что вы думаете? - person Jon; 28.06.2011
comment
Ну, на данный момент я не знаю. Это немного сбивает с толку, и я не могу ничего сказать наверняка, не глядя на весь проект, на который у меня нет времени. Я надеюсь, что кто-то еще на SO поможет вам понять это. - person Deepak Danduprolu; 28.06.2011
comment
Спасибо, Дипак, но я почти уверен, что проблема именно в этом, если бы вы могли просто помочь мне добавить эту строку кода. Я думаю, мне просто нужно преобразовать дату обратно в мой местный часовой пояс после удаления часовых и секундных интервалов. Поэтому прямо перед тем, как я сделаю \self.data = data1;, мне нужно преобразовать его в местное время в dateformatter. - person Jon; 28.06.2011