2009-07-09 10 views
39

Кто-нибудь знает, есть ли способ установить первый день недели в 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; 
+0

Ну вы нашли какие-либо решения еще? Меня поражает то же самое! –

+0

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

ответ

12

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

- (void)setFirstWeekday:(NSUInteger)weekday 

Должен сделать трюк.

+0

Я попытался установить это значение на различные значения, и это не влияет на свойство дня недели NSCalendary. Я добавил код в свой оригинальный пост, чтобы вы могли видеть, что я делаю. спасибо – Joshua

+0

извините, я имел в виду свойство weekday на NSDateComponents – Joshua

+0

Это должно быть намного больше голосов –

0

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

NSCalendar *yourCal = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] 
[yourCal setFirstWeekday:0]; 
+0

Это должно быть 'setFirstWeekday: 2' for monday –

0

... есть календарь, который уже в понедельник, как первый день недели, а не в воскресенье.

Someday, there will be.

3

я вижу непонимание в других сообщениях. Первый день недели, в зависимости от того, что есть, имеет номер 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; 
17

Этого код строит дату, которая устанавливается в понедельник Текущая неделя:

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

NSDate *today = [NSDate date]; 
NSDate *beginningOfWeek = nil; 
BOOL ok = [gregorian rangeOfUnit:NSWeekCalendarUnit startDate:&beginningOfWeek 
           interval:NULL forDate: today]; 
+4

Этот (с учетом ответа mmc) фактически работает. – hoha

+0

Было бы неплохо, если бы г-н Джошуа поставил здесь ответ, потому что он точно описывает вопрос. – epologee

+1

-1 потому что это на самом деле устанавливает beginOfWeek в воскресенье 12 утра. – joshrl

0

Iv нашел способ, чтобы отобразить любое название дня недели, используя nscalender..using следующего кода .. Просто откройте консоль из меню Xcode, чтобы увидеть results.Copy Вставьте следующий код в методе 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 и будет получить желаемый выход де в ожидании текущей даты.

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

CHANGE: [components setDay:([components day]-([components weekday]-1))];

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

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

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

Надежность ур задан ответ.

Спасибо, Bonson Dias

+0

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

10

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

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

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

+1

+1 - Это действительно вопрос личных предпочтений - хотя большая часть мира использует понедельник в качестве начала недели (и это фактически стандарт ISO), исходящий из США, я привык к воскресному старту , Почему бы не использовать этот элегантный ответ и не вернуться к собственным настройкам календаря пользователя? Это решение очень хорошо работало для моего приложения. – Jim

+0

-1 - Вопрос заключается в явном прочтении способа изменить начальный день в понедельник, а область действия stackoverflow охватывает главным образом программные решения, а не лучшие практики приложений. Во всяком случае, это должен быть комментарий к основному потоку, а не к сообщению «ответ». –

77

Редактировать: Это не проверяет край, где начало недели начинается в предыдущем месяце. Некоторые обновленный код, чтобы покрыть это: 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); 

Помните, порядковые для ш eekdays начинаются с 1 в первый день недели, а не в ноль.

Documentation link.

+0

Отличный ответ, это реальная сделка! – nobre

+0

То же, что. Отличный ответ, это путь! –

+3

@ Joshua это правильный ответ, пожалуйста, проверьте и проверьте, как ответили. –

7

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

// 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]; 
} 
+3

Это не работает для одного угла. На дату 2012-12-31 он возвращается: 2012-01-01 – pzo

+0

Я должен уточнить, что я установил будний день на 2 (понедельник). – pzo

7

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

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 
+4

Ты гений! –

7

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

Вот ответ, который работает для меня:

- (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]; 
} 

Update:

Как отметил (elsewhere) по @vikingosegundo, в общем все возможное, чтобы местный определить, какой день является начало недели, однако в этом случае ОП просил начать неделю в понедельник, поэтому мы скопируем системный календарь и переопределим первый файлWeekDay.

+0

-1 Добавление кратных 86 400 к дате никогда не будет правильным ответом. –

+1

Просьба уточнить новый вопрос здесь: http: // stackoverflow.com/questions/19826952/предположение-gregorian-calendar-why-is-add-a-time-interval-of-86-400-one-day-t –

+0

@DaveDeLong - Спасибо - исправило ответ :) –

0

Мой простой способ сделать это, чтобы получить понедельник = 0, воскресенье = 6:

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

Ниже также охватывает случай края,

- (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]; 
} 
0

ИСО 8601 календарь, как представляется, это первый будний день установлен в понедельник по умолчанию.

+0

не похоже на то, что значение для воскресенья по-прежнему 1 – Swissdude

+0

Воскресенье, очевидно, 1. Я имею в виду, что при создании экземпляра календаря ISO 8601 первый день недели должен быть установлен по умолчанию aka 2 по умолчанию. –

+0

Извините, @Christian Schnorr, вы можете объяснить - как это 2 - понедельник? Это может быть 1 - понедельник. – new2ios

0

Использование календаря nextWeekend (iOS 10 или новее) и ordinality (спасибо @ 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 
    } 
} 
0

Вы можете просто изменить .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]];