Предикат Swift Core data NSFetchRequest для извлечения даты и времени

#ios #swift #core-data #nsfetchrequest

#iOS #swift #core-data #nsfetchrequest

Вопрос:

У меня есть таблица базы данных с именем UVHour, которая имеет следующую структуру

UVHour

Мое приложение заполнит таблицу UVHour из JSON, которая выглядит следующим образом

 [
    {
        "ORDER": 1,
        "DATE_TIME": "SEP/04/2020 04 AM",
        "UV_VALUE": 0
    },
    {
        "ORDER": 2,
        "DATE_TIME": "SEP/04/2020 05 AM",
        "UV_VALUE": 0
    }
]

  

Текущий запрос NSFetchRequest

 static var uvIndexNowRequest: NSFetchRequest<UVHour>
    {
        let dateTimeNow = Date()
        let formatter = DateFormatter()
        formatter.dateFormat = "MMM/d/yyyy hh a"
        let dateHourStr = formatter.string(from: dateTimeNow)
        
        let request: NSFetchRequest = UVHour.fetchRequest()
        
        request.sortDescriptors = [NSSortDescriptor(key: "order", ascending: true)]

        // Below code will throw 'NSInvalidArgumentException', reason: 'Unable to parse the format string "date_time == Sep/4/2020 08 PM"
        // request.predicate = NSPredicate(format: "date_time == (dateHourStr)")
        
        return request
    }
  

Вопрос

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

Пример

Допустим, что текущая дата — 4 сентября 2020 года, 04:10 утра.

Основываясь на приведенном выше JSON, я бы выбрал UVHour, который является следующим

 [
    {
        "ORDER": 1,
        "DATE_TIME": "SEP/04/2020 04 AM",
        "UV_VALUE": 0
    }
]

  

Как я могу это сделать?

Ответ №1:

Я смог обновить uvIndexNowRequest, чтобы найти свое решение. Смотрите приведенный ниже код

 static var uvIndexNowRequest: NSFetchRequest<UVHour>
    {
        let dateTimeNow = Date()
        
        let formatter = DateFormatter()
        formatter.timeZone = .current
        formatter.dateFormat = "MMM/d/yyyy hh a"
        
        // Find date String from 'formatter.dateFormat'
        let dateHourStr = formatter.string(from: dateTimeNow)
        
        // Get date from dateHourStr
        let someDateTimeOpt = formatter.date(from: dateHourStr)
        
        let request: NSFetchRequest = UVHour.fetchRequest()
        
        request.sortDescriptors = [NSSortDescriptor(key: "order", ascending: true)]
        
        if let someDate = someDateTimeOpt {
            request.predicate = NSPredicate(format: "date_time == %@", someDate as CVarArg)
        }
        
        return request
    }
  

Ответ №2:

Более короткой альтернативой является расширение NSDate (!) для получения часа. Преимущество в том, что вы можете использовать вычисляемое свойство в качестве ключевого пути.

 extension NSDate {
    dynamic var isInCurrentHour : Bool {
        return Calendar.current.isDate(self as Date, equalTo: Date(), toGranularity: .hour)
    }
  

}


 static var uvIndexNowRequest: NSFetchRequest<UVHour>
{
    let request: NSFetchRequest = UVHour.fetchRequest()
    request.sortDescriptors = [NSSortDescriptor(key: "order", ascending: true)]
    request.predicate = NSPredicate(format: "date_time.isInCurrentHour == TRUE")
    
    return request
}
  

Комментарии:

1. Я добавил ваш код, но получил исключение NSUnknownKeyException с ошибкой ..»этот класс не соответствует кодированию значения ключа для ключевого часа» Я думаю, что это как-то связано с вашим NSPredicat(format:"date_time.hour== %ld", currentHour)

2. Пожалуйста, попробуйте это с dynamic

3. dynamic делает свойство совместимым с кодированием ключевого значения

4. Спасибо, чувак. Я понятия не имел, что смогу сделать это таким образом!

5. Хотел сообщить вам обновление. То, как вы запрашиваете core data, больше не выдает мне ошибок, но когда я запускаю fetchRequest, я больше не извлекаю правильные данные. Я изучу это подробнее и дам вам обновление.