Search code examples
iosswift3nsdatenspredicatensfetchrequest

Filter fetchRequest for year/month using NSPredicate


I have an app that has several time entries with a date saved as NSDate.

I would like to use a fetch request to filter for a certain year and month that I get from somewhere else. How can I use NSPredicate to filter for a year and month?

let predicate = NSPredicate(format: "%K == %D && %K == %D", ???, selectedMonth, ???, selectedYear)

Update

Using the help Raki pointed out I came up with the following code:

var dateComp = DateComponents()
dateComp.year = Int(selectedYear)
dateComp.month = Int(selectedMonth)
dateComp.day = 1
    
let calendar = Calendar.current
let firstDayOfTheMonth = calendar.date(from: dateComp)
    
var oneMonth = DateComponents()
oneMonth.month = 1
let beginningOfNextMonth = calendar.date(byAdding: oneMonth, to: firstDayOfTheMonth!)

And the predicate:

let predicate = NSPredicate(format: "date >= %@ AND date < %@", firstDayOfTheMonth as! CVarArg, beginningOfNextMonth as! CVarArg)

I get a SIGABRT with the following message:

Could not cast value of type 'Foundation.Date' (0x1073a0ae0) to 'Swift.CVarArg' (0x1196851c8).

Xcode suggested I add "as! CVarArg"

Update 2

The following predicate worked now:

let predicate = NSPredicate(format: "%K >= %@ && %K < %@", "date", firstDayOfTheMonth! as NSDate, "date", beginningOfNextMonth! as NSDate)

Solution

  • You cannot predicate like this, but you can create two Dates from your month and year which start day of month and end day of month.

    Now you need to simply predicate like this way.

    let predicate = NSPredicate(format: "%K >= %@ && %K <= %@", "DateAttribute", startDateOfMonth as NSDate, "DateAttribute", endDateOfMonth as NSDate)
    

    Edit: If you don't know how to create date for startDateOfMonth and endDateOfMonth, then you can create it using DateComponents.

    let selectedMonth = 11
    let selectedYear = 2015
    var components = DateComponents()
    components.month = selectedMonth
    components.year = selectedYear
    let startDateOfMonth = Calendar.current.date(from: components)
    
    //Now create endDateOfMonth using startDateOfMonth
    components.year = 0
    components.month = 1
    components.day = -1
    let endDateOfMonth = Calendar.current.date(byAdding: components, to: startDate!)