Cocoa-Touch:如何查看两个NSD是否在同一天?


67

我需要知道两个NSDate实例是否都来自同一天。

有没有比获取NSDateComponents和比较日/月/年更容易/更好的方法呢?


2
您可能需要对此重新评估可接受的答案。事情变了。
菲利普

Answers:


7

NSDateComponents听起来对我来说是最好的选择。尝试的另一种策略是将其免费桥接到CFDate,然后使用CFDateGetAbsoluteTime并进行减法以获得两个日期之间的时间量。但是,您必须做一些附加的数学运算才能确定时差是否将日期置入同一天。


1
是的,但是在处理时间方面,您不得不考虑很多事情,最终最终编写的代码不仅仅是使用NSDateComponents。
pxl

对; 我曾建议使用NSDateComponents的替代方法,但仍然认为这是最好的选择。如果这成为代码的性能关键部分,则替代方法可能会稍快一些,但是除非证明有必要,否则我将避免这种优化。
fbrereto

4
NSDate有一个不错的方法:timeIntervalSinceDate:因此,您甚至不需要corefoundation。
格奥尔格·舍利

2
NSDateComponents是最好的选择,因为这样会自动处理诸如时区和夏时制之类的东西。
JeremyP 2014年

3
仅时间间隔不足以确定两个日期是否在同一天。晚上11:59和上午12:01仅间隔2分钟,但间隔不同。您可以使用时间间隔来快速排除> 24小时的间隔,然后使用NSDateComponents进行完整检查。
Drew C

154

如果您的目标是iOS 8(和OS X 10.9)或更高版本,则Joe的答案是使用NSCalendar中的新方法的更好解决方案,其目的仅在于:

-[NSCalendar isDate:inSameDayAsDate:]

对于iOS 7或更早版本:NSDateComponents是我的偏爱。这样的事情怎么样:

- (BOOL)isSameDayWithDate1:(NSDate*)date1 date2:(NSDate*)date2 {
    NSCalendar* calendar = [NSCalendar currentCalendar];

    unsigned unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit |  NSDayCalendarUnit;
    NSDateComponents* comp1 = [calendar components:unitFlags fromDate:date1];
    NSDateComponents* comp2 = [calendar components:unitFlags fromDate:date2];

    return [comp1 day]   == [comp2 day] &&
           [comp1 month] == [comp2 month] &&
           [comp1 year]  == [comp2 year];
}

5
签名应为:-(BOOL)isSameDayWithDate1:​​(NSDate *)date1 date2:(NSDate *)date2 {
John

3
-(BOOL)date:(NSDate *)date1 isTheSameDayAsDate:(NSDate *)date2读起来更好:)
Javier Soto

6
还是另一种方式: -(BOOL)isDate:(NSDate*)date1 sameDayAsDate:(NSDate*)date2
progrmr 2012年

返回[comp1 isEqual:comp2]; 似乎给出相同的结果。有区别吗?为什么选择手动比较日,月和年?
亚历克斯

1
@Alex:NSDateComponents类引用中没有记录isEqual函数,因此不能确定它在所有情况下都会做正确的事情。它会忽略无效的组件吗?可能是,但是没有记录。此代码仅稍长一些,并且即使在调用component:fromDate时单位已包含其他字段(例如小时或分钟),也能给出正确的结果:
progrmr 2013年

53

如果您使用的是iOS 8,则可以使用 -isDate:inSameDayAsDate:

来自NSCalendar.h

/*
    This API compares the Days of the given dates, reporting them equal if they are in the same Day.
*/
- (BOOL)isDate:(NSDate *)date1 inSameDayAsDate:(NSDate *)date2 NS_AVAILABLE(10_9, 8_0);

请注意,由于某种原因,这并未进入Apple开发人员网站上的官方文档。但这绝对是公共API的一部分。


24

(注意:请查看Joe的答案,这是在iOS 8+上执行此操作的好方法)

我只是使用日期格式化程序:

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

if( [[dateComparisonFormatter stringFromDate:firstDate] isEqualToString:[dateComparisonFormatter stringFromDate:secondDate]] ) {
    …
}

HTH。


9
这比使用NSDateComponents还要糟糕,因为格式化程序必须首先将日期分解为组件,然后创建两个字符串,然后比较字符串。
2009年

9
您的“更好”指标是什么?我认为这比类似的NSDateComponents代码“更轻松”,因为它更简洁并且易于维护。
Ben Lachman

5
我一直在使用dateComponents方法,但这要聪明得多。较短的代码更好,如果性能有问题,我可以缓存NSDateFormatter。
史蒂芬·费舍尔

2
为我工作,很好,很聪明。使我免于所有NSCalendar开销。
卢卡斯(Lukasz)

13

在Swift中:

NSCalendar.currentCalendar().isDate(yourDate, equalToDate: yourOtherDate, toUnitGranularity: .Day)

如果它们在同一天,它将返回true。


适用于iOS 8.0
ZYiOS

11

我喜欢progrmr的解决方案,但是我会走得更远,并NSDate提供一种提供这种方法的解决方案。这将使您的代码更具可读性,并且您无需将方法复制并粘贴到可能需要的每个新类中-只需导入头文件即可。

NSDate + SameDay.h

@interface NSDate (SameDay)
- (BOOL)isSameDayAsDate:(NSDate*)otherDate;
@end

NSDate + SameDay.m

#import "NSDate+SameDay.h"

@implementation NSDate (SameDay)

