How to compare NSDate objects efficiently - performance

I have to compare many managed objects and group them by date. I can't use NSDateComponents because it's too slow to compare two NSDate objects.
How can I compare them in a more efficient way, so that I can save processing time?

I am not sure what kind of comparison you are doing but you can do:
if ( [date1 timeIntervalSince1970] > [date2 timeIntervalSince1970])
{
NSLOG(#"Do something");
}
so if date1 is bigger (further away for 1970!) than date2 the if is true.
This will work quicker than NSDateComponents.

Related

nested for loops in stata

I am having trouble to understand why a for loop construction does not work. I am not really used to for loops so I apologize if I am missing something basic. Anyhow, I appreciate any piece of advice you might have.
I am using a party level dataset from the parlgov project. I am trying to create a variable which captures how many times a party has been in government before the current observation. Time is important, the counter should be zero if a party has not been in government before, even if after the observation period it entered government multiple times. Parties are nested in countries and in cabinet dates.
The code is as follows:
use "http://eborbath.github.io/stackoverflow/loop.dta", clear //to get the data
if this does not work, I also uploaded in a csv format, try:
import delimited "http://eborbath.github.io/stackoverflow/loop.csv", bindquote(strict) encoding(UTF-8) clear
The loop should go through each country-specific cabinet date, identify the previous observation and check if the party has already been in government. This is how far I have got:
gen date2=cab_date
gen gov_counter=0
levelsof country, local(countries) // to get to the unique values in countries
foreach c of local countries{
preserve // I think I need this to "re-map" the unique cabinet dates in each country
keep if country==`c'
levelsof cab_date, local(dates) // to get to the unique cabinet dates in individual countries
restore
foreach i of local dates {
egen min_date=min(date2) // this is to identify the previous cabinet date
sort country party_id date2
bysort country party_id: replace gov_counter=gov_counter+1 if date2==min_date & cabinet_party[_n-1]==1 // this should be the counter
bysort country: replace date2=. if date2==min_date // this is to drop the observation which was counted
drop min_date //before I restart the nested loop, so that it again gets to the minimum value in `dates'
}
}
The code works without an error, but it does not do the job. Evidently there's a mistake somewhere, I am just not sure where.
BTW, it's a specific application of a problem I super often encounter: how do you count frequencies of distinct values in a multilevel data structure? This is slightly more specific, to the extent that "time matters", and it should not just sum all encounters. Let me know if you have an easier solution for this.
Thanks!
The problem with your loop is that it does not keep the replaced gov_counter after the loop. However, there is a much easier solution I'd recommend:
sort country party_id cab_date
by country party_id: gen gov_counter=sum(cabinet_party[_n-1])
This sorts the data into groups and then creates a sum by group, always up to (but not including) the current observation.
I would start here. I have stripped the comments so that we can look at the code. I have made some tiny cosmetic alterations.
foreach i of local dates {
egen min_date = min(date2)
sort country party_id date2
bysort country party_id: replace gov_counter=gov_counter+1 ///
if date2 == min_date & cabinet_party[_n-1] == 1
bysort country: replace date2 = . if date2 == min_date
drop min_date
}
This loop includes no reference to the loop index i defined in the foreach statement. So, the code is the same and completely unaffected by the loop index. The variable min_date is just a constant for the dataset and the same each time around the loop. What does depend on how many times the loop is executed is how many times the counter is incremented.
The fallacy here appears to be a false analogy with constructs in other software, in which a loop automatically spawns separate calculations for different values of a loop index.
It's not illegal for loop contents never to refer to the loop index, as is easy to see
forval j = 1/3 {
di "Hurray"
}
produces
Hurray
Hurray
Hurray
But if you want different calculations for different values of the loop index, that has to be explicit.

Compare two NSDate with .nanosecond granularity

I've tried to compare two NSDate using .nanosecond granularity:
let d1 = date1.absoluteDate // 501178812.31100011 (2016-11-18T16:20:12.311Z)
let d2 = date2.absoluteDate // 501178812.21199989 (2016-11-18T16:20:12.212Z)
let result = Calendar.current.compare(d1, to: d2, toGranularity: .nanosecond) // .orderedSame???
However while nanoseconds are different (d1=31100011 and d2=21199989) the comparison results is .orderedSame.
Is this a bug of NSDate or a precision-related issue?
I'm not sure it's a bug because on docs I've found:
"[NSDate]...makes possible a wide and fine-grained range of date and time
values, giving precision within milliseconds for dates 10,000 years
apart..."
But...why then compare method allows nanosecond as granularity?

How can I compare 2 dates in a Where statement while using NoRM for MongoDB on C#?

