【问题标题】:NSPredicate- For finding events that occur between a certain date rangeNSPredicate - 用于查找在特定日期范围内发生的事件
【发布时间】:2011-12-03 00:41:46
【问题描述】:

这比刚才复杂一点

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"startDate >= %@ AND endDate <= %@", startDay,endDay];

我正在构建一个日历应用程序,我需要从我的核心数据存储中提取特定日期发生的事件。但是,活动的开始/结束日期可能与我尝试显示的日期不同,例如

我的日期范围(开始 = 2011-12-02 00:00:00 到结束 = 2011-12-02 23:59:59)

一个事件(开始 = 2011-12-01 23:00:00 到结束 = 2011-12-02 05:00:00)

如何编写谓词来确定该事件是否在该日期范围内。请记住,事件可能在日期范围之前和之后开始。

谢谢!

【问题讨论】:

    标签: iphone core-data nsdate nspredicate


    【解决方案1】:

    这是一种构建谓词以检索给定日期发生的非重复事件(重复事件需要额外处理)的方法:

    - (NSPredicate *) predicateToRetrieveEventsForDate:(NSDate *)aDate {
    
        // start by retrieving day, weekday, month and year components for the given day
        NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
        NSDateComponents *todayComponents = [gregorian components:(NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit) fromDate:aDate];
        NSInteger theDay = [todayComponents day];
        NSInteger theMonth = [todayComponents month];
        NSInteger theYear = [todayComponents year];
    
        // now build a NSDate object for the input date using these components
        NSDateComponents *components = [[NSDateComponents alloc] init];
        [components setDay:theDay]; 
        [components setMonth:theMonth]; 
        [components setYear:theYear];
        NSDate *thisDate = [gregorian dateFromComponents:components];
        [components release];
    
        // build a NSDate object for aDate next day
        NSDateComponents *offsetComponents = [[NSDateComponents alloc] init];
        [offsetComponents setDay:1];
        NSDate *nextDate = [gregorian dateByAddingComponents:offsetComponents toDate:thisDate options:0];
        [offsetComponents release];
    
        [gregorian release];
    
    
        // build the predicate 
        NSPredicate *predicate = [NSPredicate predicateWithFormat: @"startDate < %@ && endDate > %@", nextDate, thisDate];
    
            return predicate;
    
    }
    

    谓词几乎等于@Tony 提出的那个,除了它不检查相等性。这就是为什么。假设您有一个从 12 月 8 日 23:00 开始到 12 月 9 日 00:00 结束的事件。如果您检查结束日期为 >= 而不是 > 的事件,您的应用将在 12 月 8 日和 9 日都报告该事件,这显然是错误的。尝试将此类事件添加到 iCal 和 Google 日历中,您会看到该事件仅出现在 12 月 8 日。实际上,您不应假设给定的一天在 23:59:59 结束(尽管这当然是true):您需要将午夜视为给定日期的最后一秒(关于事件的结束)。另外,请注意,这不会阻止从午夜开始的事件。

    【讨论】:

    • @massimo 你能更新你对重复事件的答案吗?
    • @JamalZafar,我对重复事件的谓词要复杂得多、冗长且不是独立的,因为它依赖于第三方库。此外,使用此添加更新答案确实没有意义,因为问题非常具体。
    【解决方案2】:

    你想要的是:

    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"startDate <= %@ AND endDate >= %@", endDay, startDay];
    

    换句话说,您正在消除在范围结束之后开始或在开始之前结束的事件,即与范围有空交集的事件。

    【讨论】:

      【解决方案3】:

      虽然建议的解决方案是正确的,但它也相当冗长。我在 Swift 3.0 中重新实现了它:

      import Foundation
      
      extension NSPredicate {
      
          static func filter(key: String, onDayRangeForDate date: Date, calendar: Calendar = Calendar(identifier: .gregorian)) -> NSPredicate {
      
              let dateComponents = calendar.dateComponents([.day, .month, .year], from: date)
      
              let startOfDay = calendar.date(from: dateComponents)!
      
              let offsetComponents = NSDateComponents()
              offsetComponents.day = 1
              let endOfDay = calendar.date(byAdding: offsetComponents as DateComponents, to: startOfDay)!
      
              return NSPredicate(format: "\(key) >= %@ && \(key) < %@",
                  startOfDay as NSDate, endOfDay as NSDate)
          }
      }
      

      【讨论】:

        【解决方案4】:

        Massimo Camaro 给出了一个很好的答案。我冒昧地将它移植到 Swift 并稍作修改以支持不同的列名。

        斯威夫特 2.0

        func predicateToRetrieveEventsForDate(aDate:NSDate, predicateColumn:String) -> NSPredicate {
            
            // start by retrieving day, weekday, month and year components for the given day
            let gregorian = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)
            let todayComponents = gregorian?.components([.Day, .Month, .Year], fromDate: aDate)
            let theDay = todayComponents?.day
            let theMonth = todayComponents?.month
            let theYear = todayComponents?.year
            
            // now build a NSDate object for the input date using these components
            let components = NSDateComponents()
            components.day = theDay!
            components.month = theMonth!
            components.year = theYear!
            let thisDate = gregorian?.dateFromComponents(components)
            
            // build a NSDate object for aDate next day
            let offsetComponents = NSDateComponents()
            offsetComponents.day = 1
            let nextDate = gregorian?.dateByAddingComponents(offsetComponents, toDate: thisDate!, options: NSCalendarOptions(rawValue: 0))
            
            // build the predicate
            let predicate = NSPredicate(format: "\(predicateColumn) >= %@ && \(predicateColumn) < %@", thisDate!, nextDate!)
            
            return predicate
        }
        

        【讨论】:

          猜你喜欢
          • 2015-10-07
          • 2015-04-09
          • 1970-01-01
          • 2023-03-20
          • 2022-07-04
          • 1970-01-01
          • 1970-01-01
          • 2014-03-29
          • 1970-01-01
          相关资源
          最近更新 更多