NSCalendar первый день недели

Кто-нибудь знает, есть ли способ установить первый день недели в NSCalendar или есть ли в календаре уже понедельник в качестве первого дня недели, а не воскресенье. В настоящее время я работаю над приложением, которое рассчитано примерно на неделю работы, и его нужно запускать в понедельник, а не в воскресенье. Скорее всего, я смогу поработать, чтобы обойти это, но будет много угловых случаев. Я бы предпочел, чтобы платформа сделала это за меня.

заранее спасибо

Вот код, который я использую. Сейчас суббота, поэтому я надеюсь, что в будний день будет 6, а не 7. Это будет означать, что воскресенье будет 7, вместо того, чтобы переходить на 0.

NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
[gregorian setFirstWeekday:0];
unsigned unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit |  NSDayCalendarUnit | NSWeekCalendarUnit | NSWeekdayCalendarUnit;
NSDateComponents *todaysDate = [gregorian components:unitFlags fromDate:[NSDate date]];
int dayOfWeek = todaysDate.weekday;

person Joshua    schedule 09.07.2009    source источник
comment
Ну что, вы еще не нашли решения? Меня поражает то же самое!   -  person Raj Pawan Gumdal    schedule 04.10.2010
comment
В календаре ISO 8601 первый день недели по умолчанию установлен на понедельник.   -  person Christian Schnorr    schedule 25.07.2014


Ответы (17)


Изменить: при этом не проверяется крайний случай, когда начало недели начинается в предыдущем месяце. Некоторый обновленный код для этого: https://stackoverflow.com/a/14688780/308315


Если кто-то все еще обращает на это внимание, вам нужно использовать

ordinalityOfUnit:inUnit:forDate:

и установите для firstWeekday значение 2. (1 == воскресенье и 7 == суббота)

Вот код:

NSCalendar *gregorian = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease];
[gregorian setFirstWeekday:2]; // Sunday == 1, Saturday == 7
NSUInteger adjustedWeekdayOrdinal = [gregorian ordinalityOfUnit:NSWeekdayCalendarUnit inUnit:NSWeekCalendarUnit forDate:[NSDate date]];
NSLog(@"Adjusted weekday ordinal: %d", adjustedWeekdayOrdinal);

Помните, что порядковые номера для будних дней начинаются с 1 для первого дня недели, а не с нуля.

Ссылка на документацию.

person Kris Markel    schedule 11.02.2011
comment
Отличный ответ, это настоящая сделка! - person Rafael Nobre; 16.06.2011
comment
То же самое. Отличный ответ, это правильный путь! - person Norman G; 15.01.2012
comment
@Joshua, это правильный ответ, проверьте и отметьте ответ. - person Andres Canella; 03.09.2012
comment
По какой-то причине при выполнении: [gregorian components:NSYearForWeekOfYearCalendarUnit |NSYearCalendarUnit | NSMonthCalendarUnit|NSWeekCalendarUnit|NSWeekdayCalendarUnit fromDate:date]; где дата - это день, приходящийся на воскресенье, comps.weekday возвращает 1 вместо 7 ... Есть какие-нибудь подсказки? - person Pedro Mancheno; 12.02.2014

Этот код создает дату, установленную на понедельник текущей недели:

NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];

NSDate *today = [NSDate date];
NSDate *beginningOfWeek = nil;
BOOL ok = [gregorian rangeOfUnit:NSWeekCalendarUnit startDate:&beginningOfWeek
                                interval:NULL forDate: today];
person Kendall Helmstetter Gelner    schedule 02.12.2009
comment
Этот (с учетом ответа mmc) действительно работает. - person hoha; 18.03.2011
comment
Было бы неплохо, если бы мистер Джошуа поставил здесь отметку для ответа, поскольку она делает именно то, что описывает вопрос. - person epologee; 31.05.2011
comment
-1, потому что это фактически устанавливает начало недели на воскресенье, 12 утра. - person joshrl; 05.07.2012

setFirstWeekday: в объекте NSCalendar. Устанавливает индекс первого дня недели для получателя.

- (void)setFirstWeekday:(NSUInteger)weekday

Должен сделать свое дело.

person mmc    schedule 09.07.2009
comment
Я попытался установить для этого значения различные значения, и это не повлияло на свойство дня недели календаря NSCalendary. Я добавил код в свой исходный пост, чтобы вы могли видеть, что я делаю. Благодарность - person Joshua; 12.07.2009
comment
извините, я имел в виду свойство буднего дня на NSDateComponents - person Joshua; 12.07.2009

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

NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
[gregorian setLocale:[NSLocale currentLocale]];

Это заставит календарь автоматически установить первый день недели в соответствии с локалью пользователя. Если вы не разрабатываете свое приложение для конкретной цели / пользователя (или предпочитаете разрешить пользователю выбирать этот день).

person Amir Naor    schedule 06.09.2010
comment
+1 - Это действительно вопрос личных предпочтений - хотя в большинстве стран мира в качестве начала недели используется понедельник (а это фактически стандарт ISO), из США я привык к воскресному началу. Почему бы не использовать этот элегантный ответ и не вернуться к настройкам календаря пользователя? Это решение очень хорошо сработало для моего приложения. - person Jim; 18.10.2011
comment
-1 - Вопрос явно запрашивает способ изменить день начала на понедельник, а объем stackoverflow охватывает в основном кодовые решения, а не лучшие практики приложений. В любом случае, это должен быть комментарий к основной теме, а не сообщение с ответом. - person Andres Canella; 03.09.2012

Я сделал это вот так.

NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDate *today = [NSDate date];
NSDateComponents *compForWeekday = [gregorian components:(NSWeekdayCalendarUnit) fromDate:today];
NSInteger weekDayAsNumber = [compForWeekday weekday]; // The week day as number but with sunday starting as 1

weekDayAsNumber = ((weekDayAsNumber + 5) % 7) + 1; // Transforming so that monday = 1 and sunday = 7
person Ivo Patrick Tudor Weiss    schedule 08.04.2013

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

Вот ответ, который мне подходит:

- (NSDate*)firstDayOfWeek
{
    NSCalendar* cal = [[NSCalendar currentCalendar] copy];
    [cal setFirstWeekday:2]; //Override locale to make week start on Monday
    NSDate* startOfTheWeek;
    NSTimeInterval interval;
    [cal rangeOfUnit:NSWeekCalendarUnit startDate:&startOfTheWeek interval:&interval forDate:self];
    return startOfTheWeek;
}

- (NSDate*)lastDayOfWeek
{
    NSCalendar* cal = [[NSCalendar currentCalendar] copy];
    [cal setFirstWeekday:2]; //Override locale to make week start on Monday
    NSDate* startOfTheWeek;
    NSTimeInterval interval;
    [cal rangeOfUnit:NSWeekCalendarUnit startDate:&startOfTheWeek interval:&interval forDate:self];
    return [startOfTheWeek dateByAddingTimeInterval:interval - 1];
}

Обновление:

Как указано (в другом месте) от @vikingosegundo, в общем, лучше всего позволить местным жителям определять, какой день является началом недели, однако в этом случае OP запрашивал начало недели в понедельник, поэтому мы копируем системный календарь и переопределяем firstWeekDay.

person Jasper Blues    schedule 23.06.2013
comment
-1 Сложение числа, кратное 86400, никогда не будет правильным ответом. - person Dave DeLong; 07.11.2013
comment
Запрошен разъяснения с помощью нового вопроса здесь: stackoverflow.com/questions/19826952/ - person Jasper Blues; 07.11.2013
comment
чтобы быть педантичным: lastDayOfTheWeek вернет последнюю секунду недели. - person vikingosegundo; 07.11.2013
comment
переименование - разумное решение - person vikingosegundo; 07.11.2013
comment
на самом деле ваш ответ очень похож на этот: stackoverflow.com/a/1835499/106435, включая тот же недостаток, что и OP явно необходимо установить начало недели на понедельник. это не рассматривается в вашем ответе. просто скажите, что перед вызовом метода вы ожидаете, что календарь будет изменен как [[NSCalendar currentCalendar] setFirstWeekday: 2];// Sunday == 1, Saturday == 7 - person vikingosegundo; 07.11.2013

Проблема с ответом Криса - это крайний случай, когда начало недели начинается в предыдущем месяце. Вот более простой код, который также проверяет крайний случай:

