首页 文章

考虑区域设置等的一些NSDate问题

提问于
浏览
1

我仍然是iOS的新手,并且与NSDate有点挣扎 . 基本上我在我的应用程序中有一定的CostPeriods:

CostPeriodDaily
CostPeriodWeekly
CostPeriodMonthly
CostPeriodSemiAnnually
CostPeriodAnnually

根据CostPeriod,我想要特定时期的开始和结束日期 . CostPeriodDaily当然是来自(即今天)16.Feb 2014 00:00:00(当地时间) - 16.Feb 2014 23:59:59(当地时间) . 每月将从01.Feb 2014 00:00:00 - 28.Feb 2014 23:59:59等 .

我首先提出两个具体问题:

  • NSWeekdayCalendarUnit:1个星期天和7个星期六?无论设置什么语言环境?

  • 如果我NSLog我的endDate(如下面的代码)或开始日期,它通常是日期和23:00:00,因为我住在GMT 1时区 . 这是正确的吗?

现在到我的endDate函数,还有两个问题:-)

  • 这个功能一般是否正常,或者我会遇到一些问题,具体取决于具体的区域设置?

  • 我的CostPeriodWeekly案例给了我错误的日期2014-02-15 23:00:00 0000今天 . 我不知道为什么......?

(NSDate *)endDateForCurrentCostPeriod:(CostPeriod)costPeriod {NSCalendar * gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];

NSDateComponents *todayComponents =
[gregorian components:(NSDayCalendarUnit | NSWeekdayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit ) fromDate:[NSDate date]];
NSRange daysOfCurrentMonth = [gregorian rangeOfUnit:NSDayCalendarUnit inUnit:NSMonthCalendarUnit forDate:[NSDate date]];


NSDateComponents *endDateComponents = [[NSDateComponents alloc] init];

switch (costPeriod) {
    case CostPeriodDaily:
        [endDateComponents setDay:[todayComponents day]];
        [endDateComponents setMonth:[todayComponents month]];
        [endDateComponents setYear:[todayComponents year]];
        break;

    case CostPeriodWeekly:
        //Weekday 1 = sunday, 2 = monday
        if([todayComponents weekday] == 1){
            //Sunday -> do nothing, we have the end date
            [endDateComponents setDay:[todayComponents day]];
            [endDateComponents setMonth:[todayComponents month]];
            [endDateComponents setYear:[todayComponents year]];

        } else {
            // all other days of current week, so 8- weekday (if Friday: 8 - 6 = + 2 -> Sunday)
            NSDateComponents *componentsToAdd = [[NSDateComponents alloc] init];
            [componentsToAdd setDay: 8 - [todayComponents weekday]];
            NSDate *endOfWeek = [gregorian dateByAddingComponents:componentsToAdd
                                                                 toDate:[NSDate date] options:0];

            NSDateComponents *endOfWeekComponents = [gregorian components:(NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit) fromDate:endOfWeek];

            [endDateComponents setDay:[endOfWeekComponents day]];
            [endDateComponents setMonth:[endOfWeekComponents month]];
            [endDateComponents setYear:[endOfWeekComponents year]];
        }
        break;

    case CostPeriodMonthly:
        [endDateComponents setDay:daysOfCurrentMonth.length];
        [endDateComponents setMonth:[todayComponents month]];
        [endDateComponents setYear:[todayComponents year]];
        break;

    case CostPeriodSemiAnnually:
        [endDateComponents setYear:[todayComponents year]];

        if([todayComponents month] <= 6){
            [endDateComponents setDay:30];
            [endDateComponents setMonth:6];
        } else {
            [endDateComponents setDay:31];
            [endDateComponents setMonth:12];
        }
        break;

    case CostPeriodAnnually:
        [endDateComponents setDay:31];
        [endDateComponents setMonth:12];
        [endDateComponents setYear:[todayComponents year]];
        break;

    default:
        [endDateComponents setDay:daysOfCurrentMonth.length];
        [endDateComponents setMonth:[todayComponents month]];
        [endDateComponents setYear:[todayComponents year]];
        break;
}

NSDate *endDate = [gregorian dateFromComponents:endDateComponents];
return endDate;

}

