问题
I'm stuck in a problem with my Core Data model and a fetch request that involves dates.
I have some objects in a entity with a NSDate attribute; I need to extract the objects with the date of today but I always get nil from this code:
public func getObjectsOfToday() -> Array<myObject>?
{
let entityDescription = NSEntityDescription.entityForName("Objects", inManagedObjectContext: DataAccess.sharedInstance.managedObjectContext)
let request = NSFetchRequest()
request.entity = entityDescription
request.returnsObjectsAsFaults = false
let today = NSDate()
request.predicate = NSPredicate(format: "(dateStart => %@) AND (dateStart <= %@)", today, today)
var objects: [AnyObject]?
do
{
objects = try DataAccess.sharedInstance.managedObjectContext.executeFetchRequest(request)
}
catch let error as NSError
{
print(error)
objects = nil
}
return objects as? Array<Objects>
}
the problem I think it's the NSPredicate because it considers also hours, minute and seconds. If I print today is something like:
Printing description of today: 2016-02-28 22:02:01 +0000
but I want to fetch objects with just the same date, ignoring hours, minutes and seconds. What I need to do?
I also tried to create another NSDate using components:
let components = cal.components([.Day , .Month, .Year ], fromDate: today)
let newDate = cal.dateFromComponents(components)
but the result it's the same. What am I doing wrong?
回答1:
What I do is compare it to the start and end of the day and have a couple helper functions to calculate them:
class DateHelper{
internal class func startOfDay(day: NSDate) -> NSDate {
let gregorian = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)
let unitFlags: NSCalendarUnit = [.Minute, .Hour, .Day, .Month, .Year]
let todayComponents = gregorian!.components(unitFlags, fromDate: day)
todayComponents.hour = 0
todayComponents.minute = 0
return (gregorian?.dateFromComponents(todayComponents))!
}
internal class func endOfDay(day: NSDate) -> NSDate {
let gregorian = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)
let unitFlags: NSCalendarUnit = [.Minute, .Hour, .Day, .Month, .Year]
let todayComponents = gregorian!.components(unitFlags, fromDate: day)
todayComponents.hour = 23
todayComponents.minute = 59
return (gregorian?.dateFromComponents(todayComponents))!
}
}
So in your code, you would call:
request.predicate = NSPredicate(format: "(dateStart => %@) AND (dateStart <= %@)", DateHelper.startOfDay(today), DateHelper.endOfDay(today))
回答2:
create a start date, get the length of the day (interval), add the interval to start date to get the next day's start.
var startOfToday: NSDate?
var interval: NSTimeInterval = 0
NSCalendar.currentCalendar().rangeOfUnit(.Day, startDate: &startOfToday, interval: &interval, forDate: NSDate())
let startOfTomorrow = startOfToday!.dateByAddingTimeInterval(interval)
create the predicate
let predicate = NSPredicate(format: "dateStart >= %@ AND dateStart < %@", startOfToday, startOfTomorrow)
I used the following test code without the core data hassle
import Foundation
let dates:[NSDate] = {
var dates:[NSDate] = []
dates.append({
let c = NSDateComponents()
c.year = 2016
c.month = 2
c.day = 1
return NSCalendar.currentCalendar().dateFromComponents(c)!
}())
dates.append({
let c = NSDateComponents()
c.year = 2016
c.month = 2
c.day = 3
return NSCalendar.currentCalendar().dateFromComponents(c)!
}())
dates.append({
let c = NSDateComponents()
c.year = 2016
c.month = 3
c.day = 1
return NSCalendar.currentCalendar().dateFromComponents(c)!
}())
dates.append({
let c = NSDateComponents()
c.year = 2016
c.month = 2
c.day = 28
c.hour = 12
c.minute = 30
return NSCalendar.currentCalendar().dateFromComponents(c)!
}())
dates.append({
let c = NSDateComponents()
c.year = 2016
c.month = 2
c.day = 28
c.hour = 11
c.minute = 15
return NSCalendar.currentCalendar().dateFromComponents(c)!
}())
return dates
}()
var startOfToday: NSDate?
var interval: NSTimeInterval = 0
NSCalendar.currentCalendar().rangeOfUnit(.Day, startDate: &startOfToday, interval: &interval, forDate: NSDate())
if let startOfToday = startOfToday {
let startOfTomorrow = startOfToday.dateByAddingTimeInterval(interval)
let predicate = NSPredicate(format: "self >= %@ AND self < %@", startOfToday, startOfTomorrow)
let filteredArray = dates.filter({predicate.evaluateWithObject($0)})
print(filteredArray)
}
Result:
[2016-02-28 11:30:00 +0000, 2016-02-28 10:15:00 +0000]
来源:https://stackoverflow.com/questions/35688952/how-fetch-objects-with-nsdate-of-today-using-nspredicate