// Finds the date for the first day of the week
- (NSDate *)getFirstDayOfTheWeekFromDate:(NSDate *)givenDate
{
    NSCalendar *calendar = [NSCalendar currentCalendar];

    // Edge case where beginning of week starts in the prior month
    NSDateComponents *edgeCase = [[NSDateComponents alloc] init];
    [edgeCase setMonth:2];
    [edgeCase setDay:1];
    [edgeCase setYear:2013];
    NSDate *edgeCaseDate = [calendar dateFromComponents:edgeCase];

    NSDateComponents *components = [calendar components:NSYearCalendarUnit|NSMonthCalendarUnit|NSWeekCalendarUnit|NSWeekdayCalendarUnit fromDate:edgeCaseDate];
    [components setWeekday:1]; // 1 == Sunday, 7 == Saturday
    [components setWeek:[components week]];

    NSLog(@"Edge case date is %@ and beginning of that week is %@", edgeCaseDate , [calendar dateFromComponents:components]);

    // Find Sunday for the given date
    components = [calendar components:NSYearCalendarUnit|NSMonthCalendarUnit|NSWeekCalendarUnit|NSWeekdayCalendarUnit fromDate:givenDate];
    [components setWeekday:1]; // 1 == Sunday, 7 == Saturday
    [components setWeek:[components week]];

    NSLog(@"Original date is %@ and beginning of week is %@", givenDate , [calendar dateFromComponents:components]);

    return [calendar dateFromComponents:components];
}
person iwasrobbed    schedule 04.02.2013
comment
Это не работает для одного углового случая. Для даты 2012-12-31 он возвращает: 2012-01-01 - person pzo; 30.07.2013
comment
Я должен уточнить, что я установил день недели на 2 (понедельник). - person pzo; 30.07.2013

В других сообщениях вижу недопонимание. Первый день недели, какой бы он ни был, имеет номер 1, а не 0. По умолчанию воскресенье = 1, как в «Введение в руководство по программированию даты и времени для какао: календарные вычисления»:

"Значение дня недели для воскресенья по григорианскому календарю равно 1"

Для понедельника как первого рабочего дня единственное средство, которое у меня есть, - это условие грубой силы для исправления расчетов.

NSCalendar *cal=[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *comps = [cal components:NSWeekdayCalendarUnit fromDate:[NSDate date]];
// set to 7 if it's Sunday otherwise decrease weekday number
NSInteger weekday=[comps weekday]==1?7:[comps weekday]-1; 
person ciukes    schedule 11.11.2009

Ниже также рассматривается крайний случай,

- (NSDate *)getFirstDayOfTheWeekFromDate:(NSDate *)givenDate
{
    NSCalendar *calendar = [NSCalendar currentCalendar];


   NSDateComponents *components = [calendar components:NSYearCalendarUnit|NSMonthCalendarUnit|NSWeekCalendarUnit|NSWeekdayCalendarUnit fromDate:givenDate];
    [components setWeekday:2]; // 1 == Sunday, 7 == Saturday
    if([[calendar dateFromComponents:components] compare: curDate] == NSOrderedDescending) // if start is later in time than end
    {
        [components setWeek:[components week]-1];
    }

    return [calendar dateFromComponents:components];
}
person Sarim Sidd    schedule 19.01.2014

Попробуй это:

NSCalendar *yourCal = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]
[yourCal setFirstWeekday:0];
person nicktmro    schedule 10.07.2009
comment
Это должно быть setFirstWeekday:2 для понедельника - person Christian Schnorr; 25.07.2014

IV нашел способ отображать любое название дня недели с помощью nscalender .. используя следующий код .. Просто откройте консоль из строки меню xcode, чтобы увидеть результаты. Копировать Вставьте следующий код в свой метод viewDidLoad, чтобы получить первый день недели

NSDate *today = [NSDate date];
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:@"MM/dd/yyyy :EEEE"];
NSString *dateString = [dateFormat stringFromDate:today];
NSLog(@"date: %@", dateString);
[dateFormat release];
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];

NSDateComponents *components = [gregorian components:NSWeekdayCalendarUnit | NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit fromDate:today];
[components setDay:([components day]-([components weekday]-1))];

NSDate *beginningOfWeek = [gregorian dateFromComponents:components];
NSDateFormatter *dateFormat_first = [[NSDateFormatter alloc] init];
[dateFormat_first setDateFormat:@"MM/dd/yyyy :EEEE"];
NSString *dateString_first = [dateFormat_first stringFromDate:beginningOfWeek];
NSLog(@"First_date: %@", dateString_first);

Результатом будет:

 date: 02/11/2010 :Thursday
 First_date: 02/07/2010 :Sunday

