两个NSDates之间的天数

时间:2011-01-19 19:02:29

标签: ios objective-c cocoa-touch nsdate

我如何确定两个NSDate值之间的天数(考虑到时间)?

NSDate值的格式为[NSDate date]

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

exitDate = [NSDate date];

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

NSDate *now = [NSDate date];

现在我想实现以下内容:

-(int)numberOfDaysBetweenStartDate:exitDate andEndDate:now

16 个答案:

答案 0 :(得分:404)

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

+ (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];
}

修改

上面的神奇解决方案,下面的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
  }
}

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

上述解决方案也适用于当前时区以外的时区,非常适合显示全球各地信息的应用。

答案 1 :(得分: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;
}

E.g。如果你也想要几个月,那么你可以将'NSMonthCalendarUnit'作为一个单位包括。

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

答案 2 :(得分: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
    }
}

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
    }

}

原始解决方案

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

答案 3 :(得分: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);
}

答案 4 :(得分: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;
}

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

答案 5 :(得分:7)

NSDate *lastDate = [NSDate date];
NSDate *todaysDate = [NSDate date];
NSTimeInterval lastDiff = [lastDate timeIntervalSinceNow];
NSTimeInterval todaysDiff = [todaysDate timeIntervalSinceNow];
NSTimeInterval dateDiff = lastDiff - todaysDiff;

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

答案 6 :(得分:5)

@布赖恩

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

借用Brian的原始实现和一天的开始/结束,我在我的程序中使用以下内容: (NSDate beginning of day and end of day

- (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;
    }
}

答案 7 :(得分:3)

另一种方法:

NSDateFormatter* dayFmt = [[NSDateFormatter alloc] init];
[dayFmt setTimeZone:<whatever time zone you want>];
[dayFmt setDateFormat:@"g"];
NSInteger firstDay = [[dayFmt stringFromDate:firstDate] integerValue];    
NSInteger secondDay = [[dayFmt stringFromDate:secondDate] integerValue];
NSInteger difference = secondDay - firstDay;

优于timeIntervalSince...方案的优点是可以考虑时区,并且在一天的短时间或长时间内,间隔不会产生歧义。

比NSDateComponents方法更紧凑,更容易混淆。

答案 8 :(得分:3)

只需为访问此页面的人添加答案,试图在Swift中执行此操作。方法几乎相同。

private class func getDaysBetweenDates(startDate:NSDate, endDate:NSDate) -> NSInteger {

    var gregorian: NSCalendar = NSCalendar.currentCalendar();
    let flags = NSCalendarUnit.DayCalendarUnit
    let components = gregorian.components(flags, fromDate: startDate, toDate: endDate, options: nil)

    return components.day
}

在以下方法的讨论部分找到了here的答案:

components(_:fromDate:toDate:options:)

答案 9 :(得分:3)

这是在Swift中实现Brian的功能:

class func daysBetweenThisDate(fromDateTime:NSDate, andThisDate toDateTime:NSDate)->Int?{

    var fromDate:NSDate? = nil
    var toDate:NSDate? = nil

    let calendar = NSCalendar.currentCalendar()

    calendar.rangeOfUnit(NSCalendarUnit.DayCalendarUnit, startDate: &fromDate, interval: nil, forDate: fromDateTime)

    calendar.rangeOfUnit(NSCalendarUnit.DayCalendarUnit, startDate: &toDate, interval: nil, forDate: toDateTime)

    if let from = fromDate {

        if let to = toDate {

            let difference = calendar.components(NSCalendarUnit.DayCalendarUnit, fromDate: from, toDate: to, options: NSCalendarOptions.allZeros)

            return difference.day
        }
    }

    return nil
}

答案 10 :(得分:1)

您的意思是日历日或24小时吗?即星期二上午6点,星期三上午6点,或不到一天?

如果你的意思是前者,那就有点复杂,你将不得不通过NSCalendarNSDateComponent进行操纵,我不记得这些操作。

如果您的意思是后者,只需获取自参考日期以来的日期时间间隔,从另一个中减去一个,并除以24小时(24 * 60 * 60)以获得大致的间隔,不包括闰秒。

答案 11 :(得分:1)

为什么不呢:

int days = [date1 timeIntervalSinceDate:date2]/24/60/60;

答案 12 :(得分:1)

有一个,不确定它是你想要的,但它可以帮助你们中的一些人,(帮帮我!!)

我的目标是知道两个日期(差异小于24小时)之间是否有“过日”日+ 1:

我做了以下(我承认有点陈旧)

NSDate *startDate = ...
NSDate *endDate = ...

NSDate已经被另一个NSDateFormatter格式化了(这个只是为了这个目的:)

NSDateFormatter *dayFormater = [[NSDateFormatter alloc]init];
[dayFormater setDateFormat:@"dd"];

int startDateDay = [[dayFormater stringFromDate:startDate]intValue];

int endDateDay = [[dayFormater stringFromDate:dateOn]intValue];

if (endDateDay > startDateDay) {
    NSLog(@"day+1");
} else {
    NSLog(@"same day");
}

也许这样的东西已经存在,但没有找到它

答案 13 :(得分:0)

我找到的解决方案是:

+(NSInteger)getDaysDifferenceBetween:(NSDate *)dateA and:(NSDate *)dateB {

  if ([dateA isEqualToDate:dateB]) 
    return 0;

  NSCalendar * gregorian = 
        [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];



  NSDate * dateToRound = [dateA earlierDate:dateB];
  int flags = (NSYearCalendarUnit | NSMonthCalendarUnit |  NSDayCalendarUnit);
  NSDateComponents * dateComponents = 
         [gregorian components:flags fromDate:dateToRound];


  NSDate * roundedDate = [gregorian dateFromComponents:dateComponents];

  NSDate * otherDate = (dateToRound == dateA) ? dateB : dateA ;

  NSInteger diff = abs([roundedDate timeIntervalSinceDate:otherDate]);

  NSInteger daysDifference = floor(diff/(24 * 60 * 60));

  return daysDifference;
}

在这里,我有效地将第一个日期从一天开始,然后计算出Jonathan建议的差异......

答案 14 :(得分:0)

我已经发布了一个开源类/库来做这件事。

查看RelativeDateDescriptor,可用于获取时差,如下所示......

RelativeDateDescriptor *descriptor = [[RelativeDateDescriptor alloc] initWithPriorDateDescriptionFormat:@"%@ ago" postDateDescriptionFormat:@"in %@"];

// date1: 1st January 2000, 00:00:00
// date2: 6th January 2000, 00:00:00
[descriptor describeDate:date2 relativeTo:date1]; // Returns '5 days ago'
[descriptor describeDate:date1 relativeTo:date2]; // Returns 'in 5 days'

答案 15 :(得分:-1)

为什么要注意使用以下NSDate方法:

- (NSTimeInterval)timeIntervalSinceDate:(NSDate *)anotherDate

这将返回两个日期之间的秒数,您可以除以86,400来获取天数!!