NSWeekdayCalendarUnit: Is 1 ALWAYS Sunday and 7 Saturday? No matter what locale is set?
That is correct. But that does not mean that 1=Sunday is always considered to be the first day in the week. NSCalendar
has a firstWeekDay
method, and that
is locale dependent. (For example, in Germany Monday is the first day of the week.)
If I NSLog my endDate (as in the following code) or start date it usually is the date and 23:00:00 since I'm living in the time zone GMT+1. Is this correct?
That is correct.
Is this function in general ok or will I run in some problems depending on specific locale settings?
Your method looks overly complicated. To determine a period you can use
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]
That should work correctly according to your locale. For the current week of today (Sunday, Feb 16) in Germany that would give the results
startOfPeriod = 2014-02-10 00:00:00 CET
endOfPeriod = 2014-02-17 00:00:00 CET
because the week starts on a Monday here. (So actually endOfPeriod
is not the end
of the period, but the start of the following period.)
For the semi-annual period
there is no corresponding NSCalendarUnit
, so you could proceed as follows:
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;
}
}