Create an account

Very important

  • To access the important data of the forums, you must be active in each forum and especially in the leaks and database leaks section, send data and after sending the data and activity, data and important content will be opened and visible for you.
  • You will only see chat messages from people who are at or below your level.
  • More than 500,000 database leaks and millions of account leaks are waiting for you, so access and view with more activity.
  • Many important data are inactive and inaccessible for you, so open them with activity. (This will be done automatically)


Thread Rating:
  • 615 Vote(s) - 3.51 Average
  • 1
  • 2
  • 3
  • 4
  • 5
NSPredicate: filtering objects by day of NSDate property

#1
I have a Core Data model with an `NSDate` property. I want to filter the database by day. I assume the solution will involve an `NSPredicate`, but I'm not sure how to put it all together.

I know how to compare the day of two `NSDate`s using `NSDateComponents` and `NSCalendar`, but how do I filter it with an `NSPredicate`?

Perhaps I need to create a category on my `NSManagedObject` subclass that can return a bare date with just the year, month and day. Then I could compare that in an `NSPredicate`. Is this your recommendation, or is there something simpler?
Reply

#2
Given a NSDate * *startDate* and *endDate* and a NSManagedObjectContext * *moc*:

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(date >= %@) AND (date <= %@)", startDate, endDate];
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
[request setEntity:[NSEntityDescription entityForName:@"EntityName" inManagedObjectContext:moc]];
[request setPredicate:predicate];

NSError *error = nil;
NSArray *results = [moc executeFetchRequest:request error:&error];
Reply

#3
In Swift I got something similar to:

let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
let date = dateFormatter.dateFromString(predicate)
let calendar = NSCalendar(calendarIdentifier: NSGregorianCalendar)
let components = calendar!.components(
NSCalendarUnit.CalendarUnitYear |
NSCalendarUnit.CalendarUnitMonth |
NSCalendarUnit.CalendarUnitDay |
NSCalendarUnit.CalendarUnitHour |
NSCalendarUnit.CalendarUnitMinute |
NSCalendarUnit.CalendarUnitSecond, fromDate: date!)
components.hour = 00
components.minute = 00
components.second = 00
let startDate = calendar!.dateFromComponents(components)
components.hour = 23
components.minute = 59
components.second = 59
let endDate = calendar!.dateFromComponents(components)
predicate = NSPredicate(format: "day >= %@ AND day =< %@", argumentArray: [startDate!, endDate!])

I had a hard time to discover that string interpolation `"\(this notation)"` doesn't work for comparing dates in NSPredicate.
Reply

#4
For me this is worked.

NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *components = [calendar components:(NSYearCalendarUnit | NSMonthCalendarUnit ) fromDate:[NSDate date]];
//create a date with these components
NSDate *startDate = [calendar dateFromComponents:components];
[components setMonth:0];
[components setDay:0]; //reset the other components
[components setYear:0]; //reset the other components
NSDate *endDate = [calendar dateByAddingComponents:components toDate:startDate options:0];

startDate = [NSDate date];
endDate = [startDate dateByAddingTimeInterval:-(7 * 24 * 60 * 60)];//change here

NSString *startTimeStamp = [[NSNumber numberWithInt:floor([endDate timeIntervalSince1970])] stringValue];
NSString *endTimeStamp = [[NSNumber numberWithInt:floor([startDate timeIntervalSince1970])] stringValue];


NSPredicate *predicate = [NSPredicate predicateWithFormat:@"((paidDate1 >= %@) AND (paidDate1 < %@))",startTimeStamp,endTimeStamp];
NSLog(@"predicate is %@",predicate);
totalArr = [completeArray filteredArrayUsingPredicate:predicate];
[self filterAndPopulateDataBasedonIndex];
[self.tableviewObj reloadData];
NSLog(@"result is %@",totalArr);

I have filtered array from current date to 7 days back. I mean I am getting one week data from current date. This should work.

Note: I am converting date which is coming with milli seconds by 1000, and comparing after. Let me know if you need any clarity.
Reply

#5
I ported the answer from [Glauco Neves][1] to Swift 2.0 and wrapped it inside a function that receives a date and returns the `NSPredicate` for the corresponding day:

func predicateForDayFromDate(date: NSDate) -> NSPredicate {
let calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)
let components = calendar!.components([.Year, .Month, .Day, .Hour, .Minute, .Second], fromDate: date)
components.hour = 00
components.minute = 00
components.second = 00
let startDate = calendar!.dateFromComponents(components)
components.hour = 23
components.minute = 59
components.second = 59
let endDate = calendar!.dateFromComponents(components)

