题 比较两个NSDates并忽略时间组件


比较两个NSDates的最有效/推荐的方法是什么?我希望能够看到两个日期是否在同一天,无论时间如何,并且已经开始编写一些在NSDate类中使用timeIntervalSinceDate:方法的代码,并获取此值的整数除以秒数一天内。这似乎很长,我觉得我错过了一些明显的东西。

我试图解决的代码是:

if (!([key compare:todaysDate] == NSOrderedDescending))
{
    todaysDateSection = [eventSectionsArray count] - 1;
}

其中key和todaysDate是NSDate对象,todaysDate正在创建使用:

NSDate *todaysDate = [[NSDate alloc] init];

问候

戴夫


71
2017-12-06 09:36


起源


美丽的问题+1 - abbood


答案:


在进行比较之前,您将日期中的时间设置为00:00:00:

unsigned int flags = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay;
NSCalendar* calendar = [NSCalendar currentCalendar];

NSDateComponents* components = [calendar components:flags fromDate:date];

NSDate* dateOnly = [calendar dateFromComponents:components];

// ... necessary cleanup

然后,您可以比较日期值。见 参考文档中的概述


72
2017-12-06 09:52



感谢格雷戈里的快速反应,这真的很有帮助。我想我的下一个问题是,因为这是紧密循环的一部分,你认为使用timeIntervalSinceDate:方法和一些整数算法更有效,而不是创建更多的对象,进行必要的计算然后清理?再次感谢你的帮助,戴夫 - Magic Bullet Dave
我的建议是:正确实施是黄金;然后简介。如果这个特定的循环确实是一个瓶颈,那么优化 - Gregory Pakosz
由于您只提取年,月和日单位,小时,分钟和秒自动设置为0.因此,您不必自己明确地执行此操作。 - Dave DeLong
我试过用这个方法没用。我的时间总是不等于00:00? - iosMentalist
我必须使用[calendar setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@“GMT”]]配置日历对象;否则比较无法正常工作。 - Vladimír Slavík


我很惊讶没有其他答案有这个选项来获取对象的“开始日期”日期:

[[NSCalendar currentCalendar] rangeOfUnit:NSCalendarUnitDay startDate:&date1 interval:NULL forDate:date1];
[[NSCalendar currentCalendar] rangeOfUnit:NSCalendarUnitDay startDate:&date2 interval:NULL forDate:date2];

哪套 date1 和 date2 到他们各自的日子开始。如果他们是平等的,他们就在同一天。

或者这个选项:

NSUInteger day1 = [[NSCalendar currentCalendar] ordinalityOfUnit:NSDayCalendarUnit inUnit: forDate:date1];
NSUInteger day2 = [[NSCalendar currentCalendar] ordinalityOfUnit:NSCalendarUnitDay inUnit:NSCalendarUnitEra forDate:date2];

哪套 day1 和 day2 有些可以比较的任意值。如果他们是平等的,他们就在同一天。


83
2017-12-07 02:07



+1我之前从未注意过这些方法!很酷。 - Dave DeLong
小FYI, NSDayCalendarUnit 已被弃用并被替换为 NSCalendarUnitDay - Dwayne Forde


有一个新的方法被引入到NSCalendar与iOS 8,使这更容易。

- (NSComparisonResult)compareDate:(NSDate *)date1 toDate:(NSDate *)date2 toUnitGranularity:(NSCalendarUnit)unit NS_AVAILABLE(10_9, 8_0);

您将粒度设置为重要的单位。这忽略了所有其他单位并限制与所选单位的比较。


19
2018-02-14 18:32



这是一个非常酷的方法。 (已投票)可惜它仅在iOS 8中可用。我想如果您仍然需要支持iOS <8,您可以使用我为iOS <8列出的代码编写方法,并且 compareDate:toDate:toUnitGranularity: 在iOS> = 8。然后,一旦您放弃对操作系统版本<8的支持,您可以将实现折叠为仅调用 compareDate:toDate:toUnitGranularity:。 - Duncan C
当然最终的方法是 differenceBetweenDate:andDate:usingUnit:,这将返回负,零或正整数值,表示请求的uint中日期之间的差异量。 - Duncan C
可以使用此方法,但单位参数的说明是错误的!它只期望应该使用的最小单位。 Apple文档:对于给定日期,必须与所有较大单位一样的最小单位才能被视为相同 - Matoz
用法示例:BOOL competitionStarted = [[NSCalendar currentCalendar] compareDate:self.competition.startDate toDate:[NSDate date] toUnitGranularity:NSCalendarUnitDay]!= NSOrderedDescending; - Leon


