NSPredicate : NSDate 속성의 날짜별로 개체 필터링


123

NSDate속성 이있는 핵심 데이터 모델이 있습니다. 매일 데이터베이스를 필터링하고 싶습니다. 솔루션이를 포함 할 것이라고 가정 NSPredicate하지만 모든 것을 통합하는 방법을 잘 모르겠습니다.

나는이 개 날 비교하는 방법을 알고 NSDate들 사용 NSDateComponents하고 NSCalendar있지만, 어떻게 그것을 필터링합니까 NSPredicate?

아마도 NSManagedObject연도, 월, 일만 포함 된 날짜를 반환 할 수있는 하위 클래스에 범주를 만들어야 할 수도 있습니다. 그런 다음 NSPredicate. 이것이 당신의 추천입니까, 아니면 더 간단한 것이 있습니까?

답변:


193

주어진 NSDate * startDate 및 endDate 및 NSManagedObjectContext * moc :

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(date >= %@) AND (date <= %@)", startDate, endDate];
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
[request setEntity:[NSEntityDescription entityForName:@"EntityName" inManagedObjectContext:moc]];
[request setPredicate:predicate];

NSError *error = nil;
NSArray *results = [moc executeFetchRequest:request error:&error];

4
데이트가 하나만 있다면?
— Wasim

4
을 (를) 사용할 수있는 것 같습니다 ==. 낮으로 검색하는 경우 NSDate는 날짜 및 시간이라는 것을 기억하십시오. 자정에서 자정까지의 범위를 사용할 수 있습니다.
— jlstrecker

1
또한 설치의 startDate와 endDate가에, 내 대답은 아래를 참조 방법에 대한 예
— d.ennis

@jlstrecker는 자정에서 자정 범위를 사용하는 방법의 예를 보여줄 수 있습니다. 예를 들어 : 나는 2 일이 같지만 타이밍이 다릅니다. 그리고 나는 일별로 필터링하고 싶다 (나는 타이밍에 신경 쓰지 않는다). 어떻게 할 수 있습니까?
— iosMentalist

3
@Shady 위의 예에서 startDate2012-09-17 0:00:00 및 endDate2012-09-18 0:00:00 및 술어를 startDate <= date <endDate로 설정할 수 있습니다. 그것은 2012-09-17에 항상 잡힐 것입니다.
— jlstrecker

63

위의 답변에 대해 startDate 및 endDate를 설정하는 방법에 대한 예 :

...

NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *components = [calendar components:(NSCalendarUnitYear | NSCalendarUnitMonth ) fromDate:[NSDate date]];
//create a date with these components
NSDate *startDate = [calendar dateFromComponents:components];
[components setMonth:1];
[components setDay:0]; //reset the other components
[components setYear:0]; //reset the other components
NSDate *endDate = [calendar dateByAddingComponents:components toDate:startDate options:0];
predicate = [NSPredicate predicateWithFormat:@"((date >= %@) AND (date < %@)) || (date = nil)",startDate,endDate];

...

여기에서 한 달 이내에 모든 항목을 검색했습니다. 이 예제는 'nil'날짜 전체를 검색하는 방법도 보여줍니다.


10

Swift에서 나는 다음과 비슷한 것을 얻었습니다.

        let dateFormatter = NSDateFormatter()
        dateFormatter.dateFormat = "yyyy-MM-dd"
        let date = dateFormatter.dateFromString(predicate)
        let calendar = NSCalendar(calendarIdentifier: NSGregorianCalendar)
        let components = calendar!.components(
            NSCalendarUnit.CalendarUnitYear |
                NSCalendarUnit.CalendarUnitMonth |
                NSCalendarUnit.CalendarUnitDay |
                NSCalendarUnit.CalendarUnitHour |
                NSCalendarUnit.CalendarUnitMinute |
                NSCalendarUnit.CalendarUnitSecond, fromDate: date!)
        components.hour = 00
        components.minute = 00
        components.second = 00
        let startDate = calendar!.dateFromComponents(components)
        components.hour = 23
        components.minute = 59
        components.second = 59
        let endDate = calendar!.dateFromComponents(components)
        predicate = NSPredicate(format: "day >= %@ AND day =< %@", argumentArray: [startDate!, endDate!])

"\(this notation)"NSPredicate에서 날짜를 비교 하는 데 문자열 보간 이 작동하지 않는다는 것을 발견하기가 어려웠습니다 .


이 답변에 감사드립니다. 아래에 Swift 3 버전이 추가되었습니다.
— DS.

9

Date 용 Swift 3.0 확장 :

extension Date{

func makeDayPredicate() -> NSPredicate {
    let calendar = Calendar.current
    var components = calendar.dateComponents([.year, .month, .day, .hour, .minute, .second], from: self)
    components.hour = 00
    components.minute = 00
    components.second = 00
    let startDate = calendar.date(from: components)
    components.hour = 23
    components.minute = 59
    components.second = 59
    let endDate = calendar.date(from: components)
    return NSPredicate(format: "day >= %@ AND day =< %@", argumentArray: [startDate!, endDate!])
}
}

