Code Snippet: NSDate Floor and Ceiling
May 25th, 2011Overview
In Stone Hill Time Card, you select a date range using an NSDatePicker. Unfortunately, NSDatePicker gives back the dates selected with the time component set to the time the app was launched. If you want to use the dates you get from the date picker in an NSPredicate to filter between the dates selected, you need to find out the NSDate value for a chosen date at 00:00:00 and 23:59:59.
NSDate+DateFloor+DateCeil is a category on NSDate that adds two methods to take care of this. Given an instance of NSDate someDate that contains the date 2011-05-25 11:00:07 -0700:, you can call
[someDate floor] to get an NSDate instance containing 2011-05-25 00:00:00 -0700
and
[someDate ceil] to get an NSDate instance containing 2011-05-25 23:59:59 -0700
Implementation
Date+DateFloor+DateCeil.h
@interface NSDate (DateFloorAndDateCeil)
- (NSDate *) floor;
- (NSDate *) ceil;
@end
Date+DateFloor+DateCeil.m
@implementation NSDate (DateFloorAndDateCeil)
// Note: This implementation assumes 60 minutes in an hour, 60 seconds in a minute, and 24 hours in a day
// Not for use on Mars.
// Assumes we’re using the gregorian calendar.
- (NSDate *) floor {
// Returns an NSDate that is the same day as the receiver, but
// with a time component of 00:00:00
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *overshootComponents = [gregorian components:NSHourCalendarUnit|NSMinuteCalendarUnit|NSSecondCalendarUnit fromDate:self];
NSTimeInterval overshotByHours = [overshootComponents hour] * 60 * 60;
NSTimeInterval overshotByMinutes = [overshootComponents minute] * 60;
NSTimeInterval overshotBySeconds = [overshootComponents second];
NSTimeInterval interval = [self timeIntervalSinceReferenceDate];
NSTimeInterval floorInterval = interval – overshotByHours – overshotByMinutes – overshotBySeconds;
NSDate *floorDate = [[[NSDate alloc] initWithTimeIntervalSinceReferenceDate:floorInterval] autorelease];
return floorDate;
}
- (NSDate *) ceil {
// Returns an NSDate that is the same day as the receiver, but
// with a time component of 11:59:59
NSDate *floorDate = [self floor];
NSTimeInterval secondsInADay = 86400;
NSDate *ceilDate = [floorDate dateByAddingTimeInterval:secondsInADay-1];
return ceilDate;
}
@end
You can also download a sample XCode project with this category.
Attribution
Attribution All source is released free of charge. You may incorporate it into any of your applications. I assume no liability for any action that may come from you using this source. If you do use this in your application, I’d like a mention in your about box, but I don’t require it. Don’t forget to drop me an email at warwick@codehackers.net so I know when to stroke my ego.