对于iOS8及更高版本,检查同一天是否出现两个日期非常简单:

[[NSCalendar currentCalendar] isDate:date1 inSameDayAsDate:date2]

看到 文件


14
2017-11-30 01:17





这是所有答案的简写:

NSInteger interval = [[[NSCalendar currentCalendar] components: NSDayCalendarUnit
                                                                  fromDate: date1
                                                                    toDate: date2
                                                                   options: 0] day];
    if(interval<0){
       //date1<date2
    }else if (interval>0){
       //date2<date1
    }else{
       //date1=date2
    }

10
2017-10-12 20:21



此代码不起作用。如果你在[NSDate日期]增加23个小时,它将显示两个日期在同一天,这在大多数情况下显然是错误的。 - Gottfried
@ Gottfired这将忽略OP请求的时间部分。添加23小时不确定你的意思。你的意思是改变日期? - Bms270
@ Bms270他的意思是改变一天。如果您今天比较@ 3PM到明天@ 9AM,您的代码将返回0天的增量,即使第二个日期显然是另一天。 - Christian Schnorr
@Jenox你试过这段代码吗?你的例子应该回归:今天>明天,不管它是什么时候。它只是忽略了小时,就像你比较12am和12am一样。 OP说“不管时间”。 - Bms270
整体 点 日历方法是他们聪明。该调用将两个日期映射到日历的时区,忽略所有较小的单位,如果您今天凌晨2点与明天凌晨1点比较,则它们不在同一天,因此结果为1。 - gnasher729


我使用了Duncan C方法,我修正了他犯的一些错误

-(NSInteger) daysBetweenDate:(NSDate *)firstDate andDate:(NSDate *)secondDate { 

    NSCalendar *currentCalendar = [NSCalendar currentCalendar];
    NSDateComponents *components = [currentCalendar components: NSDayCalendarUnit fromDate: firstDate toDate: secondDate options: 0];

    NSInteger days = [components day];

    return days;
}

6
2018-04-23 13:47





我用这个小的util方法:

-(NSDate*)normalizedDateWithDate:(NSDate*)date
{
   NSDateComponents* components = [calendar components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit)
                                              fromDate: date];
   return [calendar_ dateFromComponents:components]; // NB calendar_ must be initialized
}

(你显然需要一个名为的伊娃 calendar_ 含有 NSCalendar。)

使用这个,很容易检查今天的日期是这样的:

[[self normalizeDate:aDate] isEqualToDate:[self normalizeDate:[NSDate date]]];

[NSDate date] 返回当前日期和时间。)

这当然与格雷戈里的建议非常相似。这种方法的缺点是它往往会产生大量的临时性 NSDate 对象。如果您要处理大量日期,我建议您使用其他方法,例如直接比较组件或使用 NSDateComponents 对象而不是 NSDates


6
2017-12-06 17:25



非常有帮助:)非常感谢你 - pasql


答案比每个人都做到的更简单。 NSCalendar有一个方法

components:fromDate:toDate:options

该方法允许您使用您想要的任何单位计算两个日期之间的差异。

所以写一个像这样的方法:

-(NSInteger) daysBetweenDate: (NSDate *firstDate) andDate: (NSDate *secondDate)
{
  NSCalendar *currentCalendar = [NSCalendar currentCalendar];
  NSDateComponents components* = [currentCalendar components: NSDayCalendarUnit
    fromDate: firstDate 
    toDate: secondDate
    options: 0];

  NSInteger days = [components days];
  return days;
}

如果上述方法返回零,则两个日期在同一天。


3
2017-11-26 20:43





从iOS 8.0开始,您可以使用:

NSCalendar *calendar = [NSCalendar currentCalendar];
NSComparisonResult dateComparison = [calendar compareDate:[NSDate date] toDate:otherNSDate toUnitGranularity:NSCalendarUnitDay];

如果结果是例如NSOrderedDescending,otherDate在[NSDate date]之前以天为单位。

我没有在NSCalendar文档中看到这种方法,但它在 iOS 7.1到iOS 8.0 API差异


3
2018-03-31 15:32





对于在Swift 3中编码的开发人员

if(NSCalendar.current.isDate(selectedDate, inSameDayAs: NSDate() as Date)){
     // Do something
}

2
2018-03-31 03:26





int interval = (int)[firstTime timeIntervalSinceDate:secondTime]/(60*60*24);
if (interval!=0){
   //not the same day;
}

1
2017-09-18 09:46