NSPredicate:按NSDate属性过滤对象
我有一个NSDate
属性的核心数据模型。 我想白天过滤数据库。 我认为解决scheme将涉及NSPredicate
,但我不知道如何把它放在一起。
我知道如何使用NSDateComponents
和NSCalendar
来比较两个NSDate
的NSCalendar
,但是如何使用NSCalendar
进行过滤?
也许我需要在我的NSManagedObject
子类上创build一个类别,它可以返回只有年份,月份和date的NSManagedObject
date。 然后我可以比较一下NSPredicate
。 这是你的build议,还是有更简单的?
给定一个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];
关于如何设置startDate和endDate到上面给出的答案的例子:
... 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: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]; ...
在这里,我正在一个月内search所有条目。 值得一提的是,这个例子还展示了如何search“无”date。
在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!])
我很难发现string插值"\(this notation)"
在NSPredicate中不能比较date。
我将Glauco Neves的答案移植到Swift 2.0中,并将其封装在接收date并返回相应date的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!]) }
添加到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!]) }
Swift 3.0扩展date:
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()
我最近花了一些时间试图解决这个相同的问题,并添加以下内容的备选scheme,以准备开始和结束date(包括更新的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];
…以及核心数据NSFetchRequest
(如上面在其他答案中所示)…
[NSPredicate predicateWithFormat:@"(dateAttribute >= %@) AND (dateAttribute < %@)", dateDayStart, dateDayNext]]
对我来说这是有效的。
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);
我已经从当前date到7天前过滤了数组。 我的意思是我从当前date获取一周数据。 这应该工作。
注意:我正在将以毫秒为单位的date转换成1000,然后进行比较。 让我知道你是否需要清晰。