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

时间:2014-02-16 13:31:18

标签: ios localization nsdate

我仍然是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等。

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

  1. NSWeekdayCalendarUnit:总是1周日和7周六?不管 设置了哪个语言环境?
  2. 如果我NSLog我的endDate(如下面的代码)或开始日期,它通常是日期和23:00:00,因为我住在时区 GMT + 1。这是对的吗?
  3. 现在到我的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 个答案:

答案 0 :(得分:2)

  

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

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

  

如果我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不是结束 期间,但是下一期的开始。)

半年度期 没有相应的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;
}

编辑:在马丁的帮助下改变了一切。工作,但仍然混淆结束日期+ 1天+1小时的必要性......

+ (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;
    }
}