Как определить, является ли NSDate сегодня?
Как проверить если NSDate принадлежит сегодня?
я использовал, чтобы проверить его, используя первые 10 символов от [aDate description]. [[aDate description] substringToIndex:10] возвращает строку типа "YYYY-MM-DD" поэтому я сравнил строку со строкой, возвращаемой [[[NSDate date] description] substringToIndex:10].
есть более быстрый и/или аккуратный способ проверить?
спасибо.
20 ответов:
вы можете сравнить датой компоненты:
NSDateComponents *otherDay = [[NSCalendar currentCalendar] components:NSCalendarUnitEra | NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay fromDate:aDate]; NSDateComponents *today = [[NSCalendar currentCalendar] components:NSCalendarUnitEra | NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay fromDate:[NSDate date]]; if([today day] == [otherDay day] && [today month] == [otherDay month] && [today year] == [otherDay year] && [today era] == [otherDay era]) { //do stuff }Edit:
мне больше нравится метод Стефана, я думаю, что он делает более чистым и понятным, если заявление:
NSCalendar *cal = [NSCalendar currentCalendar]; NSDateComponents *components = [cal components:(NSCalendarUnitEra | NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay) fromDate:[NSDate date]]; NSDate *today = [cal dateFromComponents:components]; components = [cal components:(NSCalendarUnitEra | NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay) fromDate:aDate]; NSDate *otherDate = [cal dateFromComponents:components]; if([today isEqualToDate:otherDate]) { //do stuff }Крис, я включил ваше предложение. Я должен был посмотреть, какая эпоха была, поэтому для всех, кто не знает, он различает BC и AD. Это, вероятно, не нужно для большинства людей, но это легко проверить и добавляет некоторую уверенность, поэтому я включил его. Если вы собираетесь скорость, это, вероятно, не очень хороший метод в любом случае.
Примечание как и многие ответы на SO, после 7 лет это полностью устарело. В Swift теперь просто используйте
.isDateInToday
в macOS 10.9+ и iOS 8+ есть метод на Nscalendar / Calendar, который делает именно это!
- (BOOL)isDateInToday:(NSDate *)dateТак что вы бы просто сделали
Цель-C:
BOOL today = [[NSCalendar currentCalendar] isDateInToday:date];Swift 3:
let today = Calendar.current.isDateInToday(date)
это ответвление на ваш вопрос, но если вы хотите напечатать NSDate с "сегодня" или "вчера", использовать функцию
- (void)setDoesRelativeDateFormatting:(BOOL)bдля NSDateFormatter
Я бы попытался нормализовать сегодняшнюю дату до полуночи и вторую дату, нормализовать до полуночи, а затем сравнить, если это тот же NSDate.
С пример яблоко вот как вы нормализуете до полуночи сегодняшнюю дату, сделайте то же самое для второго свидания и сравните:
NSCalendar * gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; NSDateComponents * components = [gregorian components: (NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit) fromDate:[NSDate date]]; NSDate * today = [gregorian dateFromComponents:components];
нет необходимости жонглировать с компонентами, эпох и прочее.
NSCalendar предоставляет метод для получения начала определенной единицы времени для существующей даты.
этот код получит начало сегодняшнего дня и другую дату и сравните это. Если он оценивает в
NSOrderedSame, обе даты в один день - сегодня.NSDate *today = nil; NSDate *beginningOfOtherDate = nil; NSDate *now = [NSDate date]; [[NSCalendar currentCalendar] rangeOfUnit:NSDayCalendarUnit startDate:&today interval:NULL forDate:now]; [[NSCalendar currentCalendar] rangeOfUnit:NSDayCalendarUnit startDate:&beginningOfOtherDate interval:NULL forDate:beginningOfOtherDate]; if([today compare:beginningOfOtherDate] == NSOrderedSame) { //otherDate is a date in the current day }
работающего расширение Swift 3 & 4 из предложения Catfish_Man:
extension Date { func isToday() -> Bool { return Calendar.current.isDateInToday(self) } }
extension NSDate { func isToday() -> Bool { let cal = NSCalendar.currentCalendar() var components = cal.components([.Era, .Year, .Month, .Day], fromDate:NSDate()) let today = cal.dateFromComponents(components)! components = cal.components([.Era, .Year, .Month, .Day], fromDate:self) let otherDate = cal.dateFromComponents(components)! return today.isEqualToDate(otherDate) }работал для меня на Swift 2.0
Swift версия лучшего ответа:
let cal = NSCalendar.currentCalendar() var components = cal.components([.Era, .Year, .Month, .Day], fromDate:NSDate()) let today = cal.dateFromComponents(components)! components = cal.components([.Era, .Year, .Month, .Day], fromDate:aDate); let otherDate = cal.dateFromComponents(components)! if(today.isEqualToDate(otherDate)) { //do stuff }
см. запись в документации Apple, озаглавленную "выполнение календарных расчетов"[ссылка].
листинг 13 на этой странице предполагает, что для определения количества полуночников между днями вы используете:
- (NSInteger)midnightsFromDate:(NSDate *)startDate toDate:(NSDate *)endDate { NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar]; NSInteger startDay = [calendar ordinalityOfUnit:NSDayCalendarUnit inUnit:NSEraCalendarUnit forDate:startDate]; NSInteger endDay = [calendar ordinalityOfUnit:NSDayCalendarUnit inUnit:NSEraCalendarUnit forDate:endDate]; return endDay - startDay; }затем вы можете определить, являются ли два дня одинаковыми, используя этот метод и видя, возвращает ли он 0 или нет.
вы также можете проверить временной интервал между датой у вас есть, и текущая дата:
[myDate timeIntervalSinceNow]Это даст вам интервал времени, в секундах, между myDate и текущей датой / временем.
Edit: Примечание для всех: я хорошо знаю, что [myDate timeIntervalSinceNow] не однозначно определяет, является ли myDate сегодня.
Я оставляю этот ответ как есть, так что если кто-то что-то ищет подобное и [myDate timeIntervalSinceNow] полезно, они могут найти его здесь.
расширение Swift на основе лучших ответов:
extension NSDate { func isToday() -> Bool { let cal = NSCalendar.currentCalendar() if cal.respondsToSelector("isDateInToday:") { return cal.isDateInToday(self) } var components = cal.components((.CalendarUnitEra | .CalendarUnitYear | .CalendarUnitMonth | .CalendarUnitDay), fromDate:NSDate()) let today = cal.dateFromComponents(components)! components = cal.components((.CalendarUnitEra | .CalendarUnitYear | .CalendarUnitMonth | .CalendarUnitDay), fromDate:self); let otherDate = cal.dateFromComponents(components)! return today.isEqualToDate(otherDate) } }
если у вас много этих сравнений, то звонки
calendar:components:fromDateначало занимать много времени. Согласно некоторым профилям, которые я сделал, они кажутся довольно дорогими.скажем, вы пытаетесь определить, какой из некоторого массива дат, скажем
NSArray *datesToCompare, Это тот же день, что и какой-то данный день, скажемNSDate *baseDate, то вы можете использовать что-то вроде следующего (частично адаптировано из ответа выше):NSDate *baseDate = [NSDate date]; NSArray *datesToCompare = [NSArray arrayWithObjects:[NSDate date], [NSDate dateWithTimeIntervalSinceNow:100], [NSDate dateWithTimeIntervalSinceNow:1000], [NSDate dateWithTimeIntervalSinceNow:-10000], [NSDate dateWithTimeIntervalSinceNow:100000], [NSDate dateWithTimeIntervalSinceNow:1000000], [NSDate dateWithTimeIntervalSinceNow:50], nil]; // determine the NSDate for midnight of the base date: NSCalendar* calendar = [NSCalendar currentCalendar]; NSDateComponents* comps = [calendar components:(NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit) fromDate:baseDate]; NSDate* theMidnightHour = [calendar dateFromComponents:comps]; // set up a localized date formatter so we can see the answers are right! NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; [dateFormatter setDateStyle:NSDateFormatterMediumStyle]; [dateFormatter setTimeStyle:NSDateFormatterMediumStyle]; // determine which dates in an array are on the same day as the base date: for (NSDate *date in datesToCompare) { NSTimeInterval interval = [date timeIntervalSinceDate:theMidnightHour]; if (interval >= 0 && interval < 60*60*24) { NSLog(@"%@ is on the same day as %@", [dateFormatter stringFromDate:date], [dateFormatter stringFromDate:baseDate]); } else { NSLog(@"%@ is NOT on the same day as %@", [dateFormatter stringFromDate:date], [dateFormatter stringFromDate:baseDate]); } }выход:
Nov 23, 2011 1:32:00 PM is on the same day as Nov 23, 2011 1:32:00 PM Nov 23, 2011 1:33:40 PM is on the same day as Nov 23, 2011 1:32:00 PM Nov 23, 2011 1:48:40 PM is on the same day as Nov 23, 2011 1:32:00 PM Nov 23, 2011 10:45:20 AM is on the same day as Nov 23, 2011 1:32:00 PM Nov 24, 2011 5:18:40 PM is NOT on the same day as Nov 23, 2011 1:32:00 PM Dec 5, 2011 3:18:40 AM is NOT on the same day as Nov 23, 2011 1:32:00 PM Nov 23, 2011 1:32:50 PM is on the same day as Nov 23, 2011 1:32:00 PM
есть более простой способ, чем многие из вышеперечисленных ответов!
NSDate *date = ... // The date you wish to test NSCalendar *calendar = [NSCalendar currentCalendar]; if([calendar isDateInToday:date]) { //do stuff }
для iOS7 и более ранних версий:
//this is now => need that for the current date NSDate * now = [NSDate date]; NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; [calendar setTimeZone:[NSTimeZone systemTimeZone]]; NSDateComponents * components = [calendar components:( NSYearCalendarUnit| NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit) fromDate: now]; [components setMinute:0]; [components setHour:0]; [components setSecond:0]; //this is Today's Midnight NSDate *todaysMidnight = [calendar dateFromComponents: components]; //now timeIntervals since Midnight => in seconds NSTimeInterval todayTimeInterval = [now timeIntervalSinceDate: todaysMidnight]; //now timeIntervals since OtherDate => in seconds NSTimeInterval otherDateTimeInterval = [now timeIntervalSinceDate: otherDate]; if(otherDateTimeInterval > todayTimeInterval) //otherDate is not in today { if((otherDateTimeInterval - todayTimeInterval) <= 86400) //86400 == a day total seconds { @"yesterday"; } else { @"earlier"; } } else { @"today"; } now = nil; calendar = nil; components = nil; todaysMidnight = nil; NSLog("Thank you :-)");
Это, вероятно, может быть переработано как категория NSDate, но я использовал:
// Seconds per day (24h * 60m * 60s) #define kSecondsPerDay 86400.0f + (BOOL) dateIsToday:(NSDate*)dateToCheck { // Split today into components NSCalendar* gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; NSDateComponents* comps = [gregorian components:(NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit|NSHourCalendarUnit|NSMinuteCalendarUnit|NSSecondCalendarUnit) fromDate:[NSDate date]]; // Set to this morning 00:00:00 [comps setHour:0]; [comps setMinute:0]; [comps setSecond:0]; NSDate* theMidnightHour = [gregorian dateFromComponents:comps]; [gregorian release]; // Get time difference (in seconds) between date and then NSTimeInterval diff = [dateToCheck timeIntervalSinceDate:theMidnightHour]; return ( diff>=0.0f && diff<kSecondsPerDay ); }(однако, сравнивая две строки даты, как в исходном вопросе, почти чувствует себя "чище"..)
Проверьте нашу Эрику Садун отлично
NSDate extension. Очень проста в использовании. Отлично это здесь:http://github.com/erica/NSDate-Extensions
Это уже есть в этом посте:https://stackoverflow.com/a/4052798/362310
правильное и безопасное решение без принудительного разворачивания, работающее на Swift 2.2 и до iOS 8:
func isToday() -> Bool { let calendar = NSCalendar.currentCalendar() if #available(iOS 8.0, *) { return calendar.isDateInToday(self) } let todayComponents = calendar.components([.Era, .Year, .Month, .Day], fromDate:NSDate()) let dayComponents = calendar.components([.Era, .Year, .Month, .Day], fromDate:self) guard let today = calendar.dateFromComponents(todayComponents), day = calendar.dateFromComponents(dayComponents) else { return false } return today.compare(day) == .OrderedSame }
вот мой ответ на 2 цента, основанный на принятом ответе, но также поддерживающий новый API. Примечание: Я использую Григорианский календарь, так как большинство отметок времени являются GMT, но изменить ваш, как вы считаете нужным
func isDateToday(date: NSDate) -> Bool { let calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)! if calendar.respondsToSelector("isDateInToday:") { return calendar.isDateInToday(date) } let dateComponents = NSCalendarUnit.CalendarUnitYear | NSCalendarUnit.CalendarUnitMonth | NSCalendarUnit.CalendarUnitDay let today = calendar.dateFromComponents(calendar.components(dateComponents, fromDate: NSDate()))! let dateToCompare = calendar.dateFromComponents(calendar.components(dateComponents, fromDate: date))! return dateToCompare == today }
мое решение-вычислить, сколько дней прошло с 1970 года по делению и сравнить целочисленную часть
#define kOneDay (60*60*24) - (BOOL)isToday { NSInteger offset = [[NSTimeZone defaultTimeZone] secondsFromGMT]; NSInteger days =[self timeIntervalSince1970] + offset; NSInteger currentDays = [[NSDate date] timeIntervalSince1970] + offset; return (days / kOneDay == currentDays / kOneDay); }
NSDate *dateOne = yourDate; NSDate *dateTwo = [NSDate date]; switch ([dateOne compare:dateTwo]) { case NSOrderedAscending: NSLog(@”NSOrderedAscending”); break; case NSOrderedSame: NSLog(@”NSOrderedSame”); break; case NSOrderedDescending: NSLog(@”NSOrderedDescending”); break; }
Comments