Core Data group by NSDate without Time

125 Views Asked by At

I have start Date attribute in core data, and i want to fetch the items along with grouping according to startDate,

But startDate is basically having timeComponent in it, but i want grouping to be based on yyyy-mm-dd,

This is the code i am using

    NSError *error = nil;
    NSFetchRequest *request = [NSFetchRequest new];
    NSManagedObjectContext *context = self.managedObjectContext;
    request.entity = [CalendarItem entityInManagedObjectContext:context];
    NSExpression *startExpr = [NSExpression expressionForKeyPath:@"start"];
    NSExpression *countExpr = [NSExpression expressionForFunction:@"count:" arguments:[NSArray arrayWithObject:startExpr]];
    NSExpressionDescription *exprDesc = [[NSExpressionDescription alloc] init];
    [exprDesc setExpression:countExpr];
    [exprDesc setExpressionResultType:NSInteger64AttributeType];
    [exprDesc setName:@"count"];
    
    [request setPropertiesToGroupBy:@[@"start"]];
    [request setPropertiesToFetch:[NSArray arrayWithObjects:@"start", exprDesc, nil]];
    [request setResultType:NSDictionaryResultType];
    NSArray *results = [self.managedObjectContext executeFetchRequest:request error:&error];

This is the Output i am getting:

Printing description of results:
<_PFArray 0x600001e3a700>(
{
    count = 1;
    start = "2021-09-14 03:30:00 +0000";
},
{
    count = 1;
    start = "2021-09-14 04:00:00 +0000";
},
{
    count = 1;
    start = "2021-09-16 09:30:00 +0000";
},
{
    count = 1;
    start = "2021-11-11 00:00:00 +0000";
},
{
    count = 1;
    start = "2021-11-11 04:00:00 +0000";
},
{
    count = 1;
    start = "2021-11-11 06:00:00 +0000";
},
{
    count = 1;
    start = "2021-11-12 00:00:00 +0000";
}
)

Expected Result:

{
    count = 2
    start = 2021-09-14
}
{
    count = 1
    start = 2021-09-16
}
{
    count = 3
    start = 2021-11-11
}
{
    count = 1;
    start = "2021-11-12
}

1

There are 1 best solutions below

2
Tom Harrington On

Core Data "date" properties, as you've found, are actually timestamps. They include the time of day, even though they're called "date". You can't tell Core Data to use only part of the value of a date attribute-- it's all or nothing.

To get the kind of grouping you want, you need to create another property where the value is only the value you need instead of a timestamp that includes extra details you don't need. Here, that would be a date where the hour, minute, and second are all set to zero, so that those details don't affect grouping.

One way to do this is to make a new date object with that change and save it in a new property. You could call it trimmedDate. Then any time you set the date on an instance, also set trimmedDate, with code that's something like

NSDate *trimmed = [[NSCalendar currentCalendar] dateBySettingHour:0 minute:0 second:0 ofDate:date options:0];

Then use this new value for grouping.