Finding objects between two dates - ios

Okay so I have a parse database with two keys (startedAt) and (endedAt) basically I would like to return all the objects between these two given times. However, I store the times as strings, not dates. I would really like to not have to change them to dates as that would force me to rework code in a lot of other parts of my program. So is it possible to do the following
NSDate *leftDate = leftClassRoomAfterDatePicker.date;
NSDate *arrivedDate = arrivedBeforeDatePicker.date;
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"MM-dd hh:mm"];
NSString *leftDateString = [dateFormat stringFromDate:leftDate];
NSString *arrivedDateString = [dateFormat stringFromDate:arrivedDate];
NSLog(leftDateString);
NSLog(arrivedDateString);
PFQuery *query = [PFQuery queryWithClassName:#"PassData"];
[query whereKey:#"startTime" greaterThan:leftDate];
[query whereKey:#"timeArrived" lessThan:arrivedDate];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
NSLog(#"Successfully retrieved %d objects.", objects.count);
}];
When I run this code I get the following error
The problem is that the strings are not returning the correct value. In my parse database I have a value of startTime: Dec 08, 18:28
and endTime: Dec 08, 18:28
But it still does not work (no objects are returned). I think this is because the greaterthan/lessthan functions will not work on strings like this.

You've converted leftDate and arrivedDate to leftDateString and arrivedDateString, but you're still using leftDate and arrivedDate in your query. I think you meant to write:
PFQuery *query = [PFQuery queryWithClassName:#"PassData"];
[query whereKey:#"startTime" greaterThan:leftDateString];
[query whereKey:#"timeArrived" lessThan:arrivedDateString];
in which case you'd no longer get the error since you'd be comparing string to string.
Although I generally recommend that you store and sort your dates with NSDate objects, in this case where your format is in the same descending order of importance as a typical NSDate sort of month, day, hour, then minute, i.e. "MM-dd hh:mm", as long as year or seconds don't matter to you and as long as the queried time format matches the database time format, this query should work since greaterThan and lessThan will compare the string objects alphabetically/numerically.

Error: startTime contains string values but got a date (Code: 102,
Version: 1.2.21)
The error clearly indicates that you are comparing two different objects one is string and second one is date. So there are two things you can either convert any one into date or string. So to implement the same in a easy way, you can write one category with function which will convert either into date or string and use that method to perform the comparison.

I guess for that to work you have to have Date fields in database, then you pass NSDate to whereKey: on iOS.

Related

Extract objects with specific date from custom object Array

I have an ordered array of Availability object which is a class containing two attributes, startAt and endAt.
I'd like to extract from my availability array the objects from a specific day without taking into account the time.
I'd also like to use NSPredicate instead of "for" loop to do it.
Could you help me?
Thanks
for-in loop actually faster than NSPredicate for me, and easier since u can convert it to string or extract it for easy compare, but if u want then the format should be:
#"(%# >= %#) AND (%# <= %#)", dateForCompare, dayStart, dateForCompare, dayEnd where dayStart is the date to compare at 00:00:00, dayEnd is the date to compare at 23:59:59, tweak it base on your needs, u have to do this because a NSDate object contain exact date and time
Hope it help
if you are using timestamp(NSNumber) to store startAt and endAt then you can use predicate as bellow (to fetch all object whose start date is greter then current date)
NSPredicate *pred = [NSPredicate predicateWithFormat:#"startAt > %#", [NSNumber numberWithDouble:[[NSDate date] timeIntervalSince1970]]];
NSArray *filteredArr = [yourArray filteredArrayUsingPredicate:pred];
and if you are using only date string then you can use
NSPredicate *pred = [NSPredicate predicateWithFormat:#"startAt = %#", #"your date string must be same as formate you saved in array"];
and if you are using only date string then you can use

Escape special characters in FMDB iOS query

I wrote a query with arguments in FMDB using ? mark symbol.I want to get details of users who has any of info in the list(hope i can give different info separated by commas in "in" statement in sql). Since my arguments having special symbols, It is throwing error. How to escape there special symbols. I tried different methods but none worked yet
My code is like:
FMResultSet *results = [db executeQuery:#"select details from user where info in(?)",infoList];
while([results next])
{...}
Info is a string combined by different string seperated by commas.For example:
'C-note','Cuban missile crisis, the','cubbyhole','I Love Lucy','I'm a Celebrity ... Get me Out of Here!','Iacocca, Lee','-iana','Ivy League, the'
Thanks in advance
You can't use a single ? with an in clause unless you only bind a single value. It doesn't work for a list of values.
Since infoList is an array of string values, one option is to add a ? for each value in the list.
NSMutableString *query = [NSMutableString stringWithString:#"select details from user where info in ("];
for (NSInteger i = 0; i < infoList.count; i++) {
if (i) {
[query appendString:#","];
}
[query appendString:#"?"];
}
[query appendString:#")"];
FMResultSet *results = [db executeQuery:query withArgumentsInArray:infoList];

FMDB sqlite's sql query not working

I am creating a temp table using the following SQL query. But its not showing any results (result set is empty) when I execute it programmatically, and shows records when I execute it manually on the database.
NSString *query=[NSString stringWithFormat:#"create temp table search2 as select Observationsid from Observations where admin_id=%d AND teacher_id=%d AND observation_type=%d AND isvalid='yes' AND date BETWEEN '12-20-2013' AND '12-23-2013'",appDelegate.admin_id,appDelegate.teacher_id,appDelegate.observationType];
FMResultSet *results=[appDelegate.database executeQuery:query];
Nslogged query:
Printing description of results->_query:
create temp table search2 as select Observationsid from Observations where admin_id=2 AND teacher_id=1 AND observation_type=2 AND isvalid='yes' AND date BETWEEN '12-20-2013' AND '12-23-2013'
and records are there in database.
This SQL statement shouldn't return results, so you should use executeUpdate method rather than a executeQuery method. You should not see any results from this. If you want to see the results, do a separate executeQuery statement returning the results from search2. (I assume you're building the search2 table for a reason.)
NSString *query=[NSString stringWithFormat:#"create temp table search2 as select Observationsid from Observations where admin_id=%d AND teacher_id=%d AND observation_type=%d AND isvalid='yes' AND date BETWEEN '12-20-2013' AND '12-23-2013'",appDelegate.admin_id,appDelegate.teacher_id,appDelegate.observationType];
if (![appDelegate.database executeUpdate:query])
NSLog(#"create error: %#", [appDelegate.database lastErrorMessage]);
query = #"SELECT * FROM search2";
FMResultSet *results = [appDelegate.database executeQuery:query];
if (!results)
NSLog(#"create error: %#", [appDelegate.database lastErrorMessage]);
By the way, while you can get away with stringWithFormat for this particular SQL, that's not a good idea. You generally want to use the ? placeholders, e.g.
NSString *query = #"create temp table search2 as select Observationsid from Observations where admin_id=? AND teacher_id=? AND observation_type=? AND isvalid='yes' AND date BETWEEN '12-20-2013' AND '12-23-2013'";
if (![appDelegate.database executeUpdate:query, #(appDelegate.admin_id), #(appDelegate.teacher_id), #(appDelegate.observationType)])
NSLog(#"create error: %#", [appDelegate.database lastErrorMessage]);
Unrelated, but I notice that you're using MM-DD-YYYY format text string for your dates. That's not going to work. SQLite doesn't natively "understand" dates. Notably, if you've stored your dates in MM-DD-YYYY format, a text string of 12-21-2052 is BETWEEN '12-20-2013' AND '12-23-2013' (because text strings are compared in alphabetically order), which is probably not what you intended. See Date And Time Functions.
But, fortunately, FMDB does the NSDate conversion for you, storing it as numeric value. So, for example, let's assume your table was defined as follows:
CREATE TABLE IF NOT EXISTS Observations
(Observationsid INTEGER PRIMARY KEY AUTOINCREMENT,
admin_id INTEGER,
teacher_id INTEGER,
observation_type INTEGER,
isvalid TEXT,
date REAL);
You really want to use YYYY-MM-DD or, better, rely upon FMDatabase to convert your NSDate values for you. Remember, SQLite does not have proper date formats, so choose an appropriate format (e.g. YYYY-MM-DD format) or let FMDatabase handle this for you, using NSDate objects.
If you want to facilitate the conversion of date strings to dates, you can use a NSDateFormatter, e.g.:
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dateFormat = #"MM-dd-yyyy";
NSDate *someDate = [formatter dateFromString:#"12-22-2013"];
if (![appDelegate.database executeUpdate:#"INSERT INTO Observations (admin_id, teacher_id, observation_type, isvalid, date) VALUES (?, ?, ?, ?, ?)", #(appDelegate.admin_id), #(appDelegate.teacher_id), #(appDelegate.observationType), #"yes", someDate])
NSLog(#"insert error: %#", [appDelegate.database lastErrorMessage]);
Or, if I wanted to select the dates between these two dates:
NSDate *startDate = [formatter dateFromString:#"12-20-2013"];
NSDate *endDate = [formatter dateFromString:#"12-23-2013"];
NSString *query = #"create temp table search2 as select Observationsid, date from Observations where admin_id=? AND teacher_id=? AND observation_type=? AND isvalid='yes' AND date BETWEEN ? AND ?";
if (![appDelegate.database executeUpdate:query, #(appDelegate.admin_id), #(appDelegate.teacher_id), #(appDelegate.observationType), startDate, endDate])
NSLog(#"create error: %#", [appDelegate.database lastErrorMessage]);
query = #"SELECT * FROM search2";
FMResultSet *results = [appDelegate.database executeQuery:query];
if (!results)
NSLog(#"select error: %#", [appDelegate.database lastErrorMessage]);
while ([results next])
NSLog(#"%d %#", [results intForColumnIndex:0], [results dateForColumnIndex:1]);
If you want to avoid this NSDate logic, you could alternatively consciously store dates in a text format in YYYY-MM-DD format. That works, too. Again, see that Date and Time Functions page for a list of valid text formats for dates.

NSFetchResultsController time filtering predicate advice

I need some advice with predicates. In my app I want to have ability to filter results by date. Before I was doing it with having 2 separate predicates and checking if a filter was set.
if (self.isDateFilterSet==[NSNumber numberWithBool:NO])
{
fetchRequest.predicate = [NSPredicate predicateWithFormat:#" whoRecorded.username = %# AND deleted=0", [self.settings.currentUser username]];
}
else
{
fetchRequest.predicate = [NSPredicate predicateWithFormat:#" (whoRecorded.username = %#) AND (deleted = 0) AND (date =>%#) AND (date<=%#)", [self.settings.currentUser username],self.dateMinSetFilter ,self.dateMaxSetFilter];
}
I was cleaning up my code and decided to always keep the dates in the predicate and check for dates on every update. However when I insert new data the delegate methods are not called because date<=%# is not satisfied.
Can you suggest me the correct way of dealing with situations like this?
When the user hasn't specified dates to filter with, don't use the min and max from the database. You know you want everything so set the min to [NSDate distantPast] and the max to [NSDate distantFuture] and then you guarantee to cover everything.
Add a method:
- (void)resetDateFilters {
self.dateMinSetFilter = [NSDate distantPast];
self.dateMaxSetFilter = [NSDate distantFuture];
// destroy the FRC here, delete cache if necessary
}
Call it in view did load (this is initial setup). Call it whenever the user wants to reset filters.

Can't store NSDate from Parse to Core Data

I am trying to store a date field from a PFObject into my date type attribute of a Core Data entity.
coreDataObject.createdAt = [object createdAt];
This is the error XCode is returning : property = "updatedAt"; desired type = NSDate; given type = __NSCFString;
Before doing this I was storing the date as a string and parsing that [object createdAt] and everything was working fine, but now it doesn't recognize it as a NSDate.
I've tried casting in but nothing seems to work.
Any idea?
Note, it's this simple:
NSDate *teste = oneParseRow.createdAt;
NSLog(#"teste is %#", ttt);
Note that:
[oneParseRow objectForKey:#"createdAt"];
or anything similar, simply does not work, in any way. You just have to use .createdAt.
Could you verify in the Parse documentation that the createdAt method returns an NSDate? It seems that it is returning a NSString.
Try this code:
id created = [object createdAt]
coreDataObject.createdAt = created;
Put a breakpoint in the first line and within the debugger inspect the type of object that createdAt is returning. If it is not an NSString instead of NSDate you will have to convert it to a NSDate with a NSDateFormatter.

Resources