I have a table in Mongo. One of the fields is a DateTime. I would like to be able to get all of the records that are only for a single day (i.e. 9/3/2011).
If I do something like this:
var list = (from c in col
where c.PublishDate == DateTime.Now
select c).ToList();
Then it doesn't work because it is using the time in the comparison. Normally I would just compare the ToShortDateString() but NoRM does not allow me to use this.
Thoughts?
David
The best way to handle this is normally to calculate the start datetime and end datetime for the date in question and then query for values in that range.
var start = DateTime.Now.Date;
var end = start.AddDays(1);
...
But you'd also be well advised to switch to the official C# driver now. You should also use UTC datetimes in your database (but that gets more complicated).

Comparing Dates, ignoring year - Linq/Entity Framework

Is there any easy way to compare dates, that ignores year, using Linq and the Entity Framework?
Say I have the following
var result = context.SomeEntity.Where(e => e.SomeDate > startDate);
This is assuming that SomeDate and startDate are .NET DateTime's.
What I would like to do is compare these dates without comparing year. SomeDate can be any year. Is there any easy way to do this? The only way I could think of would be to use the following:
var result = context.SomeEntity(e =>
e.SomeDate.Month > startDate.Month ||
(e.SomeDate.Month == startDate.Month && e.SomeDate.Day >= startDate));
This method quickly gets more complicated if I am looking to have an endDate as well, as I will have to do things like take account for when the start date is at the end of the year and the end date is at the beginning.
Is there any easy way to go about this?
Update:
I ended up just going about it the way I had initially thought in the post... a heck of a lot of code for something conceptually simple. Basically just had to find if a date fell within a range, ignoring year, and looping the calendar if startDate > endDate If anyone knows an easier way, please post as I am still interested.
If you really need to compare only dates (not times) then DateTime.DayOfYear property might help. But you should be careful regarding leap years in this case. Other of this I cannot imagine anything more simple than your approach with comparing months and days.
If all you care about is that this method will become more complicated after introducing second comparison then simple method extraction should help.
Another approach might be creating an extension method which will return a number applicable for your comparison. For example let's call this method GetYearIgnoringOrdinal():
public static int GetYearIgnoringOrdinal(this DateTime date)
{
return date.Month*100 + date.Day;
}
And then use it like this:
var result = context.SomeEntity.Where(e => e.SomeDate.GetYearIgnoringOrdinal() > startDate.GetYearIgnoringOrdinal());
Slightly simpler looking way
var result = context.SomeEntity(e =>
e.SomeDate.Month * 100 + e.SomeDate.Day > startDate.Month * 100 + startDate.Day
);
You could also create a user defined function (assuming SQL server is used) and that function can be used in the query.

Core Data: Generate Unique ID Number

I have a window that looks like so:
Everytime a record is added, I want the repair ID to be set to a unique number that hasn't been used in the table yet. e.g. if there is ID numbers 1,2,3, then when I press +, the ID field should be set to '4'.
Also, if one of the records in the table is deleted, so that the ID numbers are: 1,2,4, then when I press +, the number in the Record ID should be set to 3.
At the moment, I have a custom ManagedObject class, where I declare:
-(void)awakeFromInsert {
[self setValue:[NSDate date] forKey:#"date"];
}
In order to set the date to today's date.
How would I go about implementing this unique record ID?
Thanks!
For a pure autoincrementing ID (like was asked for in this question), something like what's described in this message may do the job. Unfortunately, that won't provide values that fill in the blanks for deleted items in your list.
For small amount of records, simply loop through them until you find a free ID. Pseudocode here since I don't know your language:
int RepairID=1;
While isUsed(RepairID) {
RepairID=RepairID+1;
}
return RepairID;
For large numer of records you can keep track of a list of deleted ID:s and the highest ID. When adding a record pick the smallest deleted ID, or if no deleted ids left to reuse, use the highest ID+1
I've used the numerical form of the date before (with a quick check to make sure it's actually unique - ie, the clock hasn't been adjusted). +[NSDate timeIntervalSinceReferenceDate] returns an NSTimeInterval (which is a typedef double). This I believe is independent of time zones, "daylight saving", etc.
The only weakness, as I alluded earlier, is the clock being adjusted, but you could always make sure it's unique. If you have more requirements than what you listed, let me know. I have a few myself, and what I believe to be sufficient work-arounds.
If your using an Array Controller in your interface you can use the count method on its arrangedObjects array to create your ID. You can implement by overriding your -(id)newObject method
//implemented in yourArrayController.m
-(id)newObject
{
//call the super method to return an object of the entity for the array controller
NSManagedObject* yourNewObject = [super newObject];
//set the ID the count of the arrangedObjects array
NSNumber* theID = [NSNumber numberWithInteger:[[self arrangedObjects] count]];
[yourNewObject setValue:theID forKey:#"ID"];
//return your new Object
return yourNewObject;
}

Resources