两个NSDates之间的天数

Cod*_*Guy 149 cocoa-touch objective-c nsdate ios

我怎样才能确定两个NSDate值之间的天数(考虑到时间)?

NSDate值是任何形式的[NSDate date]需要.

具体来说,当用户在我的iPhone应用程序中进入非活动状态时,我存储以下值:

exitDate = [NSDate date];
Run Code Online (Sandbox Code Playgroud)

当他们打开应用程序备份时,我得到当前时间:

NSDate *now = [NSDate date];
Run Code Online (Sandbox Code Playgroud)

现在我想实现以下内容:

-(int)numberOfDaysBetweenStartDate:exitDate andEndDate:now
Run Code Online (Sandbox Code Playgroud)

Bri*_*ian 405

这是我用来确定两个日期之间的日历天数的实现:

+ (NSInteger)daysBetweenDate:(NSDate*)fromDateTime andDate:(NSDate*)toDateTime
{
    NSDate *fromDate;
    NSDate *toDate;

    NSCalendar *calendar = [NSCalendar currentCalendar];

    [calendar rangeOfUnit:NSCalendarUnitDay startDate:&fromDate
        interval:NULL forDate:fromDateTime];
    [calendar rangeOfUnit:NSCalendarUnitDay startDate:&toDate
        interval:NULL forDate:toDateTime];

    NSDateComponents *difference = [calendar components:NSCalendarUnitDay
        fromDate:fromDate toDate:toDate options:0];

    return [difference day];
}
Run Code Online (Sandbox Code Playgroud)

编辑:

上面的神奇解决方案,这里的Swift版本作为扩展NSDate:

extension NSDate {
  func numberOfDaysUntilDateTime(toDateTime: NSDate, inTimeZone timeZone: NSTimeZone? = nil) -> Int {
    let calendar = NSCalendar.currentCalendar()
    if let timeZone = timeZone {
      calendar.timeZone = timeZone
    }

    var fromDate: NSDate?, toDate: NSDate?

    calendar.rangeOfUnit(.Day, startDate: &fromDate, interval: nil, forDate: self)
    calendar.rangeOfUnit(.Day, startDate: &toDate, interval: nil, forDate: toDateTime)

    let difference = calendar.components(.Day, fromDate: fromDate!, toDate: toDate!, options: [])
    return difference.day
  }
}
Run Code Online (Sandbox Code Playgroud)

根据您的使用情况,您可能想要移除一些力量展开.

上述解决方案也适用于当前时区以外的时区,非常适合显示世界各地信息的应用程序.

  • @karim:举一个例子来澄清一下João所说的:如果fromDateTime = 2月1日晚上11:00和toDateTime = 2月2日凌晨01:00结果应为1(即使它只有2个小时,但它是另一个日期).如果没有剥离日期的时间部分(通过调用`rangeOfUnit:...`来完成),结果将为0(因为2h <1天). (38认同)
  • @karim如果您只使用该功能,差异将不会出现在"日历日"中. (12认同)
  • 为什么不使用,NSDateComponents*差异= [日历组件:NSDayCalendarUnit fromDate:fromDate toDate:toDate options:0]; 只要. (7认同)
  • 我添加了"[calendar setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];" 在"rangeOfUnit"方法之前,现在它对我来说正常工作(运行环境的本地时区设置为+4:30 GMT)! (3认同)
  • 很好的解决方案! (2认同)

小智 118

这是我发现的最佳解决方案.似乎利用Apple批准的方法确定NSDates之间的任何数量的单位.

- (int)daysBetween:(NSDate *)dt1 and:(NSDate *)dt2 {
    NSUInteger unitFlags = NSDayCalendarUnit;
    NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; 
    NSDateComponents *components = [calendar components:unitFlags fromDate:dt1 toDate:dt2 options:0];
    return [components day]+1;
}
Run Code Online (Sandbox Code Playgroud)

例如,如果您还想要几个月,那么您可以将'NSMonthCalendarUnit'作为unitFlag包含在内.

为了归功于原始博客,我在这里找到了这个信息(尽管我上面已经修复了一个小错误):http: //cocoamatic.blogspot.com/2010/09/nsdate-number-of-days-between-两dates.html?showComment = 1306198273659#c6501446329564880344

  • 这是Apple文档中的方法.这应该被接受 (8认同)
  • 它工作不正确.对于相同的日期和1天差异的日期,它给出相同的结果.在这种情况下,components.day为0. (5认同)
  • `return [components day] +1;`应该'返回ABS([components day])+ 1;`以防止错误的日计数为负值 (3认同)
  • 我想要一个方法,它返回过去的toDate的负值和将来的toDate的正值,如果toDate与fromDate的日期相同则为0.如果我删除最后一行代码中的+1,这个方法对我来说就是这样. (2认同)

Emi*_*ral 23

Swift 3.0更新

extension Date {

    func differenceInDaysWithDate(date: Date) -> Int {
        let calendar = Calendar.current

        let date1 = calendar.startOfDay(for: self)
        let date2 = calendar.startOfDay(for: date)

        let components = calendar.dateComponents([.day], from: date1, to: date2)
        return components.day ?? 0
    }
}
Run Code Online (Sandbox Code Playgroud)

Swift 2.0更新

extension NSDate {

