问题
My problem is to do with the Time Profile of NSDateComponents operations given in the code snippet below.
- I have a method that iterates over a large array of NSDate objects
- Part of the method requires that I discard the Hour, Minute and seconds of each date.
To do this I have 3 steps:
- I create an NSDateComponents object from my original date.
- I set the H:M:S elements to 0
- I get my new date object that has H:M:S set to 0 as needed
The Issue:
Steps 1 & 3 above are taking a huge percentage of my overall method execution time, 22.4% and 56.8% respectively.
I'm looking for suggestions as to how I might optimize this part of my code or alternative ways of zeroing the H:M:S that might perform better.
NSDate* date = [[NSDate alloc] init];
// Next line takes 22.4% of the overall method execution time
NSDateComponents* components = [calendar components:(NSYearCalendarUnit | NSMonthCalendarUnit
| NSDayCalendarUnit | NSHourCalendarUnit
| NSSecondCalendarUnit) fromDate:date];
[components setHour:0];
[components setMinute:0];
[components setSecond:0];
// Next line takes 56.8% of the overall method execution time
date = [calendar dateFromComponents:components];
回答1:
Update
Clocks:
Time 1: ≈ 0.000139 - Option 1 - Original
Time 2: ≈ 0.000108 - Option 2
Time 3: ≈ 0.000013 - Option 3
Time 4: ≈ 0.000004 - Option 4
Option 1 - Original
NSDate* originDate = [[NSDate alloc] init];
NSDate* date = [[NSDate alloc] init];
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents* components = [calendar components:(NSYearCalendarUnit | NSMonthCalendarUnit
| NSDayCalendarUnit | NSHourCalendarUnit
| NSSecondCalendarUnit) fromDate:date];
[components setHour:0];
[components setMinute:0];
[components setSecond:0];
date = [calendar dateFromComponents:components];
NSLog(@"Time 1: %f", -[originDate timeIntervalSinceNow]);
Option 2
You don't need
[components setHour:0];
[components setMinute:0];
[components setSecond:0];
Just don't even add these as options to date components
NSDate* originDate2 = [[NSDate alloc] init];
NSDate* date2 = [[NSDate alloc] init];
NSCalendar *calendar2 = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents* components2 = [calendar2 components:(NSYearCalendarUnit | NSMonthCalendarUnit
| NSDayCalendarUnit
) fromDate:date2];
date2 = [calendar2 dateFromComponents:components2];
NSLog(@"Time 2: %f", -[originDate2 timeIntervalSinceNow]);
Sources: Similar Question + David's Comment
Option 3
Basically, I found that if I run the method with an already created NSCalendar, I get 85% to 90% faster speed consistently.
Declare calendarProperty and initialize it before you run the method
NSDate* originDate3 = [[NSDate alloc] init];
NSDate* date3 = [[NSDate alloc] init];
NSDateComponents* components3 = [calendarProperty components:(NSYearCalendarUnit | NSMonthCalendarUnit
| NSDayCalendarUnit
) fromDate:date3];
date3 = [calendarProperty dateFromComponents:components3];
NSLog(@"Time 3: %f", -[originDate3 timeIntervalSinceNow]);
Option 4
* based on @HotLicks's comment *
Avoid all those annoying dateComponents all together - about 95% faster
I'm not sure about how consistent Option 4 is in practice, but it's clocking in the fastest and it has been reliable for me so far.
NSDate* originDate4 = [[NSDate alloc] init];
NSDate* date4 = [[NSDate alloc] init];
float date4Interval = [date4 timeIntervalSince1970];
int totalDays = date4Interval / (60 * 60 * 24);
date4 = [NSDate dateWithTimeIntervalSince1970:totalDays * 60 * 60 * 24];
NSLog(@"Time 4: %f", -[originDate4 timeIntervalSinceNow]);
来源:https://stackoverflow.com/questions/22206358/nsdatecomponents-time-profile