比较两个 NSDates 并忽略时间分量

比较两个国家可持续发展标准的最有效/推荐的方法是什么?我希望能够看到两个日期是否在同一天,不管时间如何,并且已经开始编写一些代码,使用 NSDate 类中的 timeIntervalSinceDate: 方法,并得到这个值的整数除以一天中的秒数。这似乎是冗长的,我觉得我错过了一些显而易见的东西。

我试图修复的代码是:

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

其中 key 和 todaysDate 是 NSDate 对象,todaysDate 使用以下方法创建:

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

问候

戴夫

38926 次浏览

在进行比较之前,将日期中的时间设置为00: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

然后您可以比较日期值。

关于 NSDate的文献表明,compare:isEqual:方法都将执行一个基本的比较和顺序的结果,虽然他们仍然在时间因素。

管理这个任务最简单的方法可能是创建一个新的 isToday方法,其效果如下:

- (bool)isToday:(NSDate *)otherDate
{
currentTime = [however current time is retrieved]; // Pardon the bit of pseudo-code


if (currentTime < [otherDate timeIntervalSinceNow])
{
return YES;
}
else
{
return NO;
}
}

我使用这个小的 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

令我惊讶的是,没有其他的答案有这样的选项来获得对象的“一天的开始”日期:

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

date1date2设置为它们各自日期的开始。如果他们是平等的,他们在同一天。

或者这个选项:

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

它将 day1day2设置为可以比较的任意值。如果他们是平等的,他们在同一天。

答案比大家想象的要简单,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;
}

如果上面的方法返回零,那么这两个日期在同一天。

我用邓肯 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;
}

这是所有答案的速记:

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
}

这是一个特别丑陋的猫皮,但这里有另一种方式做到这一点。我不是说它很优雅,但它可能是你在 iOS 中能够得到的最接近于日期/时间的支持。

bool isToday = [[NSDateFormatter localizedStringFromDate:date dateStyle:NSDateFormatterFullStyle timeStyle:NSDateFormatterNoStyle] isEqualToString:[NSDateFormatter localizedStringFromDate:[NSDate date] dateStyle:NSDateFormatterFullStyle timeStyle:NSDateFormatterNoStyle]];
int interval = (int)[firstTime timeIntervalSinceDate:secondTime]/(60*60*24);
if (interval!=0){
//not the same day;
}

有一种新的方法被引入到了 iOS8的 NSCalendar 中,使得这个过程变得更加简单。

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

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

NSUInteger unit = NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit;
NSDateComponents *comp = [cal components:unit
fromDate:nowDate
toDate:setDate
options:0];


NSString *dMonth;
dMonth = [NSString stringWithFormat:@"%02ld",comp.month];
NSString *dDay;
dDay = [NSString stringWithFormat:@"%02ld",comp.day + (comp.hour > 0 ? 1 : 0)];

比较时间以及固定一天的差异

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

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

如果结果是 NSOrderedDesending,other Date 在[ NSDate date ]之前,以天数表示。

我没有在 NSCalendar 文档中看到这个方法,但它在 IOS7.1到 iOS8.0 API 的差异

对于 iOS8和更高版本,检查是否在同一天发生两个日期非常简单:

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

参见 文件

我的解决方案是用 NSDateFormatter 进行两次转换:

    NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:@"yyyyMMdd"];
[dateFormat setTimeZone:[NSTimeZone timeZoneWithName:@"GMT"]];


NSDate *today = [NSDate dateWithTimeIntervalSinceNow:0];
NSString *todayString=[dateFormat stringFromDate:today];
NSDate *todayWithoutHour=[dateFormat dateFromString:todayString];


if ([today compare:exprDate] == NSOrderedDescending)
{
//do
}

用 Swift 3编写代码的开发人员

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

使用 Swift 3,根据您的需要,您可以选择以下两种模式之一来解决您的问题。


# 1. 使用 compare(_:to:toGranularity:)方法

Calendar有一个名为 compare(_:​to:​to​Granularity:​)的方法。 compare(_:​to:​to​Granularity:​)有以下声明:

func compare(_ date1: Date, to date2: Date, toGranularity component: Calendar.Component) -> ComparisonResult

将给定的日期与给定的组件进行比较,如果它们在给定的组件和所有较大的组件中相同,则报告它们 ordered​Same,否则报告 ordered​Ascendingordered​Descending

下面的 Playground 代码显示了使用它的热点:

import Foundation


let calendar = Calendar.current
let date1 = Date() // "Mar 31, 2017, 2:01 PM"
let date2 = calendar.date(byAdding: .day, value: -1, to: date1)! // "Mar 30, 2017, 2:01 PM"
let date3 = calendar.date(byAdding: .hour, value: 1, to: date1)! // "Mar 31, 2017, 3:01 PM"


/* Compare date1 and date2 */
do {
let comparisonResult = calendar.compare(date1, to: date2, toGranularity: .day)
switch comparisonResult {
case ComparisonResult.orderedSame:
print("Same day")
default:
print("Not the same day")
}
// Prints: "Not the same day"
}


/* Compare date1 and date3 */
do {
let comparisonResult = calendar.compare(date1, to: date3, toGranularity: .day)
if case ComparisonResult.orderedSame = comparisonResult {
print("Same day")
} else {
print("Not the same day")
}
// Prints: "Same day"
}

2. 使用 dateComponents(_:from:to:)

Calendar有一个名为 dateComponents(_:from:to:)的方法。 dateComponents(_:from:to:)有以下声明:

func dateComponents(_ components: Set<Calendar.Component>, from start: Date, to end: Date) -> DateComponents

返回两个日期之间的差值。

下面的 Playground 代码显示了使用它的热点:

import Foundation


let calendar = Calendar.current
let date1 = Date() // "Mar 31, 2017, 2:01 PM"
let date2 = calendar.date(byAdding: .day, value: -1, to: date1)! // "Mar 30, 2017, 2:01 PM"
let date3 = calendar.date(byAdding: .hour, value: 1, to: date1)! // "Mar 31, 2017, 3:01 PM"


/* Compare date1 and date2 */
do {
let dateComponents = calendar.dateComponents([.day], from: date1, to: date2)
switch dateComponents.day {
case let value? where value < 0:
print("date2 is before date1")
case let value? where value > 0:
print("date2 is after date1")
case let value? where value == 0:
print("date2 equals date1")
default:
print("Could not compare dates")
}
// Prints: date2 is before date1
}


/* Compare date1 and date3 */
do {
let dateComponents = calendar.dateComponents([.day], from: date1, to: date3)
switch dateComponents.day {
case let value? where value < 0:
print("date2 is before date1")
case let value? where value > 0:
print("date2 is after date1")
case let value? where value == 0:
print("date2 equals date1")
default:
print("Could not compare dates")
}
// Prints: date2 equals date1
}