그런 다음 다음과 같이 사용하십시오.

 let fetchReq = NSFetchRequest(entityName: "MyObject")
 fetchReq.predicate = myDate.makeDayPredicate()

8

Glauco Neves 의 답변 을 Swift 2.0으로 포팅하고 날짜를 수신하고 해당 날짜에 대해를 반환하는 함수로 래핑했습니다 NSPredicate.

func predicateForDayFromDate(date: NSDate) -> NSPredicate {
    let calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)
    let components = calendar!.components([.Year, .Month, .Day, .Hour, .Minute, .Second], fromDate: date)
    components.hour = 00
    components.minute = 00
    components.second = 00
    let startDate = calendar!.dateFromComponents(components)
    components.hour = 23
    components.minute = 59
    components.second = 59
    let endDate = calendar!.dateFromComponents(components)

    return NSPredicate(format: "day >= %@ AND day =< %@", argumentArray: [startDate!, endDate!])
}

이 답변에 감사드립니다. 아래에 Swift 3 버전이 추가되었습니다.
— DS.

6

Rafael의 답변에 추가 (매우 유용합니다, 감사합니다!), Swift 3 포팅.

func predicateForDayFromDate(date: Date) -> NSPredicate {
    let calendar = Calendar(identifier: Calendar.Identifier.gregorian)
    var components = calendar.dateComponents([.year, .month, .day, .hour, .minute, .second], from: date)
    components.hour = 00
    components.minute = 00
    components.second = 00
    let startDate = calendar.date(from: components)
    components.hour = 23
    components.minute = 59
    components.second = 59
    let endDate = calendar.date(from: components)

    return NSPredicate(format: "YOUR_DATE_FIELD >= %@ AND YOUR_DATE_FIELD =< %@", argumentArray: [startDate!, endDate!])
}

1

나는 최근에 동일한 문제를 해결하기 위해 시간을 보냈고 시작일과 종료일을 준비하기위한 대안 목록에 다음을 추가했습니다 (iOS 8 이상에 대한 업데이트 된 방법 포함) ...

NSDate *dateDay = nil;
NSDate *dateDayStart = nil;
NSDate *dateDayNext = nil;

dateDay = <<USER_INPUT>>;

dateDayStart = [[NSCalendar currentCalendar] startOfDayForDate:dateDay];

//  dateDayNext EITHER
dateDayNext = [dateDayStart dateByAddingTimeInterval:(24 * 60 * 60)];

//  dateDayNext OR
NSDateComponents *dateComponentDay = nil;
dateComponentDay = [[NSDateComponents alloc] init];
[dateComponentDay setDay:1];
dateDayNext = [[NSCalendar currentCalendar] dateByAddingComponents:dateComponentDay
                                                            toDate:dateDayStart
                                                           options:NSCalendarMatchNextTime];

... 및 NSPredicate핵심 데이터 NSFetchRequest(위의 다른 답변에서 이미 표시됨) ...

[NSPredicate predicateWithFormat:@"(dateAttribute >= %@) AND (dateAttribute < %@)", dateDayStart, dateDayNext]]

0

나를 위해 이것은 효과가 있습니다.

NSCalendar *calendar = [NSCalendar currentCalendar];
    NSDateComponents *components = [calendar components:(NSYearCalendarUnit | NSMonthCalendarUnit ) fromDate:[NSDate date]];
    //create a date with these components
    NSDate *startDate = [calendar dateFromComponents:components];
    [components setMonth:0];
    [components setDay:0]; //reset the other components
    [components setYear:0]; //reset the other components
    NSDate *endDate = [calendar dateByAddingComponents:components toDate:startDate options:0];

    startDate = [NSDate date];
    endDate = [startDate dateByAddingTimeInterval:-(7 * 24 * 60 * 60)];//change here

    NSString *startTimeStamp = [[NSNumber numberWithInt:floor([endDate timeIntervalSince1970])] stringValue];
    NSString *endTimeStamp = [[NSNumber numberWithInt:floor([startDate timeIntervalSince1970])] stringValue];


   NSPredicate *predicate = [NSPredicate predicateWithFormat:@"((paidDate1 >= %@) AND (paidDate1 < %@))",startTimeStamp,endTimeStamp];
    NSLog(@"predicate is %@",predicate);
    totalArr = [completeArray filteredArrayUsingPredicate:predicate];
    [self filterAndPopulateDataBasedonIndex];
    [self.tableviewObj reloadData];
    NSLog(@"result is %@",totalArr);

현재 날짜에서 7 일 전으로 배열을 필터링했습니다. 현재 날짜에서 일주일 데이터를 받고 있습니다. 작동합니다.

참고 : 밀리 초와 함께 오는 날짜를 1000으로 변환하고 그 이후를 비교하고 있습니다. 명확성이 필요하면 알려주세요.


귀하의 대답 completeArray은 Array of dictionary또는 dataModel DataModel에 적용하고 싶습니다.
— Sumeet Mourya
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.