NSDateFormatter сообщает, что 2 июня 2013 г. приходится на нулевую неделю.

Я использую NSDateFormatter для преобразования ряда дат в номер недели в течение месяца.

Я использую код форматирования даты yyyyMMW, и все, что я прочитал, говорит мне, что W будет между 1-5.

Но 2 июня 2013 года выпало на воскресенье (день начала недели по умолчанию в григорианском календаре), и его номер недели сообщается как 0, хотя дата начала недели рассчитана правильно:

2013-06-03 14:15:45.611 date=20130531, week=2013055, start of week=20130526
2013-06-03 14:15:45.612 date=20130602, week=2013060, start of week=20130602
2013-06-03 14:15:45.612 date=20130603, week=2013061, start of week=20130602

Некоторый быстрый и грязный тестовый код для воспроизведения журнала, показанного выше:

    NSDateFormatter *dateFormatDaily = [[NSDateFormatter alloc] init];
[dateFormatDaily setDateFormat:@"yyyyMMdd"];
NSDateFormatter *dateFormatterWeekly = [[NSDateFormatter alloc] init];
[dateFormatterWeekly setDateFormat:@"yyyyMMW"];

NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
[calendar setFirstWeekday:1]; // default but set here for clarity

NSDateComponents *dateComponents = [[NSDateComponents alloc] init];
[dateComponents setMonth:5];
[dateComponents setDay:31];
[dateComponents setYear:2013];
NSDate *date_1 = [calendar dateFromComponents:dateComponents];
[dateComponents setMonth:6];
[dateComponents setDay:2];
NSDate *date_2 = [calendar dateFromComponents:dateComponents];
[dateComponents setDay:3];
NSDate *date_3 = [calendar dateFromComponents:dateComponents];
NSArray *datesToTest = @[date_1, date_2, date_3];

for (NSDate *date in datesToTest) {
    NSString *weekNo = [dateFormatterWeekly stringFromDate:date];
    NSDate *beginningOfWeek = nil;
    BOOL rc = [calendar rangeOfUnit:NSWeekCalendarUnit startDate:&beginningOfWeek interval:NULL forDate:date];
    if (rc) {
        NSLog(@"date=%@, week=%@, start of week=%@", [dateFormatDaily stringFromDate:date], weekNo, [dateFormatDaily stringFromDate:beginningOfWeek]);
    } else {
        NSLog(@"Could not calculate beginning of week");
    }
}

Любые идеи? Номер недели 0 при любых обстоятельствах кажется мне неправильным.

Спасибо


person Ianp    schedule 03.06.2013    source источник
comment
+1 за полный автономный код, демонстрирующий проблему!   -  person Martin R    schedule 03.06.2013


Ответы (1)


Существуют различные параметры, вызывающие этот эффект. Прежде всего, вы не установили календарь для средства форматирования даты. Если вы добавите

[dateFormatterWeekly setCalendar:calendar];

к вашему коду, то вывод будет таким, как вы ожидали:

date=20130531, week=2013055, start of week=20130526
date=20130602, week=2013062, start of week=20130602
date=20130603, week=2013062, start of week=20130602

Но в вашем случае средство форматирования даты использует текущий календарь и поэтому имеет отдельные параметры firstWeekDay и minimumDaysInFirstWeek. Эти параметры зависят от локали. Если я проверю это на симуляторе iOS с параметром «Формат региона», установленным на «Немецкий -> Германия», тогда

[[dateFormatterWeekly calendar] firstWeekday]           = 2
[[dateFormatterWeekly calendar] minimumDaysInFirstWeek] = 4

и я предполагаю, что у вас будут аналогичные значения, потому что теперь я получаю тот же результат, что и вы.

Теперь для средства форматирования даты неделя начинается в понедельник, что означает, что 2 июня приходится на неделю, начинающуюся 27 мая. Это считается «неделей № 0» в июне, потому что только один день эта неделя в июне, но minimumDaysInFirstWeek = 4. Первая неделя месяца, в котором не менее minimumDaysInFirstWeek дней, считается "неделей №1".

(Я обнаружил актуальность параметра minimumDaysInFirstWeek здесь: http://www.cocoabuilder.com/archive/cocoa/326845-week-of-month-confusion.html)

person Martin R    schedule 03.06.2013
comment
Спасибо, Мартин Р. - ваш ответ очень полезен и заставляет меня понять, что использование номера недели в месяце - неправильный способ сделать то, что мне нужно. - person Ianp; 04.06.2013