поскольку я запускал эту программу 2/11/2010, вы получите желаемый результат в зависимости от текущей даты.

Точно так же, если вы хотите получить первый рабочий день недели, то есть дату понедельника, просто немного измените код:

ИЗМЕНЕНИЕ: [components setDay:([components day]-([components weekday]-1))];

TO [components setDay:([components day]-([components weekday]-2))];

чтобы получить дату понедельника на этой неделе ..

Точно так же вы можете попытаться найти дату любого из семи рабочих дней, изменив целое число -1, -2 и так далее ...

Надеюсь, на твой вопрос ответят.

Спасибо, Бонсон Диас

person Bonson    schedule 11.02.2010
comment
Я думал об этом решении, но оно не работает должным образом. В воскресенье 2001-01-02 он вернется в понедельник 2011-01-03, но вместо этого должен вернуться в понедельник 2010-12-27. - person hoha; 18.03.2011

В календаре ISO 8601 первый день недели по умолчанию установлен на понедельник.

person Christian Schnorr    schedule 25.07.2014
comment
не кажется правдой - значение воскресенья по-прежнему равно 1 - person Swissdude; 07.12.2014
comment
Воскресенье, очевидно, равно 1. Я имею в виду, что при создании экземпляра календаря ISO 8601 для firstWeekday по умолчанию должно быть установлено значение понедельник или 2. - person Christian Schnorr; 08.12.2014
comment
Извините, @Christian Schnorr, вы можете объяснить - как это 2 - понедельник? Может быть, 1 - понедельник. - person new2ios; 08.06.2015
comment
Эти индексы начинаются с 1, а не с 0. - person Christian Schnorr; 08.06.2015

Использование календаря nextWeekend (iOS 10 или новее) и порядковый номер (спасибо @ kris-markel). У меня понедельник - первая неделя в календаре en_US.

Вот пример этого с откатом на firstWeekday:

extension Calendar {
    var firstWorkWeekday: Int {
        guard #available(iOS 10.0, *) else{
            return self.firstWeekday
        }
        guard let endOfWeekend = self.nextWeekend(startingAfter: Date())?.end else {
            return self.firstWeekday
        }
        return self.ordinality(of: .weekday, in: .weekOfYear, for: endOfWeekend) ?? self.firstWeekday
    }
}
person ugiflezet    schedule 25.07.2017

Вы можете просто изменить .firstWeekday календаря.

NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
calendar.firstWeekday = 2;

Затем используйте rangeOfUnit:startDate:interval:forDate:, чтобы получить первый день

NSDate *startOfWeek;
[calendar rangeOfUnit:NSCalendarUnitWeekOfYear startDate:&startOfWeek interval:nil forDate:[NSdate date]];
person trapper    schedule 14.08.2017

Решение Swift (обратите внимание, используйте .yearForWeekOfYear, а не .year):

let now = Date()
let cal = Calendar.current
var weekComponents = cal.dateComponents([.yearForWeekOfYear, .weekOfYear,
                                         .weekday], from: now)
//weekComponents.weekday = 1  // if your week starts on Sunday
weekComponents.weekday = 2  // if your week starts on Monday
cal.date(from: weekComponents) // returns date with first day of the week
person Alexander Jährling    schedule 10.08.2019
comment
Может быть еще проще. Просто оставьте компонент .weekday, и вы получите дату начала текущей недели по ISO 8601 (понедельник). - person Alexander Jährling; 10.08.2019
comment
Обратите внимание: также есть ошибка в API (macOS 10.14.6) преобразования weekOfYear, если вы используете день недели 1 (2 или ноль или нормально), вы должны вычесть 1 из weekOfYear. В противном случае вы получите начало следующей недели при создании даты. - person Alexander Jährling; 10.08.2019

… Есть ли в календаре понедельник в качестве первого дня недели вместо воскресенья.

Когда-нибудь будет.

person Peter Hosey    schedule 12.10.2009

Мой простой способ сделать это - получить Monday = 0, Sunday = 6:

    NSDateComponents *dateComponents = [[NSCalendar currentCalendar] components:NSWeekdayCalendarUnit fromDate:[NSDate date]];
    NSInteger dayNumStartingFromMonday = ([dateComponents weekday] - 2 + 7) % 7;    //normal: Sunday is 1, Monday is 2
person CharlesA    schedule 05.09.2013