[英]Filtering a NSArray containing objects with a NSDate field with NSPredicate
我有一个对象数组,每个对象都包含一个称为date的字段。 我想使用NSPredicate
创建此数组的一个子集,在这里我只拉出属于某个日期范围内的那些对象。 这是我正在使用的代码:
predicate = [NSPredicate predicateWithFormat:@"(date >= %@) AND (date =< %@)", startDate, endDate];
_daysArray = [_cachedDaysArray filteredArrayUsingPredicate:predicate];
我遇到的问题是startDate
和endDate
是同一天,但时间不同。 这是XCode调试器中的变量视图
如您所见,我在数组中有一个对象,该对象的date
字段等于startDate
,但是您还可以看到_daysArray
在执行过滤器后不包含任何元素。
当日期不是同一天时,这很好用。
任何帮助将不胜感激。
编辑#1
这是评论者要求的predicate
变量的po
:
(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];
}
从谓词的输出
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
的计算与您期望的不完全相同。
在将日期传递给谓词之前,应将日期转换为不包括时间。 尝试这个:
-(NSDate*)dateNoTime:(NSDate*)myDate
{
NSDateComponents *comp = [[NSCalendar currentCalendar] components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit fromDate: myDate];
return [[NSCalendar currentCalendar] dateFromComponents:comp];
}
尝试这个:
predicate =[NSPredicate predicateWithBlock:^BOOL(TRDay *evaluatedObject, NSDictionary *bindings) {
return evaluatedObject.date.timeIntervalSince1970 >= startDate.timeIntervalSince1970 && evaluatedObject.date.timeIntervalSince1970 <= endDate.timeIntervalSince1970;
}];
我尝试过这样的事情:
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];
它按预期工作。 基本上,这意味着您在其他地方有错误。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.