[英]Filtering a NSArray containing objects with a NSDate field with NSPredicate
I have an array of objects, with each object containing a field called date. 我有一个对象数组,每个对象都包含一个称为date的字段。 I want to create a subset of this array using
NSPredicate
where I pull only those objects that fall within a certain date range. 我想使用
NSPredicate
创建此数组的一个子集,在这里我只拉出属于某个日期范围内的那些对象。 Here's the code I am using: 这是我正在使用的代码:
predicate = [NSPredicate predicateWithFormat:@"(date >= %@) AND (date =< %@)", startDate, endDate];
_daysArray = [_cachedDaysArray filteredArrayUsingPredicate:predicate];
The problem I am having is when startDate
and endDate
are the same day, but different times. 我遇到的问题是
startDate
和endDate
是同一天,但时间不同。 Here's the variables view in the XCode debugger 这是XCode调试器中的变量视图
As you can see, I have an object in the array that has a date
field equal to startDate
, but you can also see that _daysArray
contains no elements after the filter is executed. 如您所见,我在数组中有一个对象,该对象的
date
字段等于startDate
,但是您还可以看到_daysArray
在执行过滤器后不包含任何元素。
This works fine when the dates are not the same day. 当日期不是同一天时,这很好用。
Any help would be greatly appreciated. 任何帮助将不胜感激。
EDIT #1 编辑#1
Here's the po
of the predicate
variable as requested by commenter: 这是评论者要求的
predicate
变量的po
:
(lldb) po predicate
date >= CAST(406616400.676014, "NSDate") AND date <= CAST(406702799.677098, "NSDate")
(lldb)
EDIT #2 编辑#2
(lldb) po [[_cachedDaysArray firstObject] date]
2013-11-18 05:00:00 +0000
(lldb)
EDIT #3 编辑#3
Martin R. got me on the right track with his comment on how startDate
was being calculated. Martin R.通过对
startDate
计算方式的评论使我走上了正确的道路。 Now that I have changed that, it's working. 现在,我已经更改了它,它正在工作。 I am using a method to calculate
startDate
. 我正在使用一种方法来计算
startDate
。 Previously, I was using NSUIntegerMax
to indicate the components, now I am breaking them out specifically: 以前,我使用
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];
}
From the output of the predicate 从谓词的输出
date >= CAST(406616400.676014, "NSDate") AND date <= CAST(406702799.677098, "NSDate")
one can see that startDate
is not exactly "2013-11-20 05:00:00 +0000" (UTC) or "2013-11-20 00:00:00" (EST) but 0.676014 seconds later . 可以看到
startDate
并非完全是“ 2013-11-20 05:00:00 +0000”(UTC)或“ 2013-11-20 00:00:00”(EST),而是0.676014秒后 。 Therefore, if the date of the object in _cachedDaysArray
falls exactly on midnight of 2013-11-20, it does not match the predicate. 因此,如果
_cachedDaysArray
对象的日期恰好位于2013-11-20的午夜,则它与谓词不匹配。
It seems that the calculation of startDate
and endDate
does not exactly what you expect. 似乎
startDate
和endDate
的计算与您期望的不完全相同。
You should convert your dates to do not include time, before you pass it to your predicate. 在将日期传递给谓词之前,应将日期转换为不包括时间。 Try this:
尝试这个:
-(NSDate*)dateNoTime:(NSDate*)myDate
{
NSDateComponents *comp = [[NSCalendar currentCalendar] components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit fromDate: myDate];
return [[NSCalendar currentCalendar] dateFromComponents:comp];
}
Try this: 尝试这个:
predicate =[NSPredicate predicateWithBlock:^BOOL(TRDay *evaluatedObject, NSDictionary *bindings) {
return evaluatedObject.date.timeIntervalSince1970 >= startDate.timeIntervalSince1970 && evaluatedObject.date.timeIntervalSince1970 <= endDate.timeIntervalSince1970;
}];
I tried something like that: 我尝试过这样的事情:
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];
And it works as expected. 它按预期工作。 Basically it means you have error somewhere else.
基本上,这意味着您在其他地方有错误。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.