objective-c - NSPredicate:تصفية الكائنات حسب يوم خاصية NSDate




core-data nsfetchedresultscontroller (8)

لدي نموذج البيانات الأساسية مع خاصية NSDate . أريد تصفية قاعدة البيانات حسب اليوم. أفترض أن الحل سيشمل NSPredicate ، لكنني لست متأكدًا من كيفية وضع كل ذلك معًا.

أعرف كيفية مقارنة يوم اثنين من NSDateComponents باستخدام NSDateComponents و NSCalendar ، ولكن كيف يمكنني NSPredicate مع NSPredicate ؟

ربما أحتاج إلى إنشاء فئة في الفئة الفرعية NSManagedObject والتي يمكنها إرجاع التاريخ العاري مع العام والشهر واليوم فقط. ثم يمكنني مقارنة ذلك في NSPredicate . هل هذه توصيتك أم أن هناك شيئًا أكثر بساطة؟


Answers

بالنسبة لي هذا هو عمل.

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 أيام إلى الخلف. أعني أن أحصل على بيانات أسبوع واحد من التاريخ الحالي. هذا يجب أن يعمل.

ملاحظة: أنا أقوم بتحويل التاريخ الذي يأتي مع الثواني من الألف من 1000 ، ومقارنة بعد. اسمحوا لي أن أعرف إذا كنت بحاجة إلى أي وضوح.


قمت بنقل الإجابة من جلاوكو نيفيس إلى سويفت 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 حصلت على شيء مشابه لـ:

        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.


مثال على كيفية إعداد startDate و endDate للإجابة المذكورة أعلاه:

...

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

...

هنا كنت أبحث عن جميع الإدخالات في غضون شهر واحد. تجدر الإشارة إلى أن هذا المثال يوضح أيضًا كيفية البحث عن تاريخ "لا شيء".


امتداد 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()

لقد قضيت بعض الوقت في الآونة الأخيرة في محاولة حل هذه المشكلة نفسها وإضافة ما يلي إلى قائمة البدائل لإعداد تواريخ البدء والانتهاء (بما في ذلك الطريقة المحدّثة لنظام التشغيل 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]]

إضافة إلى الإجابة رافائيل (مفيد بشكل لا يصدق ، شكرا لك!) ، لنقلها إلى 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!])
}

هناك مثال في مستندات أبل ، القائمة 3: الحصول على مكونات التاريخ :

NSDate *today = [NSDate date];
NSCalendar *gregorian = [[NSCalendar alloc]
                         initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *weekdayComponents =
                    [gregorian components:(NSDayCalendarUnit | 
                                           NSWeekdayCalendarUnit) fromDate:today];
NSInteger day = [weekdayComponents day];
NSInteger weekday = [weekdayComponents weekday];

لاحظ أنه يجب عليك "أو" معا وحدات التقويم التي تريدها في استدعاء طريقة components .





objective-c core-data nsdate nspredicate nsfetchedresultscontroller