Сравнение даты предиката основных данных
Я пытаюсь получить все объекты в объекте, соответствующем пользователю selectedDate (это NSDate). Код основных данных в порядке, но мой предикат продолжает возвращать 0 результатов, даты в базе данных совпадают с выбранными пользователем.
Как следует сравнить selectedDate с датой объекта, использующего предикат?
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(eDate = %@)", selectedDate];
4 ответа
Ваш предикат выглядит хорошо.
Причина, по которой вы находите нулевой результат, возвращается, однако, может быть то, что даты не совсем совпадают.
Например:
05/04/2012 13:37:00
не будет совпадать с 05/04/2012 13:37:01
поскольку эти два значения не совсем одинаковы.
Вы хотите проверить дату (день, месяц, год), а также время?
Если вы хотите проверить только дату, вы должны создать дату начала и дату окончания и сравнить их, используя выбранную пользователем дату в качестве системы отсчета.
Нечто подобное должно создать дату и время для 00:00:00.
//gather current calendar
NSCalendar *calendar = [NSCalendar currentCalendar];
//gather date components from date
NSDateComponents *dateComponents = [calendar components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) fromDate:[NSDate date]];
//set date components
[dateComponents setHour:0];
[dateComponents setMinute:0];
[dateComponents setSecond:0];
//return date relative from date
return [calendar dateFromComponents:dateComponents];
Создайте другую дату, установив часы, минуты и секунды на 23:59:59 и убедитесь, что выбранная пользователем дата попадает в эти диапазоны.
[NSPredicate predicateWithFormat:@"date BETWEEN %@", [NSArray arrayWithObjects:startOfDay, endOfDay, nil]]
Хотя в человеческом общении дата часто совпадает с днем, это не то же самое с объектами NSDate: NSDate представляет один момент времени. Даты, которые отличаются только в секундах, не равны. И на самом деле они вообще не представляют дни, месяц, год, поскольку это отличается от календарной системы к календарной системе
Вы должны определить для себя, совпадают ли даты в одной минуте, часе, дне... Так что в основном вы должны научить программу допускать некоторую нечеткость.
здесь для минутного разрешения
NSDate *startDate = ....;
NSTimeInterval length;
[[NSCalendar currentCalendar] rangeOfUnit:NSMinuteCalendarUnit
startDate:&startDate
interval:&length
forDate:startDate];
NSDate *endDate = [startDate dateByAddingTimeInterval:length];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(eDate >= %@) AND (eDate < %@)", startDate, endDate];
Для дат в тот же день (с учетом часовых поясов и летнего времени) вы просто изменили бы это:
[[NSCalendar currentCalendar] rangeOfUnit:NSDayCalendarUnit
startDate:&startDate
interval:&length
forDate:startDate];
Я могу начать работать с некоторыми изменениями в принятом ответе и использовать API iOS 8 для создания дат со смещением времени. Код:
NSCalendar *calendar = [[FFSharedCalendar singleton] getGregorianCalendar];
NSDate *startOfDay = [calendar dateBySettingHour:0 minute:0 second:0 ofDate:[NSDate date] options:0];
NSDate *endOfDay = [calendar dateBySettingHour:23 minute:59 second:59 ofDate:[NSDate date] options:0];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"createdAt > %@ AND createdAt < %@", startOfDay, endOfDay];
NSArray* plans = [Plan MR_findAllWithPredicate:predicate];
Надеюсь, это поможет кому-то
Я запрашиваю между 1 секундой выше и ниже моей фактической даты. В моем случае можно добавлять и вычитать 1 секунду, когда я запрашиваю заказы в ресторане, поэтому я знаю, что для выполнения нового заказа требуется некоторое время, в целях безопасности у меня также есть еще одно поле orderNo.
let fetchRequest: NSFetchRequest = Order.fetchRequest()
let date_formatter = DateFormatter()
date_formatter.dateFormat = "yyyy-MM-dd-HH-mm-ss"
date_formatter.timeZone = TimeZone(abbreviation: "UTC")
let createdDate = date_formatter.date(from: clientCreatedStr)
let calendar = NSCalendar.current
//as matching exact same datetime doesnt return anything
let onesecondafter = calendar.date(byAdding: .second, value: 1, to: createdDate!)
let onesecondbefore = calendar.date(byAdding: .second, value: -1, to: createdDate!)
let predicate = NSPredicate(format: "offlineUniqueId == %@ AND (clientCreatedDate >= %@ AND clientCreatedDate <= %@)", offlineUniqueId, onesecondbefore! as NSDate, onesecondafter! as NSDate)
fetchRequest.predicate = predicate
Недавно я потратил некоторое время, пытаясь решить эту проблему, и решил следующее, теперь обновленное для iOS 8 и выше...
NSDate *dateDay = nil;
NSDate *dateDayStart = nil;
NSDate *dateDayNext = nil;
dateDay = <<USER_INPUT>>; //for example - selectedDate
dateDayStart = [[NSCalendar currentCalendar] startOfDayForDate:dateDay];
// dateDayNext EITHER
dateDayNext = [dateDayStart dateByAddingTimeInterval:(24 * 60 * 60)];
// dateDayNext OR
NSDateComponents *dateComponentDay = nil;
dateComponentDay = [[NSDateComponents alloc] init];
[dateComponentDay setDay:1];
dateDayNext = [[NSCalendar currentCalendar] dateByAddingComponents:dateComponentDay
toDate:dateDayStart
options:NSCalendarMatchNextTime];
... и NSPredicate
для основных данных NSFetchRequest
(как уже показано выше в других ответах)...
[NSPredicate predicateWithFormat:@"(dateAttribute >= %@) AND (dateAttribute < %@)", dateDayStart, dateDayNext]]