Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sort Array By Date Using Only Time?

I'm currently sorting an array of objects with a property startTime however I have realised that it is sorting by day and time.

So if I add an object and set the time to something earlier than a pre made one, if its made more than a day later it will always be listed after the other. Make sense?

So lets say my NSDate is Tuesday 25th 6:02PM. I want to scratch the Tuesday 26th bit and only sort by time, the day doesn't matter to me. How can I do this?

Thanks.

P.S This is how I am currently sorting my objects:

NSSet *tasks = [self.routine task];
    NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:@"startTime" ascending:YES];
    NSArray *sorted = [[tasks allObjects] sortedArrayUsingDescriptors:[NSArray arrayWithObject:sort]];
like image 738
Josh Kahane Avatar asked Sep 21 '26 23:09

Josh Kahane


2 Answers

Create a category on NSDate that returns the time interval since the start of the day for the current calendar and time zone, and then use that time interval to do your sorting.

@interface NSDate (CBVAdditions)

- (NSTimeInterval)cbvTimeIntervalSinceStartOfDay;

@end

@implementation NSDate (CBVAdditions)

- (NSTimeInterval)cbvTimeIntervalSinceStartOfDay
{
    NSCalendar *calendar = [NSCalendar currentCalendar];
    NSTimeZone *timeZone = [NSTimeZone defaultTimeZone];
    NSDateComponents *dateComponents = [calendar components:(NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit) fromDate:self];
    [dateComponents setCalendar:calendar];
    [dateComponents setTimeZone:timeZone];
    NSInteger hoursComponent = dateComponents.hour * 3600;
    NSInteger minutesComponent = dateComponents.minute * 60;
    double secondsComponent = dateComponents.second;
    NSTimeInterval toReturn = hoursComponent + minutesComponent + secondsComponent;
    return toReturn;
}

@end

Then, you can use NSSortDescriptor with a key like @"dateProperty.cbvTimeIntervalSinceStartOfDay" to do the actual sorting. For example, I show the Event class, and some code that accomplishes the sort.

@interface Event : NSObject

@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSDate *eventDate;

@end

@implementation Event

- (NSString *)description
{
    NSString *desc = [NSString stringWithFormat:@"%@, name = %@, eventDate = %@",[super description], self.name, [self.eventDate descriptionWithLocale:[NSLocale currentLocale]]];
    return desc;
}
@end

...

Event *e1 = [Event new];
e1.eventDate = [NSDate date];
e1.name = @"e1";
Event *e2 = [Event new];
e2.eventDate = [NSDate dateWithTimeIntervalSinceNow:(-1 * 22 * 3600)];
e2.name = @"e2";
Event *e3 = [Event new];
e3.eventDate = [NSDate dateWithTimeIntervalSinceNow:3600];
e3.name = @"e3";

NSArray *events = @[e1,e2,e3];
NSLog(@"Events = %@", events);
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"eventDate.cbvTimeIntervalSinceStartOfDay" ascending:YES];
NSArray *sortedEvents = [events sortedArrayUsingDescriptors:@[sortDescriptor]];
NSLog(@"Sorted Events = %@", sortedEvents);

Executing this code presented the following output:

2013-01-15 15:50:54.221 DateSortingFun[67319:c07] Events = (
    "<Event: 0x717b050>, name = e1, eventDate = Tuesday, January 15, 2013, 3:50:54 PM Mountain Standard Time",
    "<Event: 0x717b620>, name = e2, eventDate = Monday, January 14, 2013, 5:50:54 PM Mountain Standard Time",
    "<Event: 0x717b650>, name = e3, eventDate = Tuesday, January 15, 2013, 4:50:54 PM Mountain Standard Time" ) 


2013-01-15 15:50:54.222 DateSortingFun[67319:c07] Sorted Events = (
    "<Event: 0x717b050>, name = e1, eventDate = Tuesday, January 15, 2013, 3:50:54 PM Mountain Standard Time",
    "<Event: 0x717b650>, name = e3, eventDate = Tuesday, January 15, 2013, 4:50:54 PM Mountain Standard Time",
    "<Event: 0x717b620>, name = e2, eventDate = Monday, January 14, 2013, 5:50:54 PM Mountain Standard Time" )
like image 168
Carl Veazey Avatar answered Sep 24 '26 18:09

Carl Veazey


use comparison blocks. and in the block create a new data with year, month and date set to the same day. that do a normal compare on those dates.

    NSDateComponents *comps = [[NSDateComponents alloc] init];
    comps.year = 2007;
    comps.month = 12;
    comps.day = 3;
    comps.hour = 12;
    comps.minute = 3;

    NSDate *date1 = [[NSCalendar currentCalendar] dateFromComponents:comps];

    comps.year = 2012;
    comps.month = 9;
    comps.day = 7;
    comps.hour = 11;
    comps.minute = 13;

    NSDate *date2 = [[NSCalendar currentCalendar] dateFromComponents:comps];

    comps.year = 2021;
    comps.month = 12;
    comps.day = 3;
    comps.hour = 12;
    comps.minute = 5;

    NSDate *date3 = [[NSCalendar currentCalendar] dateFromComponents:comps];

    comps.year = 2021;
    comps.month = 12;
    comps.day = 3;
    comps.hour = 13;
    comps.minute = 5;


    NSDate *date4 = [[NSCalendar currentCalendar] dateFromComponents:comps];

    NSArray *dates = @[date1, date2, date3, date4];

    NSArray *oderedByTimeOnlyDates = [dates sortedArrayUsingComparator:^NSComparisonResult(NSDate *d1, NSDate *d2) {
        NSDateComponents *comps1 = [[NSCalendar currentCalendar] components:(NSHourCalendarUnit| NSMinuteCalendarUnit | NSSecondCalendarUnit)
                                                                  fromDate:d1];
        NSDateComponents *comps2 = [[NSCalendar currentCalendar] components:(NSHourCalendarUnit| NSMinuteCalendarUnit | NSSecondCalendarUnit)
                                                                   fromDate:d2];

        NSDate *date1 = [[NSCalendar currentCalendar] dateFromComponents:comps1];
        NSDate *date2 = [[NSCalendar currentCalendar] dateFromComponents:comps2];
        return [date1 compare:date2];
    }];

    NSLog(@"%@", oderedByTimeOnlyDates);

output:

(
    "2012-09-07 09:13:00 +0000",
    "2007-12-03 11:03:00 +0000",
    "2021-12-03 11:05:00 +0000",
    "2021-12-03 12:05:00 +0000"
)

The output is in UTC time, while they were created in UTC+1.

like image 33
vikingosegundo Avatar answered Sep 24 '26 16:09

vikingosegundo



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!