iOS:比较两个没有时间部分的NSDate对象

27

我想比较两个日期:date1 和 date2。

2011-06-06 12:59:48.994 Project[419:707] firstDate:2011-06-06 10:59:21 +0000
2011-06-06 12:59:49.004 Project[419:707] selectedData:2011-06-06 10:59:17 +0000

但是这些日期具有不同的时间,当我使用NSOrderedSame时它不能正常工作,我该如何解决?

我的代码:

NSDate *firstDate = [[appDelegate.project objectAtIndex:i]objectAtIndex:3];
NSDate *secondDate = [[appDelegate.project objectAtIndex:i]objectAtIndex:4];

NSCalendar *calendar = [NSCalendar currentCalendar];
NSInteger comps = (NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit);

NSDateComponents *date1Components = [calendar components:comps 
                                                            fromDate:firstDate];
NSDateComponents *date2Components = [calendar components:comps 
                                                            fromDate:secondDate];
NSDateComponents *date3Components = [calendar components:comps fromDate:appDelegate.selectedDate];

NSLog(@"firstDate:%@", [date1Components date]);
NSLog(@"secondDate:%@", [date2Components date]);
NSLog(@"selectedData:%@", [date3Components date]);

NSComparisonResult compareStart = [[date1Components date] compare: [date3Components date]]; 
NSComparisonResult compareEnd = [[date2Components date] compare: [date3Components date]]; 

if ((compareStart == NSOrderedAscending || compareStart == NSOrderedSame)
     && (compareEnd == NSOrderedDescending || compareEnd == NSOrderedSame))

{
    NSLog(@"inside");

然后我想在日期1≤选定日期≤日期2时将我的日期和输入进行比较。现在我明白了,因为我收到了一个警告:我应该添加这个“[date1Components date]”,它就可以工作了。问题在于,我在NSLog中有空值,为什么?


尝试使用NSLog(@"firstDate:%@", [calendar dateFromComponents:date1Components]);代替NSLog(@"firstDate:%@", [date1Components date]);。有任何改变吗? - vikingosegundo
现在是2011年6月5日22:00:00 +0000,为什么? - cyclingIsBetter
1
可能是一些时区/夏令时的魔法。 - vikingosegundo
一切都很正常:我写了[date1Components setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:(+0*3600)]];然后NSComparisonResult compareStart = [[calendar dateFromComponents:date1Components] compare:[calendar dateFromComponents:date3Components]];谢谢... - cyclingIsBetter
5个回答

53
NSCalendar *calendar = [NSCalendar currentCalendar];
NSInteger comps = (NSCalendarUnitDay | NSCalendarUnitMonth | NSCalendarUnitYear);

NSDateComponents *date1Components = [calendar components:comps 
                                                fromDate: date1];
NSDateComponents *date2Components = [calendar components:comps 
                                                fromDate: date2];

date1 = [calendar dateFromComponents:date1Components];
date2 = [calendar dateFromComponents:date2Components];

NSComparisonResult result = [date1 compare:date2];
if (result == NSOrderedAscending) {
} else if (result == NSOrderedDescending) {
}  else {
    //the same
}

有另一个实用的方法可以根据给定的日期创建代表给定单位开头的日期:[aCalendar rangeOfUnit:startDate:interval:forDate:]
为了说明这个方法是如何工作的,看一下这段代码,它可以轻松地为给定日期(此处为现在)创建开始于当天、当周、当月和当年的日期。

NSDate *now = [NSDate date];
NSDate *startOfToday = nil;
NSDate *startOfThisWeek = nil;
NSDate *startOfThisMonth = nil;
NSDate *startOfThisYear = nil;
[[NSCalendar currentCalendar] rangeOfUnit:NSDayCalendarUnit startDate:&startOfToday interval:NULL forDate:now];
[[NSCalendar currentCalendar] rangeOfUnit:NSWeekCalendarUnit startDate:&startOfThisWeek interval:NULL forDate:now];
[[NSCalendar currentCalendar] rangeOfUnit:NSMonthCalendarUnit startDate:&startOfThisMonth interval:NULL forDate:now];
[[NSCalendar currentCalendar] rangeOfUnit:NSYearCalendarUnit startDate:&startOfThisYear interval:NULL forDate:now];

NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateStyle:NSDateFormatterFullStyle];
[formatter setTimeStyle:NSDateFormatterFullStyle];

NSLog(@"%@", [formatter stringFromDate:now]);
NSLog(@"%@", [formatter stringFromDate:startOfToday]);
NSLog(@"%@", [formatter stringFromDate:startOfThisWeek]);
NSLog(@"%@", [formatter stringFromDate:startOfThisMonth]);
NSLog(@"%@", [formatter stringFromDate:startOfThisYear]);

