【问题标题】:Count number of dates in an array which fall in a particular month计算数组中属于特定月份的日期数
【发布时间】:2013-07-24 15:48:12
【问题描述】:

我有一个 NSDate 对象数组,我想知道从现在到五个月前每个月有多少条目。

这可以使用NSPredicate吗?

【问题讨论】:

    标签: objective-c cocoa nsdate date-arithmetic


    【解决方案1】:

    与 Matthias 的方法有些不同,但我也没有看到使用 NSPredicate 的任何好方法,因为这里需要日期算术。

    这会从每个日期开始创建日期组件,并计算使用 NSCountedSet 的组件。 (您也许可以在计数集上使用谓词。)然后创建另一个 NSDateComponents 对象来描述您感兴趣的月份和年份,并使用 countForObject: 简单地查询该集合

    NSArray * dates = @[/* Your dates here */];
    
    NSCalendar * cal = [NSCalendar currentCalendar];
    
    /* Convert the dates into date components objects for month and year. */
    NSMutableArray * months = [NSMutableArray array];
    for( NSDate * date in dates ){
    
        NSDateComponents * month = [cal components:(NSMonthCalendarUnit|NSYearCalendarUnit)
                                          fromDate:date];
        [months addObject:month];
    }
    
    /* Count the unique components. */
    NSCountedSet * monthsCounts = [NSCountedSet setWithArray:months];
    
    /* Use a predicate here on the set? */
    
    /* A components object for month arithmetic. */
    NSDateComponents * monthDelta = [NSDateComponents new];
    
    /* Get month names for the current locale. */
    NSDateFormatter * formatter = [NSDateFormatter new];
    NSArray * monthNames = [formatter monthSymbols];
    
    for( NSInteger i = 0; i > -NUM_MONTHS; i-- ){
    
        /* Couting backwards from the current month, get a date components
         * object for each month and year.
         */
        [monthDelta setMonth:i];
        NSDateComponents * currMonth;
        currMonth = [cal components:(NSMonthCalendarUnit|NSYearCalendarUnit)
                           fromDate:[cal dateByAddingComponents:monthDelta
                                                         toDate:[NSDate date]
                                                        options:0]];
        /* Get the count from the counted set and display. */
        NSUInteger count = [monthsCounts countForObject:currMonth];
        NSLog(@"%lu dates in %@", count,
              [monthNames objectAtIndex:[currMonth month] - 1]);
    }
    

    【讨论】:

      【解决方案2】:

      您必须测试数组中的日期 6 次。

      首先:匹配 7 月 1 日或之后且 8 月 1 日之前的所有日期。
      第二:匹配 6 月 1 日或之后且 7 月 1 日之前的所有日期。
      第三:匹配 5 月 1 日或之后且 6 月 1 日之前的所有日期。
      等等

      在循环中创建两个日期。第一个日期是月初的午夜。第二个日期正好是 1 个月(!)之后。然后,您从数组中过滤掉第一个日期或第二个日期之前或之后的所有日期。在循环的下一次迭代中,您使 startDate 比前一个 startDate 早一个月。

      很多日期计算,但在 NSDateComponents 的帮助下,这没什么大不了的。

      由于我不确定如何在数组中使用带有 NSDates 的 NSPredicate,所以我使用了另一种方法,但这基本上是它的工作原理:

      NSDateComponents *oneMonthOffset = [[NSDateComponents alloc] init];
      oneMonthOffset.month = 1;
      
      NSDateComponents *thisMonth = [calendar components:NSYearCalendarUnit|NSMonthCalendarUnit fromDate:[NSDate date]];
      thisMonth.day = 1;
      NSDate *startOfCurrentMonth = [calendar dateFromComponents:thisMonth];
      
      for (NSInteger offset = 0; offset > -5; offset--) {
          NSDateComponents *startDateOffset = [[NSDateComponents alloc] init];
          startDateOffset.month = offset;
          NSDate *startDate = [calendar dateByAddingComponents:startDateOffset toDate:startOfCurrentMonth options:0];
          NSDate *endDate = [calendar dateByAddingComponents:oneMonthOffset toDate:startDate options:0];
          NSIndexSet *matchingIndexes = [array indexesOfObjectsPassingTest:^BOOL(NSDate *date, NSUInteger idx, BOOL *stop) {
              if ([date compare:startDate] != NSOrderedAscending && [date compare:endDate] == NSOrderedAscending) {
                  // date is not before startDate (i.e. is on startDate or later than startDate) and date is before endDate
                  return YES;
              }
              return NO;
          }];
          NSLog(@"%d dates after %@ and before %@", [matchingIndexes count], [startDate descriptionWithLocale:[NSLocale currentLocale]], [endDate descriptionWithLocale:[NSLocale currentLocale]]);
      }
      

      如果您的日期数组非常大,您可能希望先对其进行排序,然后只扫描相关范围。此代码当前测试数组中的所有 NSDates。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-05-17
        • 2021-11-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-08-30
        相关资源
        最近更新 更多