问题
I'm creating a report generator in Cocoa, and I need to produce convenient date ranges such as "Today", "This Week", "This Month", "This Year", etc.
Is there a good way to do this? Here is my skeleton thus far:
@interface DateRange : NSObject
{
NSDate startDate;
NSDate endDate;
}
@property (nonatomic, retain) NSDate * startDate;
@property (nonatomic, retain) NSDate * endDate;
+ (DateRange *)rangeForDayContainingDate:(NSDate *)date;
+ (DateRange *)rangeForWeekContainingDate:(NSDate *)date;
+ (DateRange *)rangeForMonthContainingDate:(NSDate *)date;
+ (DateRange *)rangeForYearContainingDate:(NSDate *)date;
@end
Some example use cases would be as follows:
DateRange * thisWeek = [DateRange rangeForWeekContainingDate:[NSDate date]];
DateRange * thisYear = [DateRange rangeForYearContainingDate:[NSDate date]];
Essentially, I want the returned DateRange
object to contain the start and end dates for the week, month or year surrounding the target date. For example (in pseudocode):
NSDate * today = [August 25, 2009];
DateRange * thisWeek = [DateRange rangeForWeekContainingDate:today];
assert(thisWeek.startDate == [August 23, 3009]);
assert(thisWeek.endDate == [August 29, 3009]);
update:
I was able to get this working thanks to the answer provided by Kendall Helmstetter Geln. Here is the complete method for a one-week range:
+ (DateRange *)rangeForWeekContainingDate:(NSDate *)date
{
DateRange * range = [[self alloc] init];
// start of the week
NSDate * firstDay;
[[self calendar] rangeOfUnit:NSWeekCalendarUnit
startDate:&firstDay
interval:0
forDate:date];
[range setStartDate:firstDay];
// end of the week
NSDateComponents * oneWeek = [[NSDateComponents alloc] init];
[oneWeek setWeek:1];
[range setEndDate:[[self calendar] dateByAddingComponents:oneWeek
toDate:firstDay
options:0]];
[oneWeek release];
return [range autorelease];
}
回答1:
Well since timeInterval is in seconds, just do the math to figure out how many seconds are in a day:
60 seconds * 60 minutes * 24 hours = 1 day.
Then in your rangeForDayContainingDate
method you could extract date components, get the current day, create a new date based on the day with hours and minutes set to 0:00, and the create the end date adding the time interval as calculated above.
回答2:
For the sake of completeness, here is my final solution (with thanks to Kendall Helmstetter Geln and jbrennan):
+ (NSCalendar *)calendar
{
NSCalendar * gregorian = [[NSCalendar alloc]
initWithCalendarIdentifier:NSGregorianCalendar];
return [gregorian autorelease];
}
////////////////////////////////////////////////////////////////
+ (NSDateComponents *)singleComponentOfUnit:(NSCalendarUnit)unit
{
NSDateComponents * component = [[NSDateComponents alloc] init];
switch (unit)
{
case NSDayCalendarUnit: [component setDay:1]; break;
case NSWeekCalendarUnit: [component setWeek:1]; break;
case NSMonthCalendarUnit: [component setMonth:1]; break;
case NSYearCalendarUnit: [component setYear:1]; break;
}
return [component autorelease];
}
////////////////////////////////////////////////////////////////
+ (WM_DateRange *)rangeForUnit:(NSCalendarUnit)unit
surroundingDate:(NSDate *)date
{
WM_DateRange * range = [[self alloc] init];
// start of the period
NSDate * firstDay;
[[self calendar] rangeOfUnit:unit
startDate:&firstDay
interval:0
forDate:date];
[range setStartDate:firstDay];
// end of the period
[range setEndDate:[[self calendar]
dateByAddingComponents:[self singleComponentOfUnit:unit]
toDate:firstDay
options:0]];
return [range autorelease];
}
////////////////////////////////////////////////////////////////
+ (WM_DateRange *)rangeForDayContainingDate:(NSDate *)date
{ return [self rangeForUnit:NSDayCalendarUnit surroundingDate:date]; }
+ (WM_DateRange *)rangeForWeekContainingDate:(NSDate *)date
{ return [self rangeForUnit:NSWeekCalendarUnit surroundingDate:date]; }
+ (WM_DateRange *)rangeForMonthContainingDate:(NSDate *)date
{ return [self rangeForUnit:NSMonthCalendarUnit surroundingDate:date]; }
+ (WM_DateRange *)rangeForYearContainingDate:(NSDate *)date
{ return [self rangeForUnit:NSYearCalendarUnit surroundingDate:date]; }
////////////////////////////////////////////////////////////////
- (void)dealloc
{
[endDate release];
[startDate release];
[super dealloc];
}
来源:https://stackoverflow.com/questions/1330798/how-can-i-generate-convenient-date-ranges-based-on-a-given-nsdate