简体   繁体   English

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

[英]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. 我遇到的问题是startDateendDate是同一天,但时间不同。 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. 似乎startDateendDate的计算与您期望的不完全相同。

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.

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