1 回答

  • 2

    NSWeekdayCalendarUnit:总是1周日和7周六?无论设置什么语言环境?

    那是正确的 . 但这并不意味着1 =星期天总是被认为是本周的第一天 . NSCalendar 有一个 firstWeekDay 方法,这是依赖于语言环境的 . (例如,在德国,星期一是一周的第一天 . )

    如果我NSLog我的endDate(如下面的代码)或开始日期,它通常是日期和23:00:00,因为我住在GMT 1时区 . 这是正确的吗?

    那是正确的 .

    这个功能一般是否正常,或者我会遇到一些问题,具体取决于具体的区域设置?

    你的方法看起来过于复杂 . 确定您可以使用的时间段

    NSDate *now = [NSDate date];
    NSCalendar *cal = [NSCalendar currentCalendar];
    NSDate *startOfPeriod, *endOfPeriod;
    NSTimeInterval lengthOfPeriod;
    
    NSCalendarUnit unit = NSDayCalendarUnit; // or NSWeekCalendarUnit, NSMonthCalendarUnit, ...
    [cal rangeOfUnit:unit startDate:&startOfPeriod interval:&lengthOfPeriod forDate:now];
    endOfPeriod = [startOfPeriod dateByAddingTimeInterval:lengthOfPeriod]
    

    这应该根据您的语言环境正常工作 . 今天(德国,2月16日,星期日)的当前一周将给出结果

    startOfPeriod =  2014-02-10 00:00:00 CET
    endOfPeriod   =  2014-02-17 00:00:00 CET
    

    因为这周从星期一开始 . (所以实际上 endOfPeriod 不是期末,而是下一期的开始 . )

    对于 semi-annual period ,没有相应的 NSCalendarUnit ,因此您可以按以下步骤操作:

    NSDate *now = [NSDate date];
    NSCalendar *cal = [NSCalendar currentCalendar];
    
    // Compute start and end of the current year (as above):
    NSDate *startOfYear, *endOfYear;
    NSTimeInterval lengthOfYear;
    NSCalendarUnit unit = NSYearCalendarUnit;
    [cal rangeOfUnit:unit startDate:&startOfYear interval:&lengthOfYear forDate:now];
    endOfYear = [startOfYear dateByAddingTimeInterval:lengthOfYear];
    
    // Compute middle of the year:
    NSDateComponents *halfYear = [[NSDateComponents alloc] init];
    NSRange range = [cal rangeOfUnit:NSMonthCalendarUnit inUnit:NSYearCalendarUnit forDate:now];
    halfYear.month = range.length/2;
    NSDate *middleOfYear = [cal dateByAddingComponents:halfYear toDate:startOfYear options:0];
    
    // Compare current date with middle of the year and set start/end of period:
    NSDate *startOfPeriod, *endOfPeriod;
    if ([now compare:middleOfYear] == NSOrderedAscending) {
        startOfPeriod = startOfYear;
        endOfPeriod = middleOfYear;
    } else {
        startOfPeriod = middleOfYear;
        endOfPeriod = endOfYear;
    }
    

    EDIT: Changed everything with the help from Martin to this. Works, but still confused about the end date +1day +1 hour necessity...

    + (NSDate *)startDateForCostPeriod:(CostPeriod)costPeriod withDate:(NSDate *)date
    {
        NSCalendar *calender = [NSCalendar currentCalendar];
        NSDate *startOfPeriod;
        NSTimeInterval lengthOfPeriod;
        //If unit is not initialized here, semi annual throws always a caution message since no unit is initialized there
        NSCalendarUnit unit = NSMonthCalendarUnit;
    
        //For the SemiAnnual period we need date components
        NSDateComponents *todayComponents =
        [calender components:(NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit ) fromDate:date];
        NSDateComponents *startDateComponents = [[NSDateComponents alloc] init];
    
        switch (costPeriod) {
            case CostPeriodDaily:
                unit = NSDayCalendarUnit;
                break;
    
            case CostPeriodWeekly:
                unit = NSWeekCalendarUnit;
                break;
    
            case CostPeriodMonthly:
                unit = NSMonthCalendarUnit;
                break;
    
            case CostPeriodSemiAnnually:
                [startDateComponents setDay:1];
                [startDateComponents setYear:[todayComponents year]];
    
                if([todayComponents month] <= 6){
                    [startDateComponents setMonth:1];
                } else {
                    [startDateComponents setMonth:7];
                }
                break;
    
            case CostPeriodAnnually:
                unit = NSYearCalendarUnit;
                break;
    
            default:
                unit = NSMonthCalendarUnit;
                break;
        }
    
        if(costPeriod != CostPeriodSemiAnnually){
            [calender rangeOfUnit:unit startDate:&startOfPeriod interval:&lengthOfPeriod forDate:date];
            return startOfPeriod;
        } else {
            return [calender dateFromComponents:startDateComponents];
        }
    }
    
    + (NSDate *)endDateForCostPeriod:(CostPeriod)costPeriod withDate:(NSDate *)date
    {
        NSCalendar *calender = [NSCalendar currentCalendar];
        NSDate *startOfPeriod;
        NSTimeInterval lengthOfPeriod;
        //If unit is not initialized here, semi annual throws always a caution message since no unit is initialized there
        NSCalendarUnit unit = NSMonthCalendarUnit;
    
        //For the SemiAnnual period we need date components
        NSDateComponents *todayComponents =
        [calender components:(NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit ) fromDate:date];
        NSDateComponents *endDateComponents = [[NSDateComponents alloc] init];
    
        switch (costPeriod) {
            case CostPeriodDaily:
                unit = NSDayCalendarUnit;
                break;
    
            case CostPeriodWeekly:
                unit = NSWeekCalendarUnit;
                break;
    
            case CostPeriodMonthly:
                unit = NSMonthCalendarUnit;
                break;
    
            case CostPeriodSemiAnnually:
                [endDateComponents setYear:[todayComponents year]];
    
                if([todayComponents month] <= 6){
                    [endDateComponents setDay:30];
                    [endDateComponents setMonth:6];
                } else {
                    [endDateComponents setDay:31];
                    [endDateComponents setMonth:12];
                }
                break;
    
            case CostPeriodAnnually:
                unit = NSYearCalendarUnit;
                break;
    
            default:
                unit = NSMonthCalendarUnit;
                break;
        }
    
        if(costPeriod != CostPeriodSemiAnnually){
            [calender rangeOfUnit:unit startDate:&startOfPeriod interval:&lengthOfPeriod forDate:date];
            return [startOfPeriod dateByAddingTimeInterval:lengthOfPeriod];
        } else {
            //somehow if you take the date without a time it is always 1 day and 1 hour before. i.e. 16.2.2014 is 15.2.2014 22:00:00
            //thats why you need to add 1 day and 1 hour!
            NSDate *endDate = [calender dateFromComponents:endDateComponents];
            NSDateComponents *componentsToAdd = [[NSDateComponents alloc] init];
            [componentsToAdd setDay: 1];
            [componentsToAdd setHour: 1];
            endDate = [calender dateByAddingComponents:componentsToAdd
                                                 toDate:endDate options:0];
    
            return endDate;
        }
    }
    

相关问题