4

I have a Realm database with an object "Events" with a property name "occasion" of type string, a property name "venue" of type string and the other one is "date" of type Date(). My question is how do we query the occasions which have a date the same as today (current day). I have tried this code to retrieve the occasions using the date filter and it does work:

let date = Date()
let dateFormatter = DateFormatter()
// dateFormatter.dateFormat = "dd/MM/yyyy"
dateFormatter.dateFormat = "d MMM yyyy"
let stringDate = dateFormatter.string(from: date)        

todayEvent = realm.objects(Events.self).filter("date = '\(stringDate)'").sorted(byKeyPath: "venue", ascending: true)

The date in the Realm database shows a date in this format "17 Jan 2019 at 12:00:00 AM" even when the date was saved in the format of dd/MM/yyyy. I've tried changing the date format but still, it won't work. Or do I need to set a format for the date property when I declare it in the first place? If so how do I do this in a Realm class object? I've tried but it gave an error. I'm stuck here now. Please help

This is how I saved the data to Realm database :

@IBAction func addNewEventButtonPressed(_ sender: UIButton) {



    let newDataEntry = Events()

    newDataEntry.occasion = occasionTextFile.text!


    let dateString =  dateTextField.text!
    let dateFormatter = DateFormatter()
    dateFormatter.dateFormat = "dd/MM/yyyy"
    let dateFromString = dateFormatter.date(from: dateString)

    newDataEntry.date = dateFromString!

    do {
        try realm.write {
            realm.add(newDataEntry)
        }
    } catch {
        print("Error saving data \(error)")
    }


}

halim
  • 87
  • 2
  • 2
  • 11

3 Answers3

2

According to Realm docs (emphasis mine):

The comparison operators ==, <=, <, >=, >, !=, and BETWEEN are supported for Int, Int8, Int16, Int32, Int64, Float, Double and Date property types

Thus, the following should work:

let date = Date()
todayEvent = realm.objects(Events.self)
    .filter("date == %@", date)
    .sorted(byKeyPath: "venue") // sorted in ascending order by default
Dan Karbayev
  • 2,870
  • 2
  • 19
  • 28
  • I used your code again. Now the app started normally and did not crashed. However I still did not get the result of the query displayed in the table. – halim Jan 18 '19 at 08:06
  • I put a print statement for “todayEvent” to findout whether the code was called in the load func, the console states “Optional(Results <0x7f9a1754d9f0>. I dont know whether it is a usefulI info but I hope this would help to solve the matter. – halim Jan 18 '19 at 08:45
  • Just to update. When I just make a normal query without the filter in the syntax, the table displays all the available data including the dates. If I put the filter in the query syntax so that the result would show only the event which has the same date as current day, the table return empty. So it must be the syntax. At least that is what Im thinking. – halim Jan 18 '19 at 10:19
  • https://stackoverflow.com/a/35965216/10784781. Found the answer here. Now trying to set the query to “tomorrow”. Thank you very much. – halim Jan 19 '19 at 03:35
1

You are using Date object which is with time & locale, so to use only with date can use below function for removing time & locale from date object:

   func reomveTimeFrom(date: Date) -> Date {
            let components = Calendar.current.dateComponents([.year, .month, .day], from: date)
            let date = Calendar.current.date(from: components)
            return date!
        }

Now use this function to get exact date object & fetch data from realm database.

let today = self.reomveTimeFrom(date: Date())
let predicate = NSPredicate(format: "date ==  %@",today as NSDate)
let results = realm.objects(Events.self).filter(predicate)

Complete source code on github

Rocky
  • 2,903
  • 1
  • 22
  • 26
  • @DávidPásztor- update syntax for swift, previous one was for react-native. – Rocky Jan 17 '19 at 09:54
  • Rocky and Dan Karbayev, I have tried both codes and the app crashed with the following message in the console: Terminating app due to uncaught exception ‘invalid value’, reason: ‘Expected object of type date for property ‘date’ on object of type ‘Events’, but received: 19/01/2019’. I did not even have the chance to enter any date when the app crashed. Where did this “19/01/2019” come from? – halim Jan 18 '19 at 03:56
  • @halim - share your schema for `Events` table. – Rocky Jan 18 '19 at 04:40
  • Events class using Realm database has 3 properties. 1. occasions of type String 2. venue of type String 3. date of type Date(). – halim Jan 18 '19 at 06:22
  • @Rocky Thank you but the app still crash when I run it using the new codes. I’m using Dan Karbayev version now. Though the app run it still wont display the result of the query in my tableview – halim Jan 18 '19 at 09:23
  • @halim you can get woking copy of full source code on Github link. – Rocky Jan 18 '19 at 13:41
  • I found the answer here : https://stackoverflow.com/a/35965216/10784781 Thank you bery much for your efforts. – halim Jan 19 '19 at 03:36
0

The issue is you're storing Date objects but trying to filter that property as a string.

This line

let dateFromString = dateFormatter.date(from: dateString)

creates a Date() object from a string and that's what's stored in your Realm property.

A Realm date object looks like this

2019-01-18T05:00:00.000Z

Here's your filter:

let stringDate = dateFormatter.string(from: date)
todayEvent = realm.objects(Events.self).filter("date = '\(stringDate)'")

This is creating a string from a date object and Realm won't know what to do with it. If you want to filter a date property, use a date object to do so.

Importantly though - that line should crash with the following error

Expected object of type date for property 'date' on object of type 'Event', but received: 18 Jan 2019

The solution is that if the property your searching on is a Date, then the filter needs to be a Date object.

So an example of writing a date object that starts as a mm/dd/yyyy string

let aDateString = "01/20/2019"
let mmddyyyyFormatter = DateFormatter()
mmddyyyyFormatter.dateFormat = "MM/dd/yyyy"
if let dateObjectToStore = mmddyyyyFormatter.date(from: aDateString) {
    newDataEntry.date = dateObjectToStore
} else {
    print("could not create date object")
}

Suppose we now want to find that object with a string of "yyyymmdd"

let dateStringToFind = "20190120"
let yyyymmddFormatter = DateFormatter()
yyyymmddFormatter.dateFormat = "yyyyMMdd"
let dateObjectToFind = yyyymmddFormatter.date(from: dateStringToFind)
let results = realm.objects(MyObject.self).filter("date == %@", dateObjectToFind)
if results.count > 0 {
    for myObject in results {
        print(myObject)
    }
} else {
    print("no objects have that date")
}

as you can see, we stored a date as a date object and then when filtering, filtered for a date object.

There are some caveats to filtering and some exceptions but you get the general idea.

Jay
  • 34,438
  • 18
  • 52
  • 81