- (BOOL)isSameDayAsDate:(NSDate*)otherDate {

    // From progrmr's answer...
    NSCalendar* calendar = [NSCalendar currentCalendar];

    unsigned unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit |  NSDayCalendarUnit;
    NSDateComponents* comp1 = [calendar components:unitFlags fromDate:self];
    NSDateComponents* comp2 = [calendar components:unitFlags fromDate:otherDate];

    return [comp1 day]   == [comp2 day] &&
           [comp1 month] == [comp2 month] &&
           [comp1 year]  == [comp2 year];
}

@end

然后,在导入NSDate+SameDay.h您的类之后,可以像这样使用它:

if ([myFirstDate isSameDayAsDate:mySecondDate]) {
    // The two dates are on the same day...
}

我也认为这是更好的方法。
MLQ

5

我使用NSDateComponents去除时间方面,然后进行比较。就像是:

if ([[self beginningOfDay:date1] isEqualToDate:[self beginningOfDay:date2]]) 
{
...
}

- (NSDate *)beginningOfDay:(NSDate *)date {
    NSCalendar *calendar = [NSCalendar currentCalendar];

    unsigned unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit |  NSDayCalendarUnit;
    NSDateComponents *comp = [calendar components:unitFlags fromDate:date];

    return [calendar dateFromComponents:comp];
}

每个日期使用两次转换(components:fromDate和dateFromComponents)。我仅使用components:fromDate,从每个组件中提取月/日/年,然后比较这3个整数以查看它们是否匹配。
progrmr

您不应该使用BeginningOfDay,不是所有的日子都从凌晨12点开始。您应该使用中午(12pm)进行时间日期比较
Leo Dabus

4
NSCalendar.currentCalendar().isDateInToday(yourNSDate)

在iOS 8.0和更高版本以及OS X v10.9和更高版本中可用。


1

有没有比获取NSDateComponents和比较日/月/年更容易/更好的方法呢?

是的,有一种更简单的方法

-[NSCalendar rangeForUnit:startDate:interval:forDate:] 通过这种方法,可以轻松地将日期设置为单位的开始日期(天,小时,月,年等),并获取该单位的长度(间隔)。

作为一个类别,它可能像

@interface NSDate (Comparison)
-(BOOL) isSameDay:(NSDate *)rhs;
@end

@implementation NSDate (Comparison)

-(BOOL)isSameDay:(NSDate *)rhs
{
    NSDate *lhs = self;
    NSDate *lhsStart;
    NSDate *rhsStart;

    NSCalendar *cal = [NSCalendar currentCalendar];
    [cal rangeOfUnit:NSCalendarUnitDay startDate:&lhsStart interval:NULL forDate:lhs];
    [cal rangeOfUnit:NSCalendarUnitDay startDate:&rhsStart interval:NULL forDate:rhs];
    return [lhsStart compare:rhsStart] == NSOrderedSame;
}

@end

此类别适用于所有iOS版本和Mac OS X 10.5+。

对于iOS 8+和Mac OS X 10.9+,您可以使用NSCalendars

- (BOOL)isDate:(NSDate *)date1 equalToDate:(NSDate *)date2 toUnitGranularity:(NSCalendarUnit)unit;

1

在Swift 3.0,iOS8 +中

if NSCalendar.current.isDate(Date(), equalTo: date, toGranularity: .day) {

}

要么

if NSCalendar.current.isDateInToday(date) {

}

还有Calendar.current.isDate(_ date1: Date, inSameDayAs date2: Date)
垫片

-1

我创建自己的实用程序类。

ZYUtility.h

@interface ZYUtility : NSObject
+ (NSDate *)yesterday;
+ (NSDate *)tomorrow;
+ (NSDate *)endOfDay:(NSDate *)date;
+ (NSDate *)beginningOfDay:(NSDate *)date;
@end

ZYUtility.m

+ (NSDate *)yesterday;
{
    NSCalendar *calendar = [NSCalendar currentCalendar];
    NSDateComponents *componets = [calendar components:NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit
                                              fromDate:[NSDate date]];
    componets.day -= 1;
    componets.hour = 24;
    componets.minute = 0;
    componets.second = 0;

    return [calendar dateFromComponents:componets];
}

+ (NSDate *)tomorrow;
{
    NSCalendar *calendar = [NSCalendar currentCalendar];
    NSDateComponents *componets = [calendar components:NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit
                                              fromDate:[NSDate date]];
    componets.day += 1;
    componets.hour = 0;
    componets.minute = 0;
    componets.second = 0;

    return [calendar dateFromComponents:componets];
}

+ (NSDate *)beginningOfDay:(NSDate *)date {
    NSCalendar *calendar = [NSCalendar currentCalendar];

    unsigned unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit |  NSDayCalendarUnit;
    NSDateComponents *comp = [calendar components:unitFlags fromDate:date];

    return [calendar dateFromComponents:comp];
}

+ (NSDate *)endOfDay:(NSDate *)date {
    NSCalendar *calendar = [NSCalendar currentCalendar];

    NSDateComponents *components = [NSDateComponents new];
    components.day = 1;

    NSDate *theDate = [calendar dateByAddingComponents:components
                                                toDate:[ZYUtility beginningOfDay:date]
                                               options:0];

    theDate = [theDate dateByAddingTimeInterval:-1];

    return theDate;
}

-1

以下内容将测试两个日期是否代表给定时代的同一天(在许多情况下足够):

- (BOOL)isDate:(NSDate *)date1 sameDayAsDate:(NSDate *)date2 {
    NSCalendar *calendar = [NSCalendar currentCalendar];
    int diff = [calendar ordinalityOfUnit:NSDayCalendarUnit 
                                   inUnit:NSEraCalendarUnit 
                                  forDate:date1] -
               [calendar ordinalityOfUnit:NSDayCalendarUnit 
                                   inUnit:NSEraCalendarUnit 
                                  forDate:date2];
    return 0 == diff;
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.