【发布时间】:2010-12-06 09:38:53
【问题描述】:
我需要知道两个 NSDate 实例是否都来自同一天。
有没有比获取 NSDateComponents 并比较日/月/年更简单/更好的方法?
【问题讨论】:
-
您可能需要重新评估已接受的答案。情况发生了变化。
标签: ios objective-c macos cocoa-touch
我需要知道两个 NSDate 实例是否都来自同一天。
有没有比获取 NSDateComponents 并比较日/月/年更简单/更好的方法?
【问题讨论】:
标签: ios objective-c macos cocoa-touch
对我来说,NSDateComponents 听起来是最好的选择。另一种尝试的策略是将其免费桥接到 CFDate,然后使用 CFDateGetAbsoluteTime 并进行减法以获得两个日期之间的时间量。但是,您必须做一些额外的数学运算才能确定时差是否使日期在同一天。
【讨论】:
NSDate 有这个很好的方法:timeIntervalSinceDate: 因此你甚至不需要核心基础。
(注意:查看 Joe 的答案,了解在 iOS 8+ 上执行此操作的好方法)
我只是使用日期格式化程序:
NSDateFormatter *dateComparisonFormatter = [[[NSDateFormatter alloc] init] autorelease];
[dateComparisonFormatter setDateFormat:@"yyyy-MM-dd"];
if( [[dateComparisonFormatter stringFromDate:firstDate] isEqualToString:[dateComparisonFormatter stringFromDate:secondDate]] ) {
…
}
HTH。
【讨论】:
我使用 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];
}
【讨论】:
如果您的目标是 iOS 8(和 OS X 10.9)或更高版本,那么 Joe's answer 是一个更好的解决方案,为此使用 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];
}
【讨论】:
-(BOOL)isDate:(NSDate*)date1 sameDayAsDate:(NSDate*)date2
我喜欢 progrmr 的解决方案,但我会更进一步,创建一个提供此方法的 NSDate 类别。它将使您的代码更具可读性,并且您无需将该方法复制并粘贴到每个可能需要它的新类中——只需导入头文件即可。
@interface NSDate (SameDay)
- (BOOL)isSameDayAsDate:(NSDate*)otherDate;
@end
#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...
}
【讨论】:
我创建自己的实用程序类。
@interface ZYUtility : NSObject
+ (NSDate *)yesterday;
+ (NSDate *)tomorrow;
+ (NSDate *)endOfDay:(NSDate *)date;
+ (NSDate *)beginningOfDay:(NSDate *)date;
@end
+ (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;
}
【讨论】:
以下将测试两个日期是否代表给定时代中的同一天(这在许多情况下就足够了):
- (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;
}
【讨论】:
如果您使用的是 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 的一部分。
【讨论】:
有没有比获取 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;
【讨论】:
在斯威夫特中:
NSCalendar.currentCalendar().isDate(yourDate, equalToDate: yourOtherDate, toUnitGranularity: .Day)
如果他们在同一天,它将返回true。
【讨论】:
NSCalendar.currentCalendar().isDateInToday(yourNSDate)
适用于 iOS 8.0 及更高版本以及 OS X v10.9 及更高版本。
【讨论】:
在 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)