2010-08-19 16 views
12

es decir .:¿Cómo calcular el primer NSDate de la semana actual?

NSDate *firstDayOfWeek = [[NSDate date] firstDayOfWeek]; 

por ejemplo, hoy en día es Aug 19, me gustaría obtener una NSDate de 2010-08-15 12:00am desde arriba línea de código. ¡Gracias!

+2

su información, una respuesta fácil: http://stackoverflow.com/a/14688780/308315 – iwasrobbed

Respuesta

35

Creo que esto responde a las discusiones lo que estás buscando: sin embargo, que no se ocupa de los lunes como el primer día de la semana http://www.cocoabuilder.com/archive/cocoa/211648-nsdatecomponents-question.html#211826

Nota , por lo que puede tener que modificarlo un poco restando [gregorian firstWeekday] en lugar de solo 1. Además, he modificado para utilizar -currentCalendar, pero es hasta que :-)

NSDate *today = [NSDate date]; 
NSCalendar *gregorian = [NSCalendar currentCalendar]; 

// Get the weekday component of the current date 
NSDateComponents *weekdayComponents = [gregorian components:NSWeekdayCalendarUnit fromDate:today]; 
/* 
Create a date components to represent the number of days to subtract 
from the current date. 
The weekday value for Sunday in the Gregorian calendar is 1, so 
subtract 1 from the number 
of days to subtract from the date in question. (If today's Sunday, 
subtract 0 days.) 
*/ 
NSDateComponents *componentsToSubtract = [[NSDateComponents alloc] init]; 
/* Substract [gregorian firstWeekday] to handle first day of the week being something else than Sunday */ 
[componentsToSubtract setDay: - ([weekdayComponents weekday] - [gregorian firstWeekday])]; 
NSDate *beginningOfWeek = [gregorian dateByAddingComponents:componentsToSubtract toDate:today options:0]; 

/* 
Optional step: 
beginningOfWeek now has the same hour, minute, and second as the 
original date (today). 
To normalize to midnight, extract the year, month, and day components 
and create a new date from those components. 
*/ 
NSDateComponents *components = [gregorian components: (NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) 
              fromDate: beginningOfWeek]; 
beginningOfWeek = [gregorian dateFromComponents: components]; 
+0

+1 ¡Muchas gracias! – Jean

+2

Tenga en cuenta que nombrar su calendario puede ser un poco engañoso. En la mayoría de los casos, el calendario actual será gregoriano, pero no está definido para ninguna configuración regional. En su lugar, solo nombraría el puntero _calendar_. – ff10

+0

Según lo observado por @Wolfgang, esta solución es incorrecta para el caso en que '' 'today''' es anterior a la semana que' '' firstWeekday''' (por ejemplo, firstWeekday = Monday y today = Sunday). – iOSCowboy

10

La solución por naixn producirá resultados erróneos Si el lunes (2) se establece de la firstWeekday y la fecha en que se está inspeccionando es Domingo . En este caso, obtendrá como resultado el lunes de la próxima semana.

La forma correcta sería calcular los componentes resta de la siguiente manera:

[componentsToSubtract setDay: - ((([weekdayComponents weekday] - [gregorian firstWeekday]) 
            + 7) % 7)]; 

Suponiendo que siempre tiene 7 días a la semana.

2
- (NSDate *)firstDateOfWeekWithDate:(NSDate *)date { 

    NSCalendar * calendar = [NSCalendar currentCalendar]; 

    NSDateComponents *weekdayComponents = [calendar components:(NSDayCalendarUnit | NSWeekdayCalendarUnit) fromDate:date]; 

    NSDateComponents *components = [calendar components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSWeekdayCalendarUnit) fromDate:date]; 
    [components setDay:-((([weekdayComponents weekday] - [calendar firstWeekday]) + 5) % 7)]; 

    return [calendar dateFromComponents:components]; 
} 
+0

Extensión agradable ... Esta no funciona si la fecha actual ya es la fecha de inicio de la semana. –

+0

NO puede ser correcto. Si la fecha es el primer día del mes, los componentes no son válidos. –

20

¿Por qué tan complicado? :)

func firstDateOfWeekWithDate(date: NSDate) -> NSDate { 

    var beginningOfWeek: NSDate? 

    calendar.rangeOfUnit(.WeekOfYear, startDate: &beginningOfWeek, interval: nil, forDate: date) 

    return beginningOfWeek! 

} 
+0

Esta es una solución mucho más simple. Puedo verificar que funciona mucho mejor que las soluciones de Wolfgang y Naixn. –

+0

Correcta y precisa. Realmente perfecto. –

+0

Este es el enfoque correcto.Me conecté solo para votar esta :) :) – trapper

1

La solución más simple:

func firstDayOfWeek(date: NSDate) -> NSDate { 
    let calendar = NSCalendar.currentCalendar() 
    var dateComponents = calendar.components(.CalendarUnitYear | .CalendarUnitMonth | .CalendarUnitWeekOfMonth, fromDate: date) 
    dateComponents.weekday = 1 
    return calendar.dateFromComponents(dateComponents)! 
} 
+0

Se me ha terminado una semana: implementé exactamente lo anterior y pasé una fecha = NSDate(); debería haber regresado el 17 de agosto, regresó el 24 de agosto. – cdf1982

+0

Puede intentar '.CaleandarUnitWeekOfYear | .CalendarUnitYearForWeekOfYear', en lugar de '.CalendarUnitYear | .CalendarUnitMonth | .CalendarUnitWeekOfMonth'. Porque una semana puede ser compartida por dos meses o dos años. @ cdf1982, @Vassily –

+0

esto está mal, está perdiendo información como la zona horaria cuando recompone la fecha. – Vassily

1

Esto ya ha sido contestada, pero como Wolfgang has pointed out, hay un error en la respuesta aceptada. Si el primer día de la semana se configura como una fecha mayor que NSDate en cuestión, el resultado será incorrecto. Aquí hay una solución completa que funciona para todos los posibles valores de firstWeekday (el ejemplo usa el lunes).

- (NSDate *)weekOfDate:(NSDate *)originalDate 
{ 
    NSCalendar *currentCal = [NSCalendar currentCalendar]; 
    [currentCal setFirstWeekday:2]; // Sun = 1, Mon = 2, etc. 

    NSDateComponents *weekdayComponents = [currentCal components:NSCalendarUnitWeekday fromDate:originalDate]; 

    // Calculate the number of days to subtract and create NSDateComponents with them. 
    NSDateComponents *componentsToSubtract = [[NSDateComponents alloc] init]; 
    NSInteger daysToSubtract = (([weekdayComponents weekday] - [currentCal firstWeekday]) + 7) % 7; 
    [componentsToSubtract setDay:-1 * daysToSubtract]; 

    return [currentCal dateByAddingComponents:componentsToSubtract toDate:originalDate options:0]; 
} 
Cuestiones relacionadas