Сравнение двух NSDates и игнорирование компонента времени
что является наиболее эффективным/рекомендуемый способ сравнения двух NSDates? Я хотел бы видеть, находятся ли обе даты в один и тот же день, независимо от времени, и начали писать некоторый код, который использует метод timeIntervalSinceDate: в классе NSDate и получает целое число этого значения, разделенное на количество секунд в день. Это кажется долго запыхавшимся, и я чувствую, что упускаю что-то очевидное.
код, который я пытаюсь исправить это:
if (!([key compare:todaysDate] == NSOrderedDescending))
{
todaysDateSection = [eventSectionsArray count] - 1;
}
где key и todaysDate являются объектами NSDate и todaysdate создает с помощью:
NSDate *todaysDate = [[NSDate alloc] init];
в отношении
Дэйв
16 ответов:
вы устанавливаете время в дату 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
затем вы можете сравнить значения даты. Смотрите обзор в справочной документации.
Я удивлен, что никакие другие ответы не имеют этой опции для получения даты "начала дня" для объектов:
[[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
к несколько произвольным значениям, которые можно сравнить. Если они равны, то они находятся в один и тот же день.
есть новый метод, который был введен в NSCalendar с iOS 8, что делает это намного проще.
- (NSComparisonResult)compareDate:(NSDate *)date1 toDate:(NSDate *)date2 toUnitGranularity:(NSCalendarUnit)unit NS_AVAILABLE(10_9, 8_0);
вы устанавливаете степень детализации на единицу(ы), которые имеют значение. Это игнорирует все другие единицы и ограничивает сравнение с выбранными.
для iOS8 и более поздних версий проверка наличия двух дат в один и тот же день так же проста, как:
[[NSCalendar currentCalendar] isDate:date1 inSameDayAsDate:date2]
посмотреть документация
это стенография всех ответов:
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 }
я использовал подход 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; }
я использую этот маленький метод 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
объекты. Если вы собираетесь обрабатывать много из дат я бы рекомендовал использовать какой-то другой метод, например, напрямую сравнивать компоненты или работать с объектыNSDates
.
ответ проще, чем все делают это, чтобы быть. 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; }
Если выше метод возвращает ноль, две даты в один день.
начиная с 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 различия
для разработчиков кодирования в Swift 3
if(NSCalendar.current.isDate(selectedDate, inSameDayAs: NSDate() as Date)){ // Do something }
int interval = (int)[firstTime timeIntervalSinceDate:secondTime]/(60*60*24); if (interval!=0){ //not the same day; }
мое решение было два преобразования с 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, в соответствии с вашими потребностями, вы можете выбрать один из двух следующих шаблонов для того, чтобы решить вашу проблему.
#1. Используя
compare(_:to:toGranularity:)
метод
Calendar
имеет метод под названиемcompare(_:to:toGranularity:)
.compare(_:to:toGranularity:)
есть следующее объявление:func compare(_ date1: Date, to date2: Date, toGranularity component: Calendar.Component) -> ComparisonResult
сравнивает заданные даты с заданным компонентом, сообщая о них
orderedSame
если они одинаковы в данном компоненте и всех больших компонентах, иначе либоorderedAscending
илиorderedDescending
.код игровой площадки ниже показывает горячий, чтобы использовать его:
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
возвращает разницу между двумя датами.
код игровой площадки ниже показывает горячий, чтобы использовать его:
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 }
документация в отношении 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; } }
это особенно уродливая кошка для кожи, но вот еще один способ сделать это. Я не говорю, что это элегантно, но это, вероятно, так близко, как вы можете получить с поддержкой даты/времени в iOS.
bool isToday = [[NSDateFormatter localizedStringFromDate:date dateStyle:NSDateFormatterFullStyle timeStyle:NSDateFormatterNoStyle] isEqualToString:[NSDateFormatter localizedStringFromDate:[NSDate date] dateStyle:NSDateFormatterFullStyle timeStyle:NSDateFormatterNoStyle]];
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)];
сравнить час, а также исправить разницу в 1 день