    func differenceInDaysWithDate(date: NSDate) -> Int {
        let calendar: NSCalendar = NSCalendar.currentCalendar()

        let date1 = calendar.startOfDayForDate(self)
        let date2 = calendar.startOfDayForDate(date)

        let components = calendar.components(.Day, fromDate: date1, toDate: date2, options: [])
        return components.day
    }

}
Run Code Online (Sandbox Code Playgroud)

原始方案

Swift的另一个解决方案.

如果您的目的是获取两个日期之间的确切日期数,您可以解决此问题,如下所示:

// Assuming that firstDate and secondDate are defined
// ...

var calendar: NSCalendar = NSCalendar.currentCalendar()

// Replace the hour (time) of both dates with 00:00
let date1 = calendar.startOfDayForDate(firstDate)
let date2 = calendar.startOfDayForDate(secondDate)

let flags = NSCalendarUnit.DayCalendarUnit
let components = calendar.components(flags, fromDate: date1, toDate: date2, options: nil)

components.day  // This will return the number of day(s) between dates
Run Code Online (Sandbox Code Playgroud)


jki*_*jki 13

我将它用作NSDate类的类别方法

// returns number of days (absolute value) from another date (as number of midnights beween these dates)
- (int)daysFromDate:(NSDate *)pDate {
    NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
    NSInteger startDay=[calendar ordinalityOfUnit:NSCalendarUnitDay
                                           inUnit:NSCalendarUnitEra
                                          forDate:[NSDate date]];
    NSInteger endDay=[calendar ordinalityOfUnit:NSCalendarUnitDay
                                         inUnit:NSCalendarUnitEra
                                        forDate:pDate];
    return abs(endDay-startDay);
}
Run Code Online (Sandbox Code Playgroud)

  • 这是最好和正确工作的解决方案. (2认同)

ork*_*den 8

我需要两个日期之间的天数,包括开始日期.例如,14-2-2012和16-2-2012之间的天数将产生3的结果.

+ (NSInteger)daysBetween:(NSDate *)dt1 and:(NSDate *)dt2 {
        NSUInteger unitFlags = NSDayCalendarUnit;
        NSCalendar* calendar = [NSCalendar currentCalendar];
        NSDateComponents *components = [calendar components:unitFlags fromDate:dt1 toDate:dt2 options:0];
        NSInteger daysBetween = abs([components day]);
    return daysBetween+1;
}
Run Code Online (Sandbox Code Playgroud)

请注意,提供日期的顺序无关紧要.它将始终返回正数.


小智 7

NSDate *lastDate = [NSDate date];
NSDate *todaysDate = [NSDate date];
NSTimeInterval lastDiff = [lastDate timeIntervalSinceNow];
NSTimeInterval todaysDiff = [todaysDate timeIntervalSinceNow];
NSTimeInterval dateDiff = lastDiff - todaysDiff;
Run Code Online (Sandbox Code Playgroud)

dateDiff将是两个日期之间的秒数.只需除以一天中的秒数即可.

  • 你永远不应该在应用程序中进行这种数学运算.这将随着时区转换(可能导致23或25小时的天数),闰秒(在几年结束时应用而不是其他时间)以及任何数量的其他日历复杂性而下降. (71认同)
  • NSCalendar具有执行日期数学的方法.WWDC 2011会议视频包括安全执行日期数学的会话. (8认同)
  • 错误的答案.请参阅下面的Biosopher答案 (7认同)
  • 这远远不是错误,甚至没有滑稽的Biosopher的回答是正确的. (6认同)
  • 为了清楚起见,你将除以60*60*24,然后你需要决定一个部分日算是否为一天,是5.9等于6天?找出适合您应用的舍入方案. (2认同)

小智 5

@布赖恩

布莱恩的答案很好,只计算24小时的天数差异,但不计算日历日差异.例如,12月24日23:59离圣诞节只有1分钟的距离,目的是许多申请仍被视为一天.Brian的daysBetween函数将返回0.

借用Brian的原始实现和一天的开始/结束,我在我的程序中使用以下内容:(NSDate从一天开始到一天结束)

- (NSDate *)beginningOfDay:(NSDate *)date
{
    NSCalendar *cal = [NSCalendar currentCalendar];
    NSDateComponents *components = [cal components:( NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit ) fromDate:date];
    [components setHour:0];
    [components setMinute:0];
    [components setSecond:0];
    return [cal dateFromComponents:components];
}

- (NSDate *)endOfDay:(NSDate *)date
{
    NSCalendar *cal = [NSCalendar currentCalendar];
    NSDateComponents *components = [cal components:( NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit ) fromDate:date];
    [components setHour:23];
    [components setMinute:59];
    [components setSecond:59];
    return [cal dateFromComponents:components];
}

- (int)daysBetween:(NSDate *)date1 and:(NSDate *)date2 {
    NSDate *beginningOfDate1 = [self beginningOfDay:date1];
    NSDate *endOfDate1 = [self endOfDay:date1];
    NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
    NSDateComponents *beginningDayDiff = [calendar components:NSDayCalendarUnit fromDate:beginningOfDate1 toDate:date2 options:0];
    NSDateComponents *endDayDiff = [calendar components:NSDayCalendarUnit fromDate:endOfDate1 toDate:date2 options:0];
    if (beginningDayDiff.day > 0)
        return beginningDayDiff.day;
    else if (endDayDiff.day < 0)
        return endDayDiff.day;
    else {
        return 0;
    }
}
Run Code Online (Sandbox Code Playgroud)