我有一个对象数组,每个对象都包含一个名为date的字段。我想使用NSPredicate
创建此数组的子集,其中我只提取属于特定日期范围的对象。这是我正在使用的代码:
predicate = [NSPredicate predicateWithFormat:@"(date >= %@) AND (date =< %@)", startDate, endDate];
_daysArray = [_cachedDaysArray filteredArrayUsingPredicate:predicate];
我遇到的问题是startDate
和endDate
是同一天,但是时间不同。这是XCode调试器中的变量视图
正如您所看到的,我在数组中有一个date
字段等于startDate
的对象,但您也可以看到_daysArray
在过滤器之后不包含任何元素执行。
当日期不是同一天时,此功能正常。
非常感谢任何帮助。
编辑#1
以下是评论者要求的po
变量的predicate
:
(lldb) po predicate
date >= CAST(406616400.676014, "NSDate") AND date <= CAST(406702799.677098, "NSDate")
(lldb)
编辑#2
(lldb) po [[_cachedDaysArray firstObject] date]
2013-11-18 05:00:00 +0000
(lldb)
编辑#3
Martin R.让我走上正确的轨道,评论startDate
的计算方法。现在我已经改变了,它正在发挥作用。我正在使用一种方法来计算startDate
。以前,我使用NSUIntegerMax
来表示组件,现在我将它们特别分解:
-(NSDate *)pastDate:(NSInteger)daysPast
{
// Get the appropriate calendar
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *startComponents = [calendar components:(NSCalendarUnitMonth|NSCalendarUnitDay|NSCalendarUnitYear|NSCalendarUnitHour|NSCalendarUnitMinute|NSCalendarUnitSecond) fromDate:[NSDate date]];
[startComponents setHour: 00];
[startComponents setMinute: 00];
[startComponents setSecond: 00];
startComponents.day = startComponents.day - daysPast;
return [calendar dateFromComponents:startComponents];
}
答案 0 :(得分:2)
从谓词的输出
date >= CAST(406616400.676014, "NSDate") AND date <= CAST(406702799.677098, "NSDate")
可以看到startDate
不完全“2013-11-20 05:00:00 +0000”(UTC)或
“2013-11-20 00:00:00”(EST)但 0.676014秒后。
因此,如果_cachedDaysArray
中对象的日期完全落在上
2013-11-20的午夜,它不匹配谓词。
似乎startDate
和endDate
的计算没有
正是你所期待的。
答案 1 :(得分:1)
在将日期传递给谓词之前,您应该将日期转换为不包括时间。 试试这个:
-(NSDate*)dateNoTime:(NSDate*)myDate
{
NSDateComponents *comp = [[NSCalendar currentCalendar] components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit fromDate: myDate];
return [[NSCalendar currentCalendar] dateFromComponents:comp];
}
答案 2 :(得分:1)
试试这个:
predicate =[NSPredicate predicateWithBlock:^BOOL(TRDay *evaluatedObject, NSDictionary *bindings) {
return evaluatedObject.date.timeIntervalSince1970 >= startDate.timeIntervalSince1970 && evaluatedObject.date.timeIntervalSince1970 <= endDate.timeIntervalSince1970;
}];
答案 3 :(得分:0)
我尝试过类似的东西:
NSCalendar *gregorianCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *components3 = [[NSDateComponents alloc] init];
[components3 setYear:2013];
[components3 setMonth:11];
[components3 setDay:20];
NSDate *startDate = [gregorianCalendar dateFromComponents:components3];
[components3 setHour:23];
[components3 setMinute:59];
[components3 setSecond:59];
NSDate *endDate = [gregorianCalendar dateFromComponents:components3];
[gregorianCalendar release];
NSDictionary* dict = [NSDictionary dictionaryWithObjects:@[startDate] forKeys:@[@"date"]];
NSArray* mainArray = [NSArray arrayWithObjects:dict, nil];
NSPredicate* pred = [NSPredicate predicateWithFormat:@"(date >= %@) AND (date =< %@)", startDate, endDate];
NSArray* filteredArray = [mainArray filteredArrayUsingPredicate:pred];
它按预期工作。基本上它意味着你在其他地方有错误。