如何使用 NSPredicate 获取今天的 NSDate 对象?

Posted

技术标签:

【中文标题】如何使用 NSPredicate 获取今天的 NSDate 对象?【英文标题】:How fetch objects with NSDate of today using NSPredicate? 【发布时间】:2016-02-28 22:12:54 【问题描述】:

我的核心数据模型和涉及日期的获取请求遇到问题。

我在具有 NSDate 属性的实体中有一些对象; 我需要提取今天日期的对象,但我总是从这段代码中得到 nil:

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>

我认为是 NSPredicate 的问题,因为它还考虑了小时、分钟和秒。如果我今天打印是这样的:

今日打印说明:2016-02-28 22:02:01 +0000

但是我想获取具有相同日期的对象,忽略小时、分钟和秒。我需要做什么?

我还尝试使用组件创建另一个 NSDate:

let components = cal.components([.Day , .Month, .Year ], fromDate: today)
let newDate = cal.dateFromComponents(components)

但结果是一样的。我做错了什么?

【问题讨论】:

【参考方案1】:

我所做的是将它与一天的开始和结束进行比较,并使用几个辅助函数来计算它们:

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))!
    

所以在你的代码中,你会调用:

request.predicate = NSPredicate(format: "(dateStart => %@) AND (dateStart <= %@)", DateHelper.startOfDay(today), DateHelper.endOfDay(today))

【讨论】:

由于此代码不处理秒、纳秒和时代,因此在边缘情况下它可能会失败。此类方法更自然的地方是 NSDate 上的扩展而不是辅助类。 这两点都很好——如果你有改进的地方,请随意!【参考方案2】:

创建一个开始日期,获取一天的长度(间隔),将间隔添加到开始日期以获得第二天的开始。

var startOfToday: NSDate?
var interval: NSTimeInterval = 0

NSCalendar.currentCalendar().rangeOfUnit(.Day, startDate: &startOfToday, interval: &interval, forDate: NSDate())
let startOfTomorrow = startOfToday!.dateByAddingTimeInterval(interval)

创建谓词

let predicate = NSPredicate(format: "dateStart >= %@ AND dateStart < %@", startOfToday, startOfTomorrow)

我使用以下测试代码没有核心数据的麻烦

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)

结果:

[2016-02-28 11:30:00 +0000, 2016-02-28 10:15:00 +0000]

【讨论】:

以上是关于如何使用 NSPredicate 获取今天的 NSDate 对象?的主要内容,如果未能解决你的问题,请参考以下文章

NSPredicate 比较字符串小于其他字符串

如何使用 NSPredicate 和 CloudKit 获取特定用户的最新帖子?

如何在核心数据中使用 NSPredicate 从属性之一获取值

使用 NSPredicate 获取核心数据对象数组?

核心数据:NSPredicate 一对多对多关系

获取的属性和 NSPredicate