Hay dos partes en este
:
que voy a tirar de otros dos puestos para ayudarme.
Para los fines de semana, voy a necesitar saber el día de una determinada fecha de la semana. Por eso, este post viene muy bien: How to check what day of the week it is (i.e. Tues, Fri?) and compare two NSDates?
Para vacaciones, @vikingosegundo tiene una muy gran sugerencia sobre esta entrada: List of all American holidays as NSDates
En primer lugar, vamos a tratar con los fines de semana;
he envuelto la sugerencia en el post que he citado anteriormente en este pequeño función auxiliar que nos dice si una fecha es un día de la semana:
BOOL isWeekday(NSDate * date)
{
int day = [[[NSCalendar currentCalendar] components:NSWeekdayCalendarUnit fromDate:date] weekday];
const int kSunday = 1;
const int kSaturday = 7;
BOOL isWeekdayResult = day != kSunday && day != kSaturday;
return isWeekdayResult;
}
Vamos a necesitar una manera de incrementar una fecha por un número determinado de días:
NSDate * addDaysToDate(NSDate * date, int days)
{
NSDateComponents * components = [[NSDateComponents alloc] init];
[components setDay:days];
NSDate * result = [[NSCalendar currentCalendar] dateByAddingComponents:components toDate:date options:0];
[components release];
return result;
}
necesitamos una manera de pasar por alto los fines de semana:
NSDate * ensureDateIsWeekday(NSDate * date)
{
while (!isWeekday(date))
{
// Add one day to the date:
date = addDaysToDate(date, 1);
}
return date;
}
y necesitamos una manera de añadir un número arbitrario de días a una fecha:
NSDate * addBusinessDaysToDate(NSDate * start, int daysToAdvance)
{
NSDate * end = start;
for (int i = 0; i < daysToAdvance; i++)
{
// If the current date is a weekend, advance:
end = ensureDateIsWeekday(end);
// And move the date forward by one day:
end = addDaysToDate(end, 1);
}
// Finally, make sure we didn't end on a weekend:
end = ensureDateIsWeekday(end);
return end;
}
- Nota; Hay una optimización obvia que salté, podría agregar fácilmente más de un día a la fecha actual, pero el objetivo de mi publicación es mostrarle cómo hacerlo usted mismo, y no necesariamente para llegar a la mejor manera posible. solución.
Ahora vamos a atar eso y ver lo que tenemos hasta ahora:
int main() {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSDate * start = [NSDate date];
int daysToAdvance = 10;
NSDate * end = addBusinessDaysToDate(start, daysToAdvance);
NSLog(@"Result: %@", [end descriptionWithCalendarFormat:@"%Y-%m-%d"
timeZone:nil
locale:nil]);
[pool drain];
return 0;
}
Por lo tanto, tenemos cubiertas fines de semana, ahora tenemos que tirar en las vacaciones.
Sacar algunos datos RSS o datos de otra fuente está definitivamente fuera del alcance de mi publicación ... así que, supongamos que tiene algunas fechas que usted sabe que son vacaciones o, de acuerdo con su calendario de trabajo, son días apagado.
Ahora, voy a hacer esto con un NSArray ... pero, una vez más, deja mucho espacio para mejorar, como mínimo debe ser ordenado. Mejor aún, algún tipo de hash configurado para búsquedas rápidas de fechas. Pero, este ejemplo debería ser suficiente para explicar el concepto. (Aquí se construye una matriz que indica que hay dos días de fiesta y tres días a partir de ahora)
NSMutableArray * holidays = [[NSMutableArray alloc] init];
[holidays addObject:addDaysToDate(start, 2)];
[holidays addObject:addDaysToDate(start, 3)];
Y, la puesta en práctica de este va a ser muy similar a los fines de semana. Nos aseguraremos de que el día no sea feriado. Si es así, avanzaremos al día siguiente. Por lo tanto, una colección de métodos para ayudar con lo siguiente:
BOOL isHoliday(NSDate * date, NSArray * holidays)
{
BOOL isHolidayResult = NO;
const unsigned kUnits = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit;
NSDateComponents * components = [[NSCalendar currentCalendar] components:kUnits fromDate:date];
for (int i = 0; i < [holidays count]; i++)
{
NSDate * holiday = [holidays objectAtIndex:i];
NSDateComponents * holidayDateComponents = [[NSCalendar currentCalendar] components:kUnits fromDate:holiday];
if ([components year] == [holidayDateComponents year]
&& [components month] == [holidayDateComponents month]
&& [components day] == [holidayDateComponents day])
{
isHolidayResult = YES;
break;
}
}
return isHolidayResult;
}
y:
NSDate * ensureDateIsntHoliday(NSDate * date, NSArray * holidays)
{
while (isHoliday(date, holidays))
{
// Add one day to the date:
date = addDaysToDate(date, 1);
}
return date;
}
Y, por último, hacer algunas modificaciones a nuestra función además de tener en cuenta los días festivos:
NSDate * addBusinessDaysToDate(NSDate * start, int daysToAdvance, NSArray * holidays)
{
NSDate * end = start;
for (int i = 0; i < daysToAdvance; i++)
{
// If the current date is a weekend, advance:
end = ensureDateIsWeekday(end);
// If the current date is a holiday, advance:
end = ensureDateIsntHoliday(end, holidays);
// And move the date forward by one day:
end = addDaysToDate(end, 1);
}
// Finally, make sure we didn't end on a weekend or a holiday:
end = ensureDateIsWeekday(end);
end = ensureDateIsntHoliday(end, holidays);
return end;
}
Adelante, pruébelo:
int main() {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSDate * start = [NSDate date];
int daysToAdvance = 10;
NSMutableArray * holidays = [[NSMutableArray alloc] init];
[holidays addObject:addDaysToDate(start, 2)];
[holidays addObject:addDaysToDate(start, 3)];
NSDate * end = addBusinessDaysToDate(start, daysToAdvance, holidays);
[holidays release];
NSLog(@"Result: %@", [end descriptionWithCalendarFormat:@"%Y-%m-%d"
timeZone:nil
locale:nil]);
[pool drain];
return 0;
}
Si quieres todo el proyecto, aquí tienes: http://snipt.org/xolnl
salte los fines de semana y las vacaciones usted mismo. –