Вычисление даты первого дня недели для даты первой недели года изменяет месяц

Мне нужно получить дату первого дня недели с любой даты. Этот код работает нормально, но для некоторых дат я получаю очень странный результат. Дата первой недели года преобразуется в дату прошлой недели:

NSTimeInterval ti = 1420311299;
NSDate* date = [NSDate dateWithTimeIntervalSince1970:ti];

NSLog(@"%@", date); // OUTPUT: 2015-01-03 18:54:59 +0000

NSCalendar* calendar = [NSCalendar currentCalendar];
NSDateComponents *cmps = [calendar components:(kCFCalendarUnitWeekOfYear | kCFCalendarUnitYear) fromDate:date];

cmps.weekday = calendar.firstWeekday;

NSLog(@"%@", cmps); // OUTPUT:  Calendar Year: 2015
                    //          Week of Year: 1
                    //          Weekday: 1



NSDate* newDate = [calendar dateFromComponents:cmps];

NSLog(@"%@", newDate); // OUTPUT: 2015-12-26 22:00:00 +0000

person oxigen    schedule 17.07.2015    source источник


Ответы (1)


Класс NSCalendar предлагает специальные методы для выполнения таких вычислений:

NSDate *date =...;
NSDate *startOfTheWeek;
NSTimeInterval interval;
[[NSCalendar currentCalendar] rangeOfUnit:NSCalendarUnitWeekOfMonth
                                startDate:&startOfTheWeek 
                                 interval:&interval 
                                  forDate:date];

interval содержит продолжительность недели. Если вам это не нужно, вы можете просто передать NULL.

NSDate *date =...;
NSDate *startOfTheWeek;
[[NSCalendar currentCalendar] rangeOfUnit:NSCalendarUnitWeekOfMonth 
                                startDate:&startOfTheWeek 
                                 interval:NULL
                                  forDate:date];

Чтобы ответить на ваш первоначальный вопрос: начало и конец недели не совпадают с годами. 1, 2 и 3 января могут приходиться на 53-ю неделю предыдущего года. 29, 30, 31 декабря могут приходиться на первую неделю следующего года. Правило таково: если четверг этой недели приходится на декабрь, то неделя относится к старому году. Если это январь, то это первая неделя нового года.


Каждый разработчик Mac/iOS должен посмотреть: Видео WWDC 2011 "Session 117 — Выполнение расчетов календаря" "

person vikingosegundo    schedule 17.07.2015
comment
Спасибо. Я попробую. О 2-й части. Как вы видите в моем примере, 3 января приходится на 53 неделю ТЕКУЩЕГО 2015 года. И я не могу понять, как это возможно... - person oxigen; 17.07.2015
comment
Звучит странно, но это ожидаемое поведение. Даже Apple вмешивается в эту проблему дважды: будильник не срабатывает первые несколько дней в году. - person vikingosegundo; 17.07.2015