Получить NSDate на следующий день недели из эталонного NSDate?

Учитывая исходную дату, мне нужно найти следующее: «Среда».

Просто для ясности: если эталонная дата, скажем, вторник, то она должна возвращать среду из той же недели.

Если эталонной датой является среда или более поздняя дата, необходимо вернуть следующую среду с следующей недели.

Важно, чтобы он не возвращал среду после контрольной даты.

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

Это то, что у меня есть до сих пор:

NSDate *referenceDate = [NSDate date];
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *dateComponents = [calendar components:(NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit) fromDate:referenceDate];
[dateComponents setWeekday:4]; // Wednesday
NSDate *followingWednesday = [calendar dateFromComponents:dateComponents];

Хотя этот код не делает различия между средой, прошедшей на той же неделе, или следующей средой, и слышит ложь, моя проблема.

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

Есть ли способ лучше?

Любая помощь будет оценена по достоинству.


Обновить

Кажется, что установка дня недели на самом деле не влияет на дату, возвращаемую методом dateComponents: NSCalendar. Мой пример кода выше возвращает одну и ту же дату независимо от того, что установлено для дня недели.

Так что теперь я больше в тупике.


person Camsoft    schedule 02.11.2012    source источник
comment
как насчет добавления 7 дней, если дата уже в прошлом, иначе оставить ее в покое?   -  person tazzix    schedule 02.11.2012
comment
Да, это в основном то, что я делаю, но мне интересно узнать, являются ли они более приятным способом сказать «доставь меня в следующую среду» без необходимости писать много дополнительной логики. Я надеюсь, что я что-то пропустил в отношении класса NSDateComponents. Может не быть, и это хорошо, я просто сделаю это так, как я уже есть.   -  person Camsoft    schedule 02.11.2012


Ответы (5)


Я бы сделал это так:

NSDate *referenceDate = [NSDate date];
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *dateComponents = [calendar components:(NSYearCalendarUnit|NSMonthCalendarUnit | NSWeekCalendarUnit | NSWeekdayCalendarUnit) fromDate:referenceDate];

int targetWeekday = 4;

if (dateComponents.weekday >= targetWeekday)
{
    dateComponents.week++;
}

dateComponents.weekday = targetWeekday;
NSDate *followingTargetDay = [calendar dateFromComponents:dateComponents];
person Tobi    schedule 02.11.2012
comment
вы добавили флаги NSWeekdayCalendarUnit и NSWeekCalendarUnit при запросе компонентов в календаре? Возможно, вам также придется удалить флаг NSDayCalendarUnit. Я не могу проверить это прямо сейчас. - person Tobi; 02.11.2012
comment
В точку, мне пришлось удалить NSDayCalendarUnit. Спасибо! - person Camsoft; 02.11.2012

Вы должны пройти через NSDateFormatter. Вы можете сделать что-то подобное, чтобы рассчитать следующую среду. Я не уверен, что вы хотите, но вот пример:

NSDate *referenceDate = [NSDate date];
NSCalendar *cal = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *mincomp = [cal components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit|NSWeekCalendarUnit|NSWeekdayCalendarUnit fromDate:referenceDate];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"e"];
while ([[formatter stringFromDate:[cal dateFromComponents:mincomp]] intValue] != 4)
    mincomp.day += 1;
[formatter setDateFormat:@"yyyy-MM-dd"];
NSLog(@"next wednesday = %@", [formatter stringFromDate:[cal dateFromComponents:mincomp]]);
person Martol1ni    schedule 02.11.2012
comment
Это интересно и на самом деле работает, хотя кажется странным, что вам придется полагаться на NSDateFormatter, чтобы сделать это. Есть ли какие-либо предостережения относительно использования NSDateFormatter? - person Camsoft; 02.11.2012
comment
Насколько я знаю, нет, нет. - person Martol1ni; 02.11.2012

Используйте 1_

NSDate *date = [NSDate dateWithNaturalLanguageString:@"next Wednesday"];
NSLog(@"%@",date);

Примечание : dateWithNaturalLanguageString:

Создает и возвращает набор объектов NSDate с датой и временем, указанными в данной строке.

+ (id)dateWithNaturalLanguageString:(NSString *)string

Параметры

строка

Строка, содержащая разговорную характеристику даты, например «ужин в прошлый вторник», «15:00, 31 декабря 2001 г.», «31.12.01» или «31.12.01».

person Paresh Navadiya    schedule 02.11.2012
comment
Хотел бы использовать это, к сожалению, это поддерживается только для MacOS X. Извините, нужно было указать, что я использую iOS 5. См. теги. - person Camsoft; 02.11.2012
comment
Также вы должны учитывать, что это работает для тех, у кого английский язык стоит первым в настройках, в данном случае это хороший метод для тех, кто использует os x. - person Ramy Al Zuhouri; 02.11.2012
comment
Я думаю, что это частный метод API, поэтому вполне вероятно, что Apple откажется от его использования. Я не могу так рисковать. - person Camsoft; 02.11.2012
comment
@Prince - это не задокументировано для iOS. - person Hot Licks; 02.11.2012
comment
@Prince -- неизвестный селектор класса для dateWithNaturalLanguageString - person Hot Licks; 02.11.2012

У меня не все хорошо завязано, потому что реализация, которую я случайно разработал вчера, находится на другом компьютере, но примерно:

NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"e"];
NSInteger day = [[formatter stringFromDate:theDate] integerValue];
NSInteger offsetDays = (targetDay - day);  // targetDay is 4 for Wednesday
if (offsetDays < 0) offsetDays += 7;
NSDate* resultDate = [theDate dateByAddingTimeInterval:offsetDays * secondsInADay];

(Вычисление offsetDays может быть немного запутанным — такие вещи требуют больше размышлений, чем доступно в это время утра.)

person Hot Licks    schedule 02.11.2012
comment
Я не уверен, что это решение будет правильно обрабатывать часовые пояса и летнее время. - person Camsoft; 02.11.2012
comment
@Camsoft - вышеприведенное должно работать нормально независимо от часового пояса, поскольку оно смещается даже с шагом в 24 часа. (Форматировщик должен быть настроен на интересующий вас TZ, чтобы получить правильный день, конечно.) Однако изменения летнего времени требуют отдельных усилий. - person Hot Licks; 02.11.2012

Этот парень справился.

Адаптировано для ОП:

NSDate *refDate = [NSDate date]; // or whatever
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
[gregorian setLocale:[NSLocale currentLocale]];

NSDateComponents *nowComponents = [gregorian components:NSYearCalendarUnit | NSWeekCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit fromDate:refDate];
int wednesday = 4;
if(nowComponents.weekday >= wednesday) {
    [nowComponents setWeek: nowComponents.week + 1]; // Next week
}
[nowComponents setWeekday:wednesday]; // Wednesday
[nowComponents setHour:8]; // Specific time (if desired)
[nowComponents setMinute:0];
[nowComponents setSecond:0];

NSDate *nextWednesday = [gregorian dateFromComponents:nowComponents];

Как вы сказали, это будет получать «следующую среду» каждый раз, даже если контрольная дата - среда.

EDIT: исправлена ​​ошибка, указанная в комментариях.

person dooleyo    schedule 18.07.2013
comment
Допустим, refDate — вторник, и вы используете этот код: вы получите среду на 8 дней в будущем, а не среду на 1 день в будущем, о которой просил OP. - person SG1; 28.08.2013
comment
Бах. Хороший улов и глупый я. Нужно будет условно увеличить неделю, как это сделал @Tobi. - person dooleyo; 08.09.2013