在特定时区中获取两个NSDate日期之间的天数

8

我找到了计算两个日期之间天数差的代码在这里
我写了一个方法:

-(NSInteger)daysWithinEraFromDate:(NSDate *) startDate toDate:(NSDate *) endDate
{
    NSCalendar *gregorian = [[NSCalendar alloc]
                             initWithCalendarIdentifier:NSGregorianCalendar];
    NSInteger startDay=[gregorian ordinalityOfUnit:NSDayCalendarUnit
                                            inUnit: NSEraCalendarUnit forDate:startDate];
    NSInteger endDay=[gregorian ordinalityOfUnit:NSDayCalendarUnit
                                          inUnit: NSEraCalendarUnit forDate:endDate];
    return endDay-startDay;
}

这种方法存在一个问题:它无法考虑时区。即使我添加了这样一行代码:

[gregorian setTimeZone:[NSTimeZone localTimeZone]];

我的测试代码像这样:

    NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
    [dateFormat setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
    NSString *strDate = @"2012-09-03 23:00:00";
    NSDate *dateStart = [dateFormat dateFromString:strDate];
    strDate = @"2012-09-04 01:00:00";
    NSDate *dateEnd = [dateFormat dateFromString:strDate];
    NSLog(@"Days difference between %@ and %@  is:  %d days",[dateFormat stringFromDate:dateStart],[dateFormat stringFromDate:dateEnd],[self daysWithinEraFromDate:dateStart toDate:dateEnd]);

结果是:

2012-09-03 23:00:00和2012-09-04 01:00:00之间的日差为:0天

我想通过两个日期之间午夜的数量来得到1天的结果。我的时区是GMT +8。但是这个计算是基于GMT的,所以我得到了错误的天数。有没有办法解决这个问题?谢谢。


Scott Lemmon 的方法可以解决我的问题。我将代码重写为:

-(NSInteger)daysWithinEraFromDate:(NSDate *) startDate toDate:(NSDate *) endDate
{
    NSCalendar *gregorian = [[NSCalendar alloc]
                             initWithCalendarIdentifier:NSGregorianCalendar];
    [gregorian setTimeZone:[NSTimeZone localTimeZone]];
    NSDate *newDate1 = [startDate dateByAddingTimeInterval:[[NSTimeZone localTimeZone] secondsFromGMT]];
    NSDate *newDate2 = [endDate dateByAddingTimeInterval:[[NSTimeZone localTimeZone] secondsFromGMT]];

    NSInteger startDay=[gregorian ordinalityOfUnit:NSDayCalendarUnit
                                            inUnit: NSEraCalendarUnit forDate:newDate1];
    NSInteger endDay=[gregorian ordinalityOfUnit:NSDayCalendarUnit
                                          inUnit: NSEraCalendarUnit forDate:newDate2];
    return endDay-startDay;
}
2个回答

5
如果时区偏移量不起作用,那么就手动添加或减去它如何?在您的情况下,NSDate *newDate = [oldDate dateByAddingTimeInterval:(-8 * 60 * 60)]; 减去您的+8小时。
或者,如果您想要自动查找GMT偏移量,那么它将简单地为 NSDate *newDate = [oldDate dateByAddingTimeInterval:(-[[NSTimeZone localTimeZone] secondsFromGMT]) 另一个想法:也许更容易的解决方案是完全忽略时间信息。只需将其设置为两个日期的同一任意数字,然后只要这些日期来自同一时区,无论GMT偏移量如何,您都将始终得到它们之间正确数量的午夜。

嗨,谢谢你的回答。我刚刚考虑过忽略时间信息。我已经在我的代码中实现了这一点。但是你的第一个解决方案真是太棒了!我认为这是解决这个问题更精确的方法。我已经在我的代码中尝试了它,我会展示给你看的。 - Vigor

3
你需要的是NSDate方法timeIntervalSinceDate:,将结果与0比较,如果大于0但小于86400(即一天中的秒数),则代表已经过去了一天。否则,将结果除以86400,就可以得到天数。
根据你目前的代码,两天之间只有2个小时,这就是为什么你看到的结果是0而不是1。
编辑 - 为了确定日期是否已经过了午夜,让我们试试我刚刚想到的这个函数:
- (NSDate *) getMidnightDateFromDate: (NSDate *) originalDate
{
    NSDateComponents *components = [[NSCalendar currentCalendar] components:NSIntegerMax fromDate:originalDate];
    [components setHour:0];
    [components setMinute:0];
    [components setSecond:0];
    NSDate *midnight = [[NSCalendar currentCalendar] dateFromComponents:components];
    return(midnight);
}

- (BOOL) howManyDaysDifferenceBetween: startDate and: endDate
{
    NSDate * firstMidnight = [self getMidnightDateFromDate: startDate];
    NSDate * secondMidnight = [self getMidnightDateFromDate: endDate];
    NSTimeInterval timeBetween = [firstMidnight timeIntervalSinceDate: secondMidnight];

    NSInteger numberOfDays = (timeBetween / 86400);

    return(numberOfDays);
}

我基于Dave Delong在这个问题上的答案。不能保证我的代码能够正常运行(我没有测试过),但是我认为这个概念是可行的。


谢谢您的回答。我想通过两个NSDate实例之间午夜的数量来确定它们是否在不同的日期。根据您的方法,我仍然会得到0天。但是,2012-09-03和2012-09-04在不同的日期,即使时间间隔只有2小时。如果我将第二个日期更改为2012-09-04 08:00:00,我将在我的方法下得到1天的结果。我认为这是由于时区的原因。 - Vigor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接