在Objective-C中计算两个日期之间的天数

59

可能是重复问题:
如何比较两个日期,返回相差的天数?

我有两个日期(以字符串形式"yyyy-mm-dd"表示),例如:

NSString *start = "2010-11-01";
NSString *end = "2010-12-01";

我想要实现:

- (int)numberOfDaysBetween:(NSString *)startDate and:(NSString *)endDate {

}

3
复制?https://dev59.com/FHE85IYBdhLWcg3w6oF0该问题询问如何比较两个日期并返回它们之间的天数差异。 - Mantar
那个问题没有回答我需要的内容。我只是想看看如何实现那个方法。 - CodeGuy
1
复制Meke提到的问题,你可以使用几乎相同的代码来解决,只需省略月份标志即可。 - Pascal
14
嘿,我猜你对 SO 的想法有些误解。大多数人来这里并不是为了实施你的方法,而是帮助你实施它们。你尝试过什么?阅读了哪些资料?具体在哪方面遇到了困难? - moritz
可能是重复的问题:两个NSDate之间的天数 - Sulthan
可能是两个NSDate对象之间的天数的重复问题。 - Cœur
8个回答

175
NSString *start = @"2010-09-01";
NSString *end = @"2010-12-01";

NSDateFormatter *f = [[NSDateFormatter alloc] init];
[f setDateFormat:@"yyyy-MM-dd"];
NSDate *startDate = [f dateFromString:start];
NSDate *endDate = [f dateFromString:end];

NSCalendar *gregorianCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
NSDateComponents *components = [gregorianCalendar components:NSCalendarUnitDay
                                                    fromDate:startDate
                                                      toDate:endDate
                                                     options:0];

components现在持有差异。

NSLog(@"%ld", [components day]);

@SpacePyro:算了吧,那只是我在回应别的地方说过的一个双关语。 - vikingosegundo
@RamyAlZuhouri 哈哈,抓住你了。我刚才还有点担心呢。;) - SpacePyro
我实际上认为这个不正确。尝试使用真正的NSDate组件,看看结果是否偏移了1天,因为某些组件没有超过24小时的差异。 - royherma
@vikingosegundo 我更关注最终的结果 - [components day],当比较来自同一时区的两个日期时会收到错误的结果。我会进一步研究它,但非常确定我的做法是正确的。 - royherma
@royherma:这是正确的行为,因为NSDate代表了一个精确的时间点。 - valeCocoa
显示剩余5条评论

23

有一份完整的日期和时间编程指南。这里是一个相关章节,可以给你提供一些提示。

这是其他问题中示例代码的来源。

试着根据这个写点东西,如果你有具体的问题再回来。

编辑

好的。这是我如何以最基本的形式编写代码。

首先,我会扩展NSDate。

头文件:

//  NSDate+ADNExtensions.h

#import <Cocoa/Cocoa.h>


@interface NSDate (ADNExtensions)

- (NSInteger)numberOfDaysUntil:(NSDate *)aDate;

@end

实现文件:
//  NSDate+ADNExtensions.m

#import "NSDate+ADNExtensions.h"


@implementation NSDate (ADNExtensions)


- (NSInteger)numberOfDaysUntil:(NSDate *)aDate {
    NSCalendar *gregorianCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];

    NSDateComponents *components = [gregorianCalendar components:NSDayCalendarUnit fromDate:self toDate:aDate options:0];

    return [components day];
}


@end

这是非常粗糙的代码。没有错误检查或验证第二个日期是否晚于第一个日期。

然后我会像这样使用它(在64位垃圾回收环境下运行):

NSDate *startDate = [NSDate dateWithString:@"2010-11-01 00:00:00 +0000"];
NSDate *endDate = [NSDate dateWithString:@"2010-11-02 00:00:00 +0000"];

NSInteger difference = [startDate numberOfDaysUntil:endDate];

NSLog(@"Diff = %ld", difference);

这真是遗憾,因为如果您发布您的代码和不正确的输出并获得更具体的帮助,您将学到更多。但是如果您只想成为一个复制粘贴程序员,请使用此代码,祝你好运。


你可不可以提供一下代码呢?说实话,我已经尝试了很多方法了。我试过使用 Gregarian 和 NSTimeInterval,能否直接实现这个方法? - CodeGuy
14
罗伯特,这不是一个“给我代码”的网站。如果你遇到问题,请提出一个关于此问题的问题,你将会得到帮助来解决它。人们不会只是为了解决你的问题而帮助你。你越早理解这一点,就越能从Stack Overflow社区中获得更好的答案。我认为Abizer在给你代码方面有点过于友善了。 ;) - Jasarien
顺便说一句,我不确定NSDate方法dateWithString是否存在,但至少很久以前它已被弃用,因此第二个答案更相关,现在必须使用NSDateFormatter - Artem
5
嘿,我最初是在寻找像这样的代码片段,现在却因此感到很内疚,哈哈! - GoldenJoe
你不需要扩展类来编写这样一个简单的辅助方法。 - sp_nz

