Есть ли лучший способ найти полночь завтра?

Есть лучший способ сделать это?

-(NSDate *)getMidnightTommorow {
    NSCalendarDate *now = [NSCalendarDate date];
    NSCalendarDate *tomorrow = [now dateByAddingYears:0 months:0 days:1 hours:0 minutes:0 seconds:0];
    return [NSCalendarDate dateWithYear:[tomorrow yearOfCommonEra]
                                  month:[tomorrow monthOfYear]
                                    day:[tomorrow dayOfMonth]
                                   hour:0
                                 minute:0
                                 second:0
                               timeZone:[tomorrow timeZone]];
}

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

Функции естественного языка кажутся ненадежными, и я не уверен, что будет делать Cocoa, если я передам 32 в поле «день». (Если бы это сработало, я мог бы отказаться от вызова [now dateByAddingYears:...])


person Dre    schedule 08.10.2008    source источник


Ответы (6)


Из документации:

Использование NSCalendarDate настоятельно не рекомендуется. Он еще не объявлен устаревшим, однако может появиться в следующем крупном выпуске ОС после Mac OS X v10.5. Для календарных вычислений следует использовать подходящие комбинации NSCalendar, NSDate и NSDateComponents, как описано в Календарях в Темы программирования даты и времени для Cocoa.

Следуя этому совету:

NSDate *today = [NSDate date];

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

NSDateComponents *components = [[NSDateComponents alloc] init];
components.day = 1;
NSDate *tomorrow = [gregorian dateByAddingComponents:components toDate:today options:0];
[components release];

NSUInteger unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit |  NSDayCalendarUnit;
components = [gregorian components:unitFlags fromDate:tomorrow];
components.hour = 0;
components.minute = 0;

NSDate *tomorrowMidnight = [gregorian dateFromComponents:components];

[gregorian release];
[components release];

(Я не уверен, что это самая эффективная реализация, но она должна служить указателем в правильном направлении.)

Примечание. Теоретически вы можете уменьшить объем кода здесь, разрешив объект компонента даты со значениями, превышающими диапазон нормальных значений для компонента (например, просто добавив 1 к компоненту дня, что может привести к его значению 32 ). Однако, хотя dateFromComponents: может допускать значения, выходящие за пределы допустимого диапазона, это не гарантируется. Вам настоятельно рекомендуется не полагаться на него.

person mmalc    schedule 08.10.2008
comment
И, исходя из этого указателя, похоже, что я могу вырезать большую часть этого, поскольку dateFromComponents действительно, кажется, допускает дни после конца месяца. - person Dre; 08.10.2008
comment
dateFromComponents может допускать значения за пределами границ, но это не гарантируется. Вам настоятельно рекомендуется не полагаться на это. - person mmalc; 09.10.2008
comment
Я на восточном побережье, и весь день сегодня, когда я выполняю приведенное выше преобразование, я получаю 1:00 (мой сдвиг времени -5 часов, но кажется, что NSCalendar убежден, что это -4 часа. (Даже если я явно установил часовой пояс) - person Corey Floyd; 24.02.2011
comment
Разве вы не выпускаете components дважды? - person ; 31.07.2012

Нет, это будет точно так же, как сегодня вы находите полночь.

person loudej    schedule 08.10.2008
comment
Боюсь, у людей здесь очень несовершенные детекторы иронии/юмора. Если вы не отметите свои смешные комментарии как таковые, вас заминусуют. БДТ. - person JesperE; 08.10.2008
comment
Я не буду минусовать ваш ответ, но даже если предположить, что это смешно, в чем шутка? Легкомысленный короткий ответ, который игнорирует детали вопроса? Вы можете использовать свою шутку для каждого технического вопроса на SO. ПОТОМУ и не смешно. - person Dan Rosenstark; 06.08.2009
comment
Это не говорит о том, что формула такая же, как сегодня плюс один. Это преднамеренное непонимание структуры предложения вопроса, как будто я полагал, что Дре спрашивал, может ли представиться лучшая формула, недоступная в настоящее время, если он подождет день. Есть ли лучший способ найти полночь завтра? Видеть? На что вы могли бы совершенно справедливо ответить: Если вам придется это объяснять, это не смешно. - person loudej; 25.08.2009
comment
Это было забавно, но вы должны были дать более основательный ответ под своим забавным комментарием. - person strange; 17.09.2013

Преобразуйте текущую дату и время в дату Unix (секунды с 1970 года) или в стиле DOS (с 1980 года), затем добавьте 24 часа и преобразуйте их обратно. Затем обнулите часы, минуты и секунды, чтобы добраться до полуночи.

person selwyn    schedule 08.10.2008

Вы можете попробовать так:

NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *comps = [[NSDateComponents alloc] init];
[comps setDay:1];
NSDate *tomorrow = [calendar dateByAddingComponents:comps toDate:[NSDate date] options:0]; //it gives us tomorrow with current time
NSDate *midnight = [calendar startOfDayForDate:tomorrow]; //here we get next midnight

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

double intervalToMidnight = midnight.timeIntervalSinceNow;
person julia_v    schedule 21.02.2016

person    schedule
comment
Каждый раз, когда программист определяет день как 60 * 60 * 24, дополнительная секунда умирает. Не делайте этого. - person cbowns; 13.06.2012

person    schedule
comment
Интересный подход (и я проголосовал за него), но обратите внимание на предостережение в документации: «Это может дать неожиданные результаты, и его использование настоятельно не рекомендуется». - person Peter Hosey; 14.05.2009
comment
Спасибо, я тоже искал лучшее решение, так как iPhone sdk не любит, когда я его использую, но пока он все еще работает :) - person user58338; 14.05.2009