结果:

Thursday, July 12, 2012, 4:36:07 PM Central European Summer Time 
Thursday, July 12, 2012, 12:00:00 AM Central European Summer Time 
Sunday, July 8, 2012, 12:00:00 AM Central European Summer Time 
Sunday, July 1, 2012, 12:00:00 AM Central European Summer Time 
Sunday, January 1, 2012, 12:00:00 AM Central European Standard Time
这使我们能够将第一段代码简写为:
[[NSCalendar currentCalendar] rangeOfUnit:NSDayCalendarUnit startDate:&date1 interval:NULL forDate:date1];
[[NSCalendar currentCalendar] rangeOfUnit:NSDayCalendarUnit startDate:&date2 interval:NULL forDate:date2];

NSComparisonResult result = [date1 compare:date2];
if (result == NSOrderedAscending) {
} else if (result == NSOrderedDescending) {
}  else {
    //the same
}

请注意,此代码中的date1date2将被覆盖。或者您可以像上面的代码示例中所示,传递对另一个NSDate指针的引用作为startDate参数,这样now就不会被改变。


我有一个警告:“NSDateComponents可能无法响应compare”。 - cyclingIsBetter
第一个实现是否覆盖了date1和date2?似乎它会将小时、分钟和秒设置为0,因为: date1 = [calendar dateFromComponents:date1Components]; date2 = [calendar dateFromComponents:date2Components]; - McGar
@McGar 是的,它将新对象分配给变量。 - vikingosegundo
截至2016年,“NSCalendar”拥有许多有用的日期比较方法。 - Paul Patterson
对我来说,即使在2020年,这仍然很有帮助。我发现在我的应用程序中使用[[NSCalendar currentCalendar] rangeOfUnit:NSDayCalendarUnit startDate:&startOfToday interval:NULL forDate:now];非常有用。 - Carl Smith

27

我使用了另一种方法,利用NSDateFormatter和字符串比较,这种方法不如NSDate compare 方法聪明,但写起来更快,并且足够灵活以进行各种比较:

我使用了NSDateFormatter和字符串比较的另一种方法,虽然不如NSDatecompare方法聪明,但是更易于编写,同时也可以灵活地进行多种比较:

NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:@"yyyy-MM-dd"];

if ([[dateFormat stringFromDate:date1] isEqualToString:[dateFormat stringFromDate:date2]])
{
    //It's the same day
}

10

好的,虽然原问题已经几年了,但值得一提的是,NSCalendar现在有许多方法可以使某些日期比较问题更加简单明了:

NSCalendar *currentCalendar = [NSCalendar currentCalendar];
Bool sameDay = [currentCalendar isDate:dateA inSameDayAsDate:dateB];

2

Swift版本,比较日期并忽略它们的时间。

let dateExam1:NSDate = NSDate.init(timeIntervalSinceNow: 300)
let dateExam2:NSDate = NSDate.init(timeIntervalSinceNow: 10000)

let currCalendar = NSCalendar.currentCalendar()

let dateCompanent1:NSDateComponents = currCalendar.components([.Year,.Month,.Day], fromDate: dateExam1)
let dateCompanent2:NSDateComponents = currCalendar.components([.Year,.Month,.Day], fromDate: dateExam2)

let date1WithoutTime:NSDate? = currCalendar .dateFromComponents(dateCompanent1)
let date2WithoutTime:NSDate? = currCalendar .dateFromComponents(dateCompanent2)
if (date1WithoutTime != nil) && (date2WithoutTime != nil)
{
    let dateCompResult:NSComparisonResult = date1WithoutTime!.compare(date2WithoutTime!)
    if (dateCompResult == NSComparisonResult.OrderedSame)
    {
        print("Same Dates")
    }
    else
    {
        print("Different Dates")
    }
}

0

更新 @LuAndre 的 Swift 5 回答

    let dateExam1 = Date(timeIntervalSinceNow: 300)
    let dateExam2 = Date(timeIntervalSinceNow: 10000)

    let currCalendar = Calendar.current

    let dateCompanent1 = currCalendar.dateComponents([.year,.month,.day], from: dateExam1)
    let dateCompanent2 = currCalendar.dateComponents([.year,.month,.day], from: dateExam2)


    if  let date1WithoutTime = currCalendar.date(from:dateCompanent1), let dateCompanent2 = currCalendar.date(from:dateCompanent2) {
            let dateCompResult = date1WithoutTime.compare(dateCompanent2)
            if (dateCompResult == ComparisonResult.orderedSame)
            {
                print("Same Dates")
            }
            else
            {
                print("Different Dates")
            }
        
    }

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