Objective c 根据过去的NSDate和重复间隔,计算从现在开始的下一个事件

Objective c 根据过去的NSDate和重复间隔,计算从现在开始的下一个事件,objective-c,cocoa,cocoa-touch,nsdate,date-arithmetic,Objective C,Cocoa,Cocoa Touch,Nsdate,Date Arithmetic,如何通过重复某个时间间隔,从过去的某个日期计算比现在晚的第一个日期?例如: // Date in the past NSDate *pastDate = [NSDate my_dateWithString:@"11/09/2001"]; // Time interval NSTimeInterval repeatInterval = 14 * 24 * 60 * 60; // 2 weeks // Current date NSDate *now = [NSDate date]; // 23

如何通过重复某个时间间隔,从过去的某个日期计算比现在晚的第一个日期?例如:

// Date in the past
NSDate *pastDate = [NSDate my_dateWithString:@"11/09/2001"];

// Time interval
NSTimeInterval repeatInterval = 14 * 24 * 60 * 60; // 2 weeks

// Current date
NSDate *now = [NSDate date]; // 23/07/2015

// Start calculating next date ->
NSDate *nextDate = /* interval added to past date */
// Is result later than now?
// No? Calculate again
// Abracadabra

NSLog(@"nexDate = %@",nextDate); // 28/07/2015
我不想使用迭代。我关心的是计算一个案例,比如过去一年的开始日期和一天的重复间隔

这是我的解决方案,但它有迭代

  NSDateComponents *twoWeeksDateComponents = [NSDateComponents new];
  twoWeeksDateComponents.weekOfMonth = 2;

  NSDate *date = self.picker.date;
  NSCalendar *calendar = [NSCalendar currentCalendar];

  NSDate *now = [NSDate date];
  NSDate *nextDate = date;
  NSComparisonResult result = [nextDate compare:now];
  while (result == NSOrderedAscending) {
    nextDate = [calendar dateByAddingComponents:kTwoWeeksDateComponents
                                         toDate:nextDate
                                        options:NSCalendarMatchNextTime];
    result = [nextDate compare:now];
  }
  NSLog(@"nexDate = %@",nextDate); // 28/07/2015

您确实可以不用迭代就完成这项工作,而只需使用一点算术。您正在寻找某个因子f严格大于另一个值n的最近倍数。日历计算要复杂一点,但仍然只是算术(当然,所有繁重的工作都由NSCalendar来完成,例如闰年)


从用户处获取您喜欢的重复间隔,并构造一个表示该间隔的
NSDateComponents

NSCalendarUnit repeatUnit = NSCalendarUnitWeekOfYear;
NSUInteger repeatInterval = 2;

NSDateComponents * repeatComps = [NSDateComponents new];
[repeatComps setValue:repeatInterval forComponent:repeatUnit];
给定重复单位,查找两个日期之间发生的单位数量,作为另一个日期组件对象:

NSCalendar * cal = [NSCalendar currentCalendar];
NSDateComponents * deltaComps = [cal components:repeatUnit
                                       fromDate:pastDate
                                         toDate:now
                                        options:0];
NSInteger deltaVal = [deltaComps valueForComponent:repeatUnit];
现在是算术位。将增量四舍五入到重复间隔的最近倍数。然后加上舍入值(使用适当的单位)将产生一个等于或早于现在的日期

现在,作为Jawbox,对于
NSCalendarUnitMonth
repeatUnit
,如果使用该值计算日期,然后再添加一个重复间隔(与此答案的原始版本一样),则会得到意外的结果。相反,立即在重复次数上增加一次;然后,日历将正确处理月份增量

NSInteger repeatsJustPastNow = 1 + deltaVal - (deltaVal % repeatInterval);

NSDateComponents * toNowComps = [NSDateComponents new];
[toNowComps setValue:repeatsJustPastNow
        forComponent:repeatUnit];

NSDate * nextDate;
nextDate = [cal dateByAddingComponents:toNowComps
                                toDate:pastDate
                               options:0];

Jawboxer的。

您确实可以不用迭代就完成这项工作,而只需使用一点算术。您正在寻找某个因子f严格大于另一个值n的最近倍数。日历计算要复杂一点,但仍然只是算术(当然,所有繁重的工作都由NSCalendar来完成,例如闰年)


从用户处获取您喜欢的重复间隔,并构造一个表示该间隔的
NSDateComponents

NSCalendarUnit repeatUnit = NSCalendarUnitWeekOfYear;
NSUInteger repeatInterval = 2;

NSDateComponents * repeatComps = [NSDateComponents new];
[repeatComps setValue:repeatInterval forComponent:repeatUnit];
给定重复单位,查找两个日期之间发生的单位数量,作为另一个日期组件对象:

NSCalendar * cal = [NSCalendar currentCalendar];
NSDateComponents * deltaComps = [cal components:repeatUnit
                                       fromDate:pastDate
                                         toDate:now
                                        options:0];
