Как я могу фильтровать по указанной c дате из объекта области в Swift? - PullRequest
0 голосов
/ 07 марта 2020

У меня есть объект области с типом свойства даты Date, и я хочу получить список элементов с указанием c date.

Если я нажму указанную дату c из календаря, например 2020- 03-06, тогда будет представлен список предметов, который был создан в 2020-03-06.

:: EDITED ::

Вот мой объект области с именем "Профиль", и существуют даты с 2020-03-05 по 2020-03- 08.

enter image description here

Вот мой объект Profile и ProfileManager Singleton.

class Profile: Object {
    @objc dynamic var date: Date!
    @objc dynamic var content: String!

    convenience init(_ content: String) {
        self.init()
        self.content = content
        self.date = Date()
    }
}


class ProfileManager {

    static let shared = ProfileManager()

    private var realm = try! Realm()

    var profileList: Results<Profile>?

    private init() {
        profileList = realm.objects(Profile.self)
    }

    func save(_ object: Profile) {
        do {
            try realm.write {
                realm.add(object)
            }
        } catch {
            print(error)
        }
    }

    func addNewProfile(_ content: String) {
        let newProfile = Profile(content)
        save(newProfile)
    }
}

И, наконец, вот viewController, который имеет кнопки. Один для добавления нового профиля и один для печати списка отфильтрованных профилей.

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    @IBAction func addProfilePressed(_ sender: Any) {
        ProfileManager.shared.addNewProfile("profile content")
    }

    @IBAction func filterButtonPressed(_ sender: Any) {
        let stringDate = "2020-03-09"
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "yyyy-MM-dd"
        let searchDate:Date = dateFormatter.date(from: stringDate)!
        let results = ProfileManager.shared.profileList!.filter("date == %@", searchDate)
        print(searchDate)
        print(results)
        for profile in results {
            print(profile.content!)
        }
    }
}

результат на консоли, когда вызывается метод filterButtonPressed.

2020-03-08 15:00:00 +0000
Results<Profile> <0x7f9b36f160a0> (

)

Как я могу исправить эту проблему? И вот еще одна проблема. Я установил для «stringDate» значение «2020-03-09», но когда я печатаю преобразованную дату «searchDate», он печатает «2020-03-08», почему это происходит?

Надеюсь, теперь мои вопросы понятнее для понимания.

1 Ответ

2 голосов
/ 07 марта 2020

Ниже приведен мой первоначальный ответ, который после многих исследований был лишь несколько верным.

Фактический ответ связан с временной частью даты.

Итак ... если мы создадим объект даты с помощью приведенного ниже кода и установим его на известную дату,

let stringDate = "2020-03-08"
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
let searchDate:Date = dateFormatter.date(from: stringDate)!

, фактический объект будет выглядеть следующим образом

2020-03-08T05:00:00.000Z

Однако, как выглядит объект профиля создается, как это

convenience init(_ content: String) {
   self.init()
   self.content = content
   self.date = Date()
}

, и этот объект даты выглядит так

2020-03-08T16:10:25.123Z

, так что, как вы можете видеть, если мы отфильтруем по определенной дате c, они не равны

2020-03-08T05:00:00.000Z != 2020-03-08T16:10:25.123Z

, поэтому этому

let stringDate = "2020-03-08"
let searchDate:Date = dateFormatter.date(from: stringDate)!
let searchResults = realm.objects(Profile.self).filter("date == %@", searchDate)

не удалось найти дату, поскольку она фильтрует для этого

2020-03-08T05:00:00.000Z

Чтобы исправить, измените класс профиля с помощью отметка даты с отметкой времени по умолчанию

class Profile: Object {

    @objc dynamic var date: Date!
    @objc dynamic var content: String!

    convenience init(_ content: String) {
        self.init()
        self.content = content

        let formatter = DateFormatter()
        formatter.timeStyle = .none
        formatter.dateFormat = "MM/dd/yy"

        let today = Date()
        let s = formatter.string(from: today)
        let d = formatter.date(from: s)

        self.date = d
    }
}

или, сохраните ваши даты в виде строки ггггммдд, которая полностью удалит неоднозначность.

- ОРИГИНАЛЬНЫЙ ОТВЕТ НИЖЕ ---

Фильтрация по дате полностью поддерживается для объектов даты. Вот два быстрых примера. Один для фильтрации на указанную c дату (для вашего вопроса) и один для диапазона дат с использованием BETWEEN.

Обратите внимание, у меня есть функция makeDate , которая преобразует строку в дату объект. В этом примере используется объект Realm DogClass, имеющий свойство Date типа dog_birthdate.


Этот фильтр для объектов с указанными c date

let searchDate = self.makeDate(fromString: "06/01/2019")
let specificDateResults = realm.objects(DogClass.self)
                               .filter("dog_birthdate == %@", searchDate)
for dog in specificDateResults {
    print(dog.dog_name)
}

Этот фильтр для объектов в пределах диапазона дат

let startDate = self.makeDate(fromString: "06/01/2019")
let endDate = self.makeDate(fromString: "06/20/2019")
let dateRangeResuls = realm.objects(DogClass.self)
                           .filter("dog_birthdate BETWEEN {%@,%@}", startDate, endDate)
for dog in dateRangeResuls {
    print(dog.dog_name)
}

РЕДАКТИРОВАТЬ : Использование кода в комментарии из OP для тестирования

let stringDate = "2019-06-01"
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
let searchDate:Date = dateFormatter.date(from: stringDate)!
let result = realm.objects(DogClass.self).filter("dog_birthdate == %@", searchDate)
for dog in result {
    print(dog.dog_name)
}

, который отлично работает.

...