8

Swift 4 实现

方法调用:

let numberOfDays = daysBetweenDates(startDate: fileCreatedDate,endDate: date)

方法实现:

 func daysBetweenDates(startDate: Date, endDate: Date) -> Int {
        let daysBetween = Calendar.current.dateComponents([.day], from: startDate, to: endDate)
        print(daysBetween.day!)
        return daysBetween.day!
  }

Objective C实现:

方法调用:

int numberOfDaysSinceFileCreation = [self daysBetweenDates: fileCreatedDate
                                                                   currentDate: today];

方法实现:

- (int) daysBetweenDates: (NSDate *)startDate currentDate: (NSDate *)endDate
{
    NSCalendar *calendar = [NSCalendar currentCalendar];
    NSDateComponents *dateComponent = [calendar components:NSCalendarUnitDay fromDate:startDate toDate:endDate options:0];

    int totalDays = (int)dateComponent.day;
    return totalDays;

}

6

这段代码在Swift 2中看起来运行良好:

func daysBetweenDate(startDate: NSDate, endDate: NSDate) -> Int
{
    let calendar = NSCalendar.currentCalendar()

    let components = calendar.components([.Day], fromDate: startDate, toDate: endDate, options: [])

    return components.day
}

3

Swift 3:

let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
let start = formatter.date(from: "2010-09-01")!
let end = formatter.date(from: "2010-12-01")!
let days = Calendar.current.dateComponents([.day], from: start, to: end).day!

3

ObjC代码:

NSDateComponents *dateComponent = [calender components:NSCalendarUnitDay fromDate:startDate toDate:endDate options:0];

结果:

int totalDays = (int)dateComponent.day;

2
上述例子只揭示了解决方案的一半,因为大部分解决方案在计算差异时只考虑日期值(例如:2010-11-01),但是在现实世界中,NSDate实例始终与时间一起出现,并对结果产生影响。
现在,让我们来谈谈用户定义了两个日期但没有为它们定义时间的接受的解决方案。
NSString *start = @"2010-09-01";
NSString *end = @"2010-09-02";

NSDateFormatter *f = [[NSDateFormatter alloc] init];
[f setDateFormat:@"yyyy-MM-dd"];
NSDate *startDate = [f dateFromString:start];
NSDate *endDate = [f dateFromString:end]; 

在这里,两个日期的时间相同,因为它们都没有提供时间,这意味着它不会影响差异计算。

startDate "2010-09-01 12:00 AM"
endDate "2010-09-02 12:00 AM"

结果将会是days = 1

现在让我们为两个日期添加具体时间:

startDate "2010-09-01 02:00 PM"
endDate "2010-09-02 02:00 AM"

添加一个特定的时间后,结果会改变。现在days = 0,尽管日期中定义的天数不同。 这是因为两个日期之间的时间差小于24小时。 只要满足以下条件,这种计算方法就可以正常工作:
  • 所需结果基于时间差异。
或者
  • 时间未定义为差异。
然而,如果你想根据日历日期变化计算天数差异,那么会有问题,因为在上面的例子中,即使日历日期发生了变化,但结果仍然为days = 0。这是因为时间差异小于24小时。
那么,我们如何基于日历日期变化计算天数差异呢?以下是Apple建议的做法:
@implementation NSCalendar (MySpecialCalculations)
- (NSInteger)daysWithinEraFromDate:(NSDate *)startDate toDate:(NSDate *)endDate {
     NSInteger startDay=[self ordinalityOfUnit:NSDayCalendarUnit inUnit: NSEraCalendarUnit forDate:startDate];
     NSInteger endDay=[self ordinalityOfUnit:NSDayCalendarUnit  inUnit: NSEraCalendarUnit forDate:endDate];
     return endDay - startDay;
}
@end 

更多详细信息可在此处查看

我对这个话题的两分观点,以代表剩下的一半画面。


0

enter image description here

 let date1Start = Calendar.current.startOfDay(for: date1)
    let date2Start = Calendar.current.startOfDay(for: date2)
    let dayDiff2 = Calendar.current.dateComponents([.day], from: date1Start, to: date2Start).day

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