搜索CoreData以匹配NSDate - Swift

时间:2014-08-29 14:46:27

标签: ios core-data swift nsdate nspredicate

我想搜索所有现有对象,以查看CoreData中是否有任何匹配的日期对象:

日期目前通过 start_date 属性保存在我的CoreData中,格式如下:2013-08-29 14:27:47 +0000。

然后我让用户从UIDatePicker中选择日期并将.date()分配给变量日期

e.g。我的选择日期 = 2013-08-29 17:34:23 +0000。

以下是我使用谓词搜索CoreData的方法。

let predicate = NSPredicate(format: "start_date contains[search] %@", date)
let request:NSFetchRequest = NSFetchRequest(entityName: "Project")
let sortDescriptor:NSSortDescriptor = NSSortDescriptor(key: "number", ascending: true)
let sortDescriptorsAry:NSArray = [sortDescriptor]
request.sortDescriptors = sortDescriptorsAry
request.predicate = predicate

return request

然而我没有结果。我认为这是因为两个属性因时间而不匹配:

  

start_date = 2013-08-29 14:27:47 +0000

     

date = 2013-08-29 17:34:23 +0000

我怎么能告诉CoreData忽略" 177:34:23 + 0000"有点,还是有更好的方法?

编辑:

我可以选择更改最初存储日期格式的方式:

我试过这个:

    var now:NSDate = self.startDatePicker.date
    var calendar:NSCalendar = NSCalendar(calendarIdentifier: NSGregorianCalendar)
    var components:NSDateComponents = calendar.components(NSCalendarUnit.CalendarUnitYear | NSCalendarUnit.CalendarUnitMonth | NSCalendarUnit.CalendarUnitDay, fromDate: now)
    components.hour = 00
    components.minute = 00
    components.second = 00
    var newDate:NSDate = calendar.dateFromComponents(components)!

然而在某些日子里,我的时间定在前一天。 例如:

选择8月30日,改造后我得到2014-08-29 23:00:00 +0000

3 个答案:

答案 0 :(得分:2)

在Core Data中保存start_date属性之前,您需要确保他们的时间设置为12:00 AM:

//Get "Aug 29, 2014, 12:00 AM" from "Aug 29, 2014, 10:07 PM"
let newDate = NSDate() //or any other date
let calendar = NSCalendar.currentCalendar()
calendar.timeZone = NSTimeZone.systemTimeZone()
var startDate: NSDate?
var duration: NSTimeInterval = 0
calendar.rangeOfUnit(.DayCalendarUnit, startDate: &startDate, interval: &duration, forDate: newDate)

//Create, set and save a new managedObject
//Records, here, is the name of your NSManagedObject subclass
let record = NSEntityDescription.insertNewObjectForEntityForName("Records", inManagedObjectContext: managedObjectContext) as Records
record.start_date = startDate
/* set other attributes here */

var error: NSError?
if !managedObjectContext.save(&error) {
    // Replace this implementation with code to handle the error appropriately.
    // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
    println("Unresolved error \(error), \(error!.userInfo)")
    abort()
}

然后,您将能够使用您想要的谓词在Core Data中获取日期:

//Set your datePicker date to 12:00 AM
let pickerDate = dateFromMyDatePicker //as NSDate
let calendar = NSCalendar.currentCalendar()
calendar.timeZone = NSTimeZone.systemTimeZone()
var predicateDate: NSDate?
var duration: NSTimeInterval = 0
calendar.rangeOfUnit(.DayCalendarUnit, startDate: &predicateDate, interval: &duration, forDate: pickerDate)

//Create your fetchRequest
/* ... */
//Set your predicate
let predicate = NSPredicate(format: "start_date == %@", predicateDate)

修改

作为rangeOfUnit:startDate:interval:forDate:的替代方案,您可以使用您提供的代码。但在这两种情况下,请不要忘记添加以下行:

calendar.timeZone = NSTimeZone.systemTimeZone()

答案 1 :(得分:1)

<edit>

在我看来,第二种做事方式似乎是一种很好的方式。存储年,月和日的整数值,并使用该值创建谓词。您对NSDateComponents和日历的使用非常好,因此这应该是最简单的方法。非常重要:不要使用00的时间,因为午夜是一个棘手的时间(在世界的某些地方有夏令时,有一个问题是午夜是否是第二天的前一部分)。只需输入12作为时间,尽可能远离午夜。 此外,我建议你从2011年的“执行日历计算,会议117”观看WWDC。它讨论了其他非常有趣的事情,关于为什么午夜很棘手(如果没有,那么在2013年会议中解释:)。

</edit>

NSDate具有亚秒级的准确性。它的描述方法(在NSLog NSDate时调用)仅显示第二精度。 因此,要在NSPredicate中使用NSDate,请始终指定“大于/小于或等于”运算符。

例如:

NSDate * lastWeek = // ... created using NSCalendar and NSDateComponents.
NSDate * now = [NSDate date];

NSPredicate * entitiesFromAfterLastWeekAndBeforeNow = [NSPredicate predicateWithFormat: @"start_date >= %@ AND start_date <= %@", lastWeek, now];

我建议不要将数据存储在原生NSDate的其他内容中,因为您可能会存储由于转换而导致错误的日期。此外,将日期存储为字符串将使查询慢得多(因为必须解析字符串,而NSDate只是一个数字)。但这是另一个讨论,你可能想发货,所以你必须做你认为最好的事情。

编辑:对不起,现在才注意到你正在写Swift。但我认为我的例子很清楚它可以转换为Swift,对吧?

答案 2 :(得分:1)

如果您仍然需要更改存储数据的方式,我会将其存储在您的项目实体中作为三个属性:年份的整数,月份的整数和白天的整数。编码会更容易(你可以创建一个谓词:

NSInteger year = ....
NSInteger month = ....
NSInteger day = ....    
[NSPredicate predicateWithFormat: @"day == %@  AND month == %@ and year == %@", @(day), @(month), @(year)];

)与使用字符串相比,这可能更快。如果你想使用字符串(注意无关的空格或其他交集!),你可以在代码中构造一个格式为&#39; yyyy-mm-dd&#39;的字符串。 (使用NSString stringWithFormat :)然后使用NSPredicate,如:

NSInteger year = ....
NSInteger month = ....
NSInteger day = ....    
NSString * dateString = [NSStringWithFormat: @"%4i-%2i-%2i", year, month, day];
[NSPredicate predicateWithFormat: @"dateString contains %@", dateString];

但是,只有在您构建了存储的字符串而不是NSDate.description()时,这才有效。如果您存储实际的NSDate,请参阅我的第一个原始答案:)。

但实际上,如果您仍有选项,请不要将其存储为字符串。如果不是现在,那么它确实会成为问题,然后(我可以从经验中得知)。