Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using NSPredicate to fetch exact NSDate from NSManagedObjectContect

I'm trying to fetch results of my entity "MeterReading", which has two properties, "timestamp" and "reading". "timestamp" is an NSDate. I'm now trying to fetch an object with an exact date.

NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"MeterReading" inManagedObjectContext:context];
[request setEntity:entity];
NSLog(@"%f", [self.timestamp timeIntervalSince1970]);

NSPredicate *pre = [NSPredicate predicateWithFormat:@"timestamp == %@", self.timestamp];
NSLog(@"%@", pre);
[request setPredicate:pre];

Now, self.timestamp is passed to another ViewController beforehand, the NSLog shows:

1290264372.210091

The NSPredicate logs

timestamp == CAST(311957172.210091, "NSDate")

First question: Why aren't the two numbers the same?

Second and more important question: In the ManagedContext, I have four entries with dates. If I use "<=" instead of "==", I do get results with a date smaller than the one I passed, including the one I want to have. Why can't I get the one single date with the "==" operator? Can this be related to precision of my dates?

Thanks!

like image 466
denbec Avatar asked Nov 21 '10 12:11

denbec


Video Answer


2 Answers

This is the same issue as floating-point equality checks being inherently unsafe. As floating-point values get passed around, converted, used in arithmetic, etc., they lose accuracy bit by bit. You may have to use a more complex predicate that instead checks for dates within a certain tolerance; for instance,

NSArray *timestamps = [NSArray arrayWithObjects:
    [self.timestamp dateByAddingTimeInterval:-1],
    [self.timestamp dateByAddingTimeInterval:1],
    nil
];

NSPredicate *pre = [NSPredicate predicateWithFormat:@"timestamp BETWEEN %@", timestamps];

which would get you any objects matching your date plus or minus one second.

like image 137
Justin Spahr-Summers Avatar answered Nov 10 '22 21:11

Justin Spahr-Summers


First question: Why aren't the two numbers the same?

Internally, NSDate seems to store a timestamp relative to January 1, 2001, and not January 1, 1970. The number 311957172.210091 probably is the number of seconds since 01/01/2001.

Why can't I get the one single date with the "==" operator? Can this be related to precision of my dates?

I don't know. Have you inspected the SQLite file directly to see which timestamps are stored there?

like image 44
Ole Begemann Avatar answered Nov 10 '22 21:11

Ole Begemann