NSPredicate:按NSDate属性的天筛选对象


123

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

我知道如何NSDate使用NSDateComponents和比较两个星期几NSCalendar,但是如何用和过滤呢NSPredicate

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

Answers:


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 2011年

1
有关如何同时设置startDate和endDate的示例,请参见下面的答案
d.ennis,2011年

@jlstrecker您能给我示范一个如何使用午夜到午夜范围的例子。例如:我有2个相同的日子,但时间不同。我想按天筛选(我不在乎时间)。我怎样才能做到这一点?
iosMentalist 2012年

3
@Shady在上面的示例中,您可以将其设置startDate为2012-09-17 0:00:00和endDate2012-09-18 0:00:00,并将谓词为startDate <= date <endDate。这将在2012-09-17的所有时间生效。
jlstrecker 2012年

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

...

在这里,我正在寻找一个月内的所有条目。值得一提的是,此示例还显示了如何搜索“无”日期整个字段。


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

日期的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是它的数组dictionary还是dataModel 我想在DataModel上应用。
Sumeet Mourya
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.