NSPredicate: NSDate özelliğinin gününe göre nesneleri filtreleme


123

Bir özelliğe sahip bir Core Data modelim var NSDate. Veritabanını güne göre filtrelemek istiyorum. Çözümün bir içereceğini varsayıyorum NSPredicate, ancak hepsini nasıl bir araya getireceğimi bilmiyorum.

İki gün karşılaştırmak bilen NSDates kullanarak NSDateComponentsve NSCalendarfakat nasıl bir ile filtrelerim NSPredicate?

Belki de NSManagedObjectalt sınıfımda sadece yıl, ay ve gün ile çıplak bir tarih döndürebilen bir kategori oluşturmam gerekiyor . Sonra bunu bir NSPredicate. Bu senin tavsiyen mi yoksa daha basit bir şey mi var?

Yanıtlar:


193

NSDate * startDate ve endDate ve NSManagedObjectContext * moc verildiğinde :

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(date >= %@) AND (date <= %@)", startDate, endDate];
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
[request setEntity:[NSEntityDescription entityForName:@"EntityName" inManagedObjectContext:moc]];
[request setPredicate:predicate];

NSError *error = nil;
NSArray *results = [moc executeFetchRequest:request error:&error];

4
ya tek bir randevumuz varsa?
Wasim

4
Kullanabileceğin gibi görünüyor ==. Güne göre arama yapıyorsanız, NSDate'in bir tarih ve saat olduğunu unutmayın - gece yarısından gece yarısına kadar bir aralık kullanmak isteyebilirsiniz.
jlstrecker


@jlstrecker bana gece yarısı ile gece yarısı aralığının nasıl kullanılacağına dair bir örnek gösterebilir. örneğin: aynı 2 günüm var ama farklı zamanlamam var. ve güne göre filtrelemek istiyorum (zamanlama umurumda değil). Bunu nasıl yapabilirim?
iosMentalist

3
@Shady Yukarıdaki örnekte, 2012-09-17 startDate0:00:00 ve endDate2012-09-18 0:00:00 ve tahmini başlangıç ​​tarihi <= tarih < bitişTarihi olarak ayarlayabilirsiniz . Bu, 2012-09-17'de her zaman yakalanacaktır.
jlstrecker

63

StartDate ve endDate'in yukarıda verilen cevaba nasıl ayarlanacağına dair örnek:

...

NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *components = [calendar components:(NSCalendarUnitYear | NSCalendarUnitMonth ) fromDate:[NSDate date]];
//create a date with these components
NSDate *startDate = [calendar dateFromComponents:components];
[components setMonth:1];
[components setDay:0]; //reset the other components
[components setYear:0]; //reset the other components
NSDate *endDate = [calendar dateByAddingComponents:components toDate:startDate options:0];
predicate = [NSPredicate predicateWithFormat:@"((date >= %@) AND (date < %@)) || (date = nil)",startDate,endDate];

...

Burada bir ay içinde tüm kayıtları arıyordum. Bu örneğin 'nil' tarih girişlerinin nasıl aranacağını da gösterdiğini belirtmekte fayda var.


10

Swift'de şuna benzer bir şey buldum:

        let dateFormatter = NSDateFormatter()
        dateFormatter.dateFormat = "yyyy-MM-dd"
        let date = dateFormatter.dateFromString(predicate)
        let calendar = NSCalendar(calendarIdentifier: NSGregorianCalendar)
        let components = calendar!.components(
            NSCalendarUnit.CalendarUnitYear |
                NSCalendarUnit.CalendarUnitMonth |
                NSCalendarUnit.CalendarUnitDay |
                NSCalendarUnit.CalendarUnitHour |
                NSCalendarUnit.CalendarUnitMinute |
                NSCalendarUnit.CalendarUnitSecond, fromDate: date!)
        components.hour = 00
        components.minute = 00
        components.second = 00
        let startDate = calendar!.dateFromComponents(components)
        components.hour = 23
        components.minute = 59
        components.second = 59
        let endDate = calendar!.dateFromComponents(components)
        predicate = NSPredicate(format: "day >= %@ AND day =< %@", argumentArray: [startDate!, endDate!])

Dize enterpolasyonunun "\(this notation)"NSPredicate'de tarihleri ​​karşılaştırmak için işe yaramadığını keşfetmekte zorlandım .


Bu cevap için teşekkür ederim. Swift 3 versiyonu aşağıya eklendi.
DS.

9

Tarih için Swift 3.0 uzantısı:

extension Date{

func makeDayPredicate() -> NSPredicate {
    let calendar = Calendar.current
    var components = calendar.dateComponents([.year, .month, .day, .hour, .minute, .second], from: self)
    components.hour = 00
    components.minute = 00
    components.second = 00
    let startDate = calendar.date(from: components)
    components.hour = 23
    components.minute = 59
    components.second = 59
    let endDate = calendar.date(from: components)
    return NSPredicate(format: "day >= %@ AND day =< %@", argumentArray: [startDate!, endDate!])
}
}

O zaman aşağıdaki gibi kullanın:

 let fetchReq = NSFetchRequest(entityName: "MyObject")
 fetchReq.predicate = myDate.makeDayPredicate()

8

Yanıtı Glauco Neves'den Swift 2.0'a taşıdım ve bir tarih alan ve NSPredicatekarşılık gelen gün için döndüren bir işlevin içine sardım :

func predicateForDayFromDate(date: NSDate) -> NSPredicate {
    let calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)
    let components = calendar!.components([.Year, .Month, .Day, .Hour, .Minute, .Second], fromDate: date)
    components.hour = 00
    components.minute = 00
    components.second = 00
    let startDate = calendar!.dateFromComponents(components)
    components.hour = 23
    components.minute = 59
    components.second = 59
    let endDate = calendar!.dateFromComponents(components)

    return NSPredicate(format: "day >= %@ AND day =< %@", argumentArray: [startDate!, endDate!])
}

Bu cevap için teşekkür ederim. Swift 3 versiyonu aşağıya eklendi.
DS.

6

Rafael'in cevabına (inanılmaz derecede faydalı, teşekkürler!) Swift 3'ü aktarıyorum.

func predicateForDayFromDate(date: Date) -> NSPredicate {
    let calendar = Calendar(identifier: Calendar.Identifier.gregorian)
    var components = calendar.dateComponents([.year, .month, .day, .hour, .minute, .second], from: date)
    components.hour = 00
    components.minute = 00
    components.second = 00
    let startDate = calendar.date(from: components)
    components.hour = 23
    components.minute = 59
    components.second = 59
    let endDate = calendar.date(from: components)

    return NSPredicate(format: "YOUR_DATE_FIELD >= %@ AND YOUR_DATE_FIELD =< %@", argumentArray: [startDate!, endDate!])
}

1

Son zamanlarda aynı sorunu çözmeye çalışmak için biraz zaman harcadım ve başlangıç ​​ve bitiş tarihlerini hazırlamak için aşağıdakileri alternatifler listesine ekledim (iOS 8 ve üstü için güncellenmiş yöntemi içerir) ...

NSDate *dateDay = nil;
NSDate *dateDayStart = nil;
NSDate *dateDayNext = nil;

dateDay = <<USER_INPUT>>;

dateDayStart = [[NSCalendar currentCalendar] startOfDayForDate:dateDay];

//  dateDayNext EITHER
dateDayNext = [dateDayStart dateByAddingTimeInterval:(24 * 60 * 60)];

//  dateDayNext OR
NSDateComponents *dateComponentDay = nil;
dateComponentDay = [[NSDateComponents alloc] init];
[dateComponentDay setDay:1];
dateDayNext = [[NSCalendar currentCalendar] dateByAddingComponents:dateComponentDay
                                                            toDate:dateDayStart
                                                           options:NSCalendarMatchNextTime];

... ve NSPredicateTemel Veriler için NSFetchRequest(yukarıda diğer yanıtlarda gösterildiği gibi) ...

[NSPredicate predicateWithFormat:@"(dateAttribute >= %@) AND (dateAttribute < %@)", dateDayStart, dateDayNext]]

0

Benim için bu çalıştı.

NSCalendar *calendar = [NSCalendar currentCalendar];
    NSDateComponents *components = [calendar components:(NSYearCalendarUnit | NSMonthCalendarUnit ) fromDate:[NSDate date]];
    //create a date with these components
    NSDate *startDate = [calendar dateFromComponents:components];
    [components setMonth:0];
    [components setDay:0]; //reset the other components
    [components setYear:0]; //reset the other components
    NSDate *endDate = [calendar dateByAddingComponents:components toDate:startDate options:0];

    startDate = [NSDate date];
    endDate = [startDate dateByAddingTimeInterval:-(7 * 24 * 60 * 60)];//change here

    NSString *startTimeStamp = [[NSNumber numberWithInt:floor([endDate timeIntervalSince1970])] stringValue];
    NSString *endTimeStamp = [[NSNumber numberWithInt:floor([startDate timeIntervalSince1970])] stringValue];


   NSPredicate *predicate = [NSPredicate predicateWithFormat:@"((paidDate1 >= %@) AND (paidDate1 < %@))",startTimeStamp,endTimeStamp];
    NSLog(@"predicate is %@",predicate);
    totalArr = [completeArray filteredArrayUsingPredicate:predicate];
    [self filterAndPopulateDataBasedonIndex];
    [self.tableviewObj reloadData];
    NSLog(@"result is %@",totalArr);

Diziyi geçerli tarihten 7 gün öncesine kadar filtreledim. Yani şu anki tarihten bir haftalık veri alıyorum. Bu çalışmalı.

Not: Milyon saniye ile gelen tarihi 1000'e dönüştürüyor ve sonrasını karşılaştırıyorum. Açıklığa ihtiyacınız olursa bana bildirin.


Cevabınızda completeArrayArray of var mı dictionaryyoksa dataModel DataModel'e uygulamak istiyorum.
Sumeet Mourya
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.