我有一个具有NSDate
属性的Core Data模型。我想白天过滤数据库。我假设解决方案将涉及NSPredicate
,但我不确定如何将它们放在一起。
我知道如何使用NSDate
和NSDateComponents
比较两个NSCalendar
的日期,但如何使用NSPredicate
对其进行过滤?
也许我需要在NSManagedObject
子类上创建一个类别,该类别可以返回仅有年,月和日的裸日期。然后我可以在NSPredicate
中进行比较。这是你的推荐,还是有更简单的东西?
答案 0 :(得分:188)
给定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];
答案 1 :(得分:62)
如何将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'date-entires。
答案 2 :(得分: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中的日期。
答案 3 :(得分:8)
我将Glauco Neves的答案移植到Swift 2.0并将其包装在一个接收日期的函数中,并返回相应日期的(20000)
:
NSPredicate
答案 4 :(得分:8)
日期的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()
答案 5 :(得分: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!])
}
答案 6 :(得分: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
的{{1}}(如上文其他答案所示)......
NSFetchRequest
答案 7 :(得分: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,并在之后进行比较。如果您需要任何清晰度,请告诉我。
答案 8 :(得分:0)
以先前的答案为基础,使用Swift 5.x进行更新和替代方法
func predicateForDayUsingDate(_ date: Date) -> NSPredicate {
var calendar = Calendar.current
calendar.timeZone = NSTimeZone.local
// following creates exact midnight 12:00:00:000 AM of day
let startOfDay = calendar.startOfDay(for: date)
// following creates exact midnight 12:00:00:000 AM of next day
let endOfDay = calendar.date(byAdding: .day, value: 1, to: startOfDay)!
return NSPredicate(format: "day >= %@ AND day < %@", argumentArray: [startOfDay, endOfDay])
}
如果您希望将endOfDay
的时间设置为晚上11:59:59,则可以添加...
let endOfDayLessOneSecond = endOfDay.addingTimeInterval(TimeInterval(-1))
但是您可以将NSPredicate更改为...
return NSPredicate(format: "day >= %@ AND day <= %@", argumentArray: [startOfDay, endOfDayLessOneSecond])
...特别说明从day < %@
到day <= %@
的变化。