1
votes

I want to create a NSPredicate with BETWEEN keyword for two dates: my argument e_date is a CoreData Entity Property of type Date

let sd = DateComponents(calendar: Calendar.current,year: 2019, month: 1, day: 1).date!
let ed = DateComponents(calendar: Calendar.current,year: 2020, month: 1, day: 1).date!

let whenPredicate = NSPredicate(format: "e_date BETWEEN %@", [sd, ed])

I get a following exception:

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unable to parse the format string "e_date BETWEEN %@"'

I have tried to cast arguments to Objective-C Types but still gets the same error.

let whenPredicate = NSPredicate(format: "e_date BETWEEN %@", [sd as NSDate, ed as NSDate])
let whenPredicate = NSPredicate(format: "e_date BETWEEN %@", [sd as NSDate, ed as NSDate] as NSArray)

What is a correct way to use NSPredicate with BETWEEN keyword?

* Updated *

I have done Clean Build Folderand the error has gone.

1
stackoverflow.com/a/5269494/1801544 use e_date > sd AND e_date < ed - Larme
@Larme Thx for the link. A predicate with BETWEEN can be applied on a memory store and a collection types. A solution with < > works but this question is to understand why NSPredicate(format with between terminates with an exception. One more thing, NSPredicate doesn't know where it will be used, so it should parse correctly at this stage. - Blazej SLEBODA

1 Answers

1
votes

It is quite strange, because the predicate works well the way you wrote it:

 let sd = DateComponents(calendar: Calendar.current,year: 2019, month: 1, day: 1).date!
 let ed = DateComponents(calendar: Calendar.current,year: 2020, month: 1, day: 1).date!

 let whenPredicate = NSPredicate(format: "e_date BETWEEN %@", [sd, ed])

 let date = DateComponents(calendar: Calendar.current,year: 2019, month: 10, day: 17).date!

 whenPredicate.evaluate(with: ["e_date": date]) // true

I suspect a bug, you may still use < and > and fill a feedback.

EDIT: It could be a Core Data problem, because when you use Objective-C methods and types the syntax is still correct and working...

let dates : NSArray = [
    DateComponents(calendar: Calendar.current,year: 2018, month: 10, day: 17).date! as NSDate,
    DateComponents(calendar: Calendar.current,year: 2019, month: 10, day: 17).date! as NSDate,
    DateComponents(calendar: Calendar.current,year: 2020, month: 10, day: 17).date! as NSDate,
]

let whenPredicate2 = NSPredicate(format: "SELF BETWEEN %@", [sd, ed])

dates.filtered(using: whenPredicate2)

EDIT2: I confirm that with Objective-C classes your original predicate works...

@objc class MyEntity : NSObject {
    @objc let e_date : NSDate

    init(_ date: NSDate) {
        self.e_date = date

        super.init()
    }
}

let entities : NSArray = [
    MyEntity(DateComponents(calendar: Calendar.current,year: 2018, month: 10, day: 17).date! as NSDate),
    MyEntity(DateComponents(calendar: Calendar.current,year: 2019, month: 10, day: 17).date! as NSDate),
    MyEntity(DateComponents(calendar: Calendar.current,year: 2020, month: 10, day: 17).date! as NSDate),
]

entities.filtered(using: whenPredicate)