How can I generate convenient date ranges based on a given NSDate?

喜夏-厌秋 提交于 2019-12-20 09:38:18

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!