繁体   English   中英

使用NSPredicate过滤包含带有NSDate字段的对象的NSArray

[英]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];

我遇到的问题是startDateendDate是同一天,但时间不同。 这是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的午夜,则它与谓词匹配。

似乎startDateendDate的计算与您期望的不完全相同。

在将日期传递给谓词之前,应将日期转换为不包括时间。 尝试这个:

-(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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM