NSPredicate:NSDateプロパティの日によるオブジェクトのフィルタリング


123

NSDateプロパティを持つコアデータモデルがあります。データベースを日でフィルタリングしたい。ソリューションにはが含まれるNSPredicateと思いますが、すべてをまとめる方法がわかりません。

NSDateを使用NSDateComponentsして2つのの日を比較する方法を知っていますがNSCalendar、それをどのようにフィルタリングしNSPredicateますか?

おそらくNSManagedObject、年、月、日だけで最低限の日付を返すことができるカテゴリをサブクラスに作成する必要があります。次に、それをで比較できNSPredicateます。これはあなたの推薦ですか、それとももっと簡単なものがありますか?

回答:


193

NSDate * startDateおよびendDateとNSManagedObjectContext * mocが指定された場合

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
日付が1つしかない場合はどうなりますか?
Wasim

4
使用できるようです==。ただし、日単位で検索する場合は、NSDateが日付と時刻であることを覚えておいてください。午前0時から午前0時の範囲を使用することもできます。
jlstrecker

1
startDateとendDateの設定方法の例については、以下の私の回答を参照してください
d.ennis

@jlstreckerは、午前0時から午前0時の範囲の使用例を見せてくれます。たとえば、私は同じ2日間ですが、タイミングが異なります。そして、私は日でフィルタリングしたい(私はタイミングを気にしない)。どうやってやるの?
iosMentalist 2012

3
@Shady上記の例では、startDate2012-09-17 0:00:00および2012-09-18 0:00:00に設定しendDate、述語をstartDate <= date <endDateに設定できます。それは2012-09-17に常にキャッチされます。
jlstrecker 2012

63

startDateとendDateを上記の回答に設定する方法の例:

...

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];

...

ここでは、1か月以内にすべてのエントリを検索していました。この例は「nil」の日付全体を検索する方法も示していることは注目に値します。


10

Swiftで私は次のようなものを得ました:

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

文字列補間"\(this notation)"がNSPredicateの日付を比較するために機能しないことを発見するのに苦労しました。


この回答をありがとうございます。以下にSwift 3バージョンを追加しました。
DS。

9

日付のSwift 3.0拡張:

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

次に、次のように使用します。

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

8

私はGlauco Nevesからの回答をSwift 2.0 に移植し、日付を受け取りNSPredicate、対応する日のを返す関数内にラップしました。

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

この回答をありがとうございます。以下にSwift 3バージョンを追加しました。
DS。

6

ラファエルの回答に加えて(信じられないほど便利です、ありがとう!)、Swift 3への移植です。

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

私は最近、この同じ問題を解決するために少し時間を費やして、開始日と終了日を準備するための選択肢のリストに以下を追加しました(iOS 8以降の更新されたメソッドを含む)...

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];

...およびNSPredicateコアデータのNSFetchRequest(他の回答ですでに示したように)...

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

0

私にとってはこれでうまくいきました。

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

現在の日付から7日前までの配列をフィルターしました。つまり、現在の日付から1週間分のデータを取得しています。これはうまくいくはずです。

注:私はミリ秒で来る日付を1000で変換し、後で比較しています。明確にする必要がある場合はお知らせください。


あなたの答えcompleteArrayは、それが配列を持っているdictionarydataModel 、DataModelに適用したいということです。
Sumeet Mourya 2017年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.