return NSPredicate(format: "day >= %@ AND day =< %@", argumentArray: [startDate!, endDate!])
}


[1]:

[To see links please register here]

Reply

#6
I've recently spent some time attempting to solve this same problem and add the following to the list of alternatives to prepare start and end dates (includes updated method for iOS 8 and above)...

NSDate *dateDay = nil;
NSDate *dateDayStart = nil;
NSDate *dateDayNext = nil;

dateDay = <<USER_INPUT>>;

dateDayStart = [[NSCalendar currentCalendar] startOfDayForDate:dateDay];

// dateDayNext EITHER
dateDayNext = [dateDayStart dateByAddingTimeInterval:(24 * 60 * 60)];

// dateDayNext OR
NSDateComponents *dateComponentDay = nil;
dateComponentDay = [[NSDateComponents alloc] init];
[dateComponentDay setDay:1];
dateDayNext = [[NSCalendar currentCalendar] dateByAddingComponents:dateComponentDay
toDate:dateDayStart
options:NSCalendarMatchNextTime];

...and the `NSPredicate` for the Core Data `NSFetchRequest` (as already shown above in other answers)...

[NSPredicate predicateWithFormat:@"(dateAttribute >= %@) AND (dateAttribute < %@)", dateDayStart, dateDayNext]]
Reply

#7
Adding to Rafael's answer (incredibly useful, thank you!), porting for Swift 3.

func predicateForDayFromDate(date: Date) -> NSPredicate {
let calendar = Calendar(identifier: Calendar.Identifier.gregorian)
var components = calendar.dateComponents([.year, .month, .day, .hour, .minute, .second], from: date)
components.hour = 00
components.minute = 00
components.second = 00
let startDate = calendar.date(from: components)
components.hour = 23
components.minute = 59
components.second = 59
let endDate = calendar.date(from: components)

return NSPredicate(format: "YOUR_DATE_FIELD >= %@ AND YOUR_DATE_FIELD =< %@", argumentArray: [startDate!, endDate!])
}
Reply

#8
Swift 3.0 extension for Date:

extension Date{

func makeDayPredicate() -> NSPredicate {
let calendar = Calendar.current
var components = calendar.dateComponents([.year, .month, .day, .hour, .minute, .second], from: self)
components.hour = 00
components.minute = 00
components.second = 00
let startDate = calendar.date(from: components)
components.hour = 23
components.minute = 59
components.second = 59
let endDate = calendar.date(from: components)
return NSPredicate(format: "day >= %@ AND day =< %@", argumentArray: [startDate!, endDate!])
}
}





Then use like:

let fetchReq = NSFetchRequest(entityName: "MyObject")
fetchReq.predicate = myDate.makeDayPredicate()

Reply

#9
Example on how to also set up startDate and endDate to the above given answer:

...

NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *components = [calendar components:(NSCalendarUnitYear | NSCalendarUnitMonth ) fromDate:[NSDate date]];
//create a date with these components
NSDate *startDate = [calendar dateFromComponents:components];
[components setMonth:1];
[components setDay:0]; //reset the other components
[components setYear:0]; //reset the other components
NSDate *endDate = [calendar dateByAddingComponents:components toDate:startDate options:0];
predicate = [NSPredicate predicateWithFormat:@"((date >= %@) AND (date < %@)) || (date = nil)",startDate,endDate];

...


Here I was searching for all entries within one month. It's worth to mention, that this example also shows how to search 'nil' date-entires.
Reply

#10
Building on the previous answers, an update and alternative method using Swift 5.x

func predicateForDayUsingDate(_ date: Date) -> NSPredicate {

var calendar = Calendar.current
calendar.timeZone = NSTimeZone.local
// following creates exact midnight 12:00:00:000 AM of day
let startOfDay = calendar.startOfDay(for: date)
// following creates exact midnight 12:00:00:000 AM of next day
let endOfDay = calendar.date(byAdding: .day, value: 1, to: startOfDay)!

return NSPredicate(format: "day >= %@ AND day < %@", argumentArray: [startOfDay, endOfDay])
}


If you'd prefer to create the time for `endOfDay` as 11:59:59 PM, you can instead include...

let endOfDayLessOneSecond = endOfDay.addingTimeInterval(TimeInterval(-1))

but then you might change the NSPredicate to...

return NSPredicate(format: "day >= %@ AND day <= %@", argumentArray: [startOfDay, endOfDayLessOneSecond])

...with specific note of the change from `day < %@` to `day <= %@`.
Reply



Forum Jump:


Users browsing this thread:
1 Guest(s)

©0Day  2016 - 2023 | All Rights Reserved.  Made with    for the community. Connected through