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


123

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

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

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

답변:


193

주어진 NSDate * startDateendDate 및 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.