NSInteger deltaVal = [deltaComps valueForComponent:repeatUnit];
现在是算术位。将增量四舍五入到重复间隔的最近倍数。然后加上舍入值(使用适当的单位)将产生一个等于或早于现在的日期

现在,作为Jawbox,对于
NSCalendarUnitMonth
repeatUnit
,如果使用该值计算日期,然后再添加一个重复间隔(与此答案的原始版本一样),则会得到意外的结果。相反,立即在重复次数上增加一次;然后,日历将正确处理月份增量

NSInteger repeatsJustPastNow = 1 + deltaVal - (deltaVal % repeatInterval);

NSDateComponents * toNowComps = [NSDateComponents new];
[toNowComps setValue:repeatsJustPastNow
        forComponent:repeatUnit];

NSDate * nextDate;
nextDate = [cal dateByAddingComponents:toNowComps
                                toDate:pastDate
                               options:0];

Jawboxer's.

编辑:正如Josh指出的,这并不能解释闰年。因此,这是一个很好的实现示例,它似乎可以在短期测试中工作,但存在漏洞。它也会在日志中关闭几个小时,因为
dateFromString:
将补偿时区,而日志将记录为GMT



编辑:正如乔希指出的,这并不能解释闰年。因此,这是一个很好的实现示例,它似乎可以在短期测试中工作,但存在漏洞。它也会在日志中关闭几个小时,因为
dateFromString:
将补偿时区,而日志将记录为GMT



我很早就提出了另一个解决方案

  NSDate *date = ...;

  static NSTimeInterval k2WeeksInterval = 14 * 24 * 60 * 60.0;

  NSTimeInterval timeInterval = -date.timeIntervalSinceNow;

  double repeats = ceil(timeInterval / k2WeeksInterval);

  NSCalendar *calendar = [NSCalendar currentCalendar];

  NSDateComponents *components = [NSDateComponents new];
  components.weekOfYear = repeats * 2;

  NSDate *nextDate = [calendar dateByAddingComponents:components
                                               toDate:date
                                              options:NSCalendarMatchNextTime];

我很早就提出了另一个解决方案

  NSDate *date = ...;

  static NSTimeInterval k2WeeksInterval = 14 * 24 * 60 * 60.0;

  NSTimeInterval timeInterval = -date.timeIntervalSinceNow;

  double repeats = ceil(timeInterval / k2WeeksInterval);

  NSCalendar *calendar = [NSCalendar currentCalendar];

  NSDateComponents *components = [NSDateComponents new];
  components.weekOfYear = repeats * 2;

  NSDate *nextDate = [calendar dateByAddingComponents:components
                                               toDate:date
                                              options:NSCalendarMatchNextTime];

最后在看到你的之前发布了我的。。。使用我的可以吗(它似乎总是返回正确的日期,保留时间,并以疯狂的间隔工作,如1周+1天+3小时+4分钟)?或者我应该检查日期组件,而不仅仅是计算时间间隔?你的版本不能很容易地处理月或年的重复单位。例如,尝试使用2015-03-01的开始日期和1年的间隔
NSCalendar
说明了2016年的闰日。
NSDateComponents
也可以处理复合间隔。啊,我现在明白了。谢谢。:)这很好,但我想我发现了一个缺陷。假设
pastDate
是2015年1月31日,您的
repeatUnit
是每月一次,而
now
是2015年3月15日-结果是2015年3月28日(而不是3月31日的预期结果)。像我在中所做的那样,将1添加到
repeatsToNow
并从中获取
nextDate
是否更好?我的修改版本确实给出了预期的3月31日的结果,但也许你这样做还有其他原因?在看到你的之前,我发布了我的。。。使用我的可以吗(它似乎总是返回正确的日期,保留时间,并以疯狂的间隔工作,如1周+1天+3小时+4分钟)?或者我应该检查日期组件,而不仅仅是计算时间间隔?你的版本不能很容易地处理月或年的重复单位。例如,尝试使用2015-03-01的开始日期和1年的间隔
NSCalendar
说明了2016年的闰日。
NSDateComponents
也可以处理复合间隔。啊,我现在明白了。谢谢。:)这很好,但我想我发现了一个缺陷。假设
pastDate
是2015年1月31日,您的
repeatUnit
是每月一次,而
now
是2015年3月15日-结果是2015年3月28日(而不是3月31日的预期结果)。像我在中所做的那样,将1添加到
repeatsToNow
并从中获取
nextDate
是否更好?我修改过的版本确实给出了预期的3月31日结果,但可能您这样做还有其他原因吗?这不能很好地处理月份或年份。@Josh Caswell,我想这会很好地工作,因为NSTimeInterval是一个双倍值,计算重复次数可以得到真实结果,但是关于闰年N的计算