objective-c NSPredicate:按 NSDate 属性的日期过滤对象

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1965331/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 22:39:59  来源:igfitidea点击:

NSPredicate: filtering objects by day of NSDate property

objective-ccore-datansdatenspredicatensfetchedresultscontroller

提问by Jonathan Sterling

I have a Core Data model with an NSDateproperty. I want to filter the database by day. I assume the solution will involve an NSPredicate, but I'm not sure how to put it all together.

我有一个带有NSDate属性的核心数据模型。我想按天过滤数据库。我认为解决方案将涉及NSPredicate,但我不确定如何将它们放在一起。

I know how to compare the day of two NSDates using NSDateComponentsand NSCalendar, but how do I filter it with an NSPredicate?

我知道如何NSDate使用NSDateComponentsand比较两个s的天数NSCalendar,但是如何用 an 过滤它NSPredicate

Perhaps I need to create a category on my NSManagedObjectsubclass that can return a bare date with just the year, month and day. Then I could compare that in an NSPredicate. Is this your recommendation, or is there something simpler?

也许我需要在我的NSManagedObject子类上创建一个类别,该类别可以仅返回年、月和日的空日期。然后我可以在一个NSPredicate. 这是您的建议,还是有更简单的方法?

回答by diciu

Given a NSDate * startDateand endDateand a NSManagedObjectContext * moc:

给定一个 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];

回答by d.ennis

Example on how to also set up startDate and endDate to the above given answer:

关于如何将 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];

...

Here I was searching for all entries within one month. It's worth to mention, that this example also shows how to search 'nil' date-entires.

在这里,我正在搜索一个月内的所有条目。值得一提的是,这个例子还展示了如何搜索“nil”日期整体。

回答by Glauco Neves

In Swift I got something similar to:

在 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!])

I had a hard time to discover that string interpolation "\(this notation)"doesn't work for comparing dates in NSPredicate.

我很难发现字符串插值"\(this notation)"不适用于比较 NSPredicate 中的日期。

回答by Roni Leshes

Swift 3.0 extension for Date:

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!])
}
}

Then use like:

然后使用像:

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

回答by Rafael Bugajewski

I ported the answer from Glauco Nevesto Swift 2.0 and wrapped it inside a function that receives a date and returns the NSPredicatefor the corresponding day:

我将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!])
}

回答by DS.

Adding to Rafael's answer (incredibly useful, thank you!), porting for Swift 3.

添加到 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!])
}

回答by andrewbuilder

I've recently spent some time attempting to solve this same problem and add the following to the list of alternatives to prepare start and end dates (includes updated method for iOS 8 and above)...

我最近花了一些时间尝试解决同样的问题,并将以下内容添加到准备开始和结束日期的备选列表中(包括适用于 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];

...and the NSPredicatefor the Core Data NSFetchRequest(as already shown above in other answers)...

...以及NSPredicate核心数据NSFetchRequest(如上面其他答案中所示)...

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

回答by Narasimha Nallamsetty

For me this is worked.

对我来说这是有效的。

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);

I have filtered array from current date to 7 days back. I mean I am getting one week data from current date. This should work.

我已经过滤了从当前日期到 7 天前的数组。我的意思是我从当前日期开始获取一周的数据。这应该有效。

Note: I am converting date which is coming with milli seconds by 1000, and comparing after. Let me know if you need any clarity.

注意:我正在将以毫秒为单位的日期转换为 1000,然后进行比较。如果您需要任何澄清,请告诉我。