Как хранить и сравнивать объекты данных времени

Это должно быть очень просто!

У меня есть магазин, он открывается в 8:30 и закрывается в 17:00. Я хочу, чтобы мое приложение сообщало, что магазины в настоящее время открыты или закрыты.

Как лучше всего хранить мои open_time и close_time? Хранить их как секунды с начала дня, т.е. 30600 и 63000?

Это имеет смысл, но как мне получить текущее время прямо сейчас, в секундах с начала сегодняшнего дня, чтобы я мог проверить, находится ли current_time между open_time и close_time, то есть открыто!!

Заранее спасибо!


person Jason Podwojski    schedule 27.08.2011    source источник


Ответы (3)


Эта проблема не так тривиальна, как вы думаете. С датами нужно работать очень осторожно. Лучшее решение — хранить все ваши открытые и закрытые часы в виде дат. Вот некоторый код для создания времени открытия/закрытия и их сравнения:

NSDate * now = [NSDate date];
NSCalendar * calendar = [NSCalendar currentCalendar];
NSDateComponents * comps = [calendar components:~(NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit) fromDate:now];
[comps setHour:8];
[comps setMinute:30];
NSDate * open = [calendar dateFromComponents:comps];
[comps setHour:17];
[comps setMinute:0];
NSDate * close = [calendar dateFromComponents:comps];

if ([now compare:open] == NSOrderedDescending && [now compare:close] == NSOrderedAscending) {
    // The date is within the shop's hours.
}
else {
    // The date is not within the shop's hours.
}

Вот что я сделал:

  1. Возьмите текущую дату.

  2. Получите компоненты даты, кроме часов, минут и секунд.

  3. Установите часы и минуты.

  4. Создайте открытое время.

  5. Повторите шаги 3-4 для закрытия времени.

  6. Сравните время открытия и закрытия с текущим.

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

person rbrown    schedule 27.08.2011
comment
Довольно нелепо, что Apple делает эту простую проблему такой сложной. - person zaph; 27.08.2011
comment
Я бы сказал наоборот. Apple делает сложную проблему простой. Проверьте ответ, на который я ссылался в своем ответе. Даты очень сложны, особенно если вы хотите сделать какую-либо локализацию. Также легко обернуть приведенный выше код в отдельный метод, чтобы код не выглядел таким уродливым. - person rbrown; 27.08.2011
comment
Разве NSOrderedAscending и NSOrderedDescending не должны быть перевернуты? Может показаться, что ваш код возвращает положительное значение для времени, которое на самом деле не соответствует времени открытия, а наоборот. - person Henri Normak; 27.08.2011
comment
Хороший улов. Я исправил это сейчас. Это проблема написания кода в браузере. - person rbrown; 27.08.2011
comment
Спасибо! Я использовал ваш код, но когда я NSLog выводил какой-то вывод, у меня удалялся час из end_time? setHour:17 отображает результирующее значение date.time 16:00? - person Jason Podwojski; 27.08.2011
comment
Проверьте часовой пояс. NSLog преобразует даты во время UTC. - person rbrown; 27.08.2011
comment
Вы должны использовать NSDateFormatter для преобразования дат в строки. - person Henri Normak; 27.08.2011
comment
Понятно! Теперь я показываю свою отладочную информацию с помощью NSDateFormatter, я вижу правильные даты, а не UTC, отображаемые как NSLog! Спасибо!! - person Jason Podwojski; 27.08.2011

Я думаю, что более четким решением было бы использование объектов NSDate с присутствием только компонентов часа/минуты.

По сути, где-то в вашем приложении вам нужно хранить время открытия/закрытия магазина как таковое:

NSCalendar *calendar = [[NSCalendar alloc] 
                         initWithCalendarIdentifier: NSGregorianCalendar];
NSDateComponents *openTime = [[NSDateComponents alloc] init];
[openTime setHour: 12];
[openTime setMinute: 30];
NSDate *openDate = [calendar dateFromComponents: openTime];
[calendar release];

И если вам нужно увидеть, находится ли текущее время между двумя такими объектами NSDate, у вас может быть такой метод:

- (BOOL)currentTimeIsInBetween: (NSDate *)date1 andDate: (NSDate *)date2 {
    NSCalendar *calendar = [[NSCalendar alloc] 
                             initWithCalendarIdentifier: NSGregorianCalendar];
    NSDateComponents *currentComponents = [calendar components: 
                                   (NSMinuteCalendarUnit | NSHourCalendarUnit)
                                          fromDate: [NSDate date]];
    NSDate *currentAdjusted = [calendar dateFromComponents: currentComponents];
    [calendar release];

    if ([currentAdjusted compare: date1] == NSOrderedAscending)
        return NO;

    if ([currentAdjusted compare: date2] == NSOrderedDescending)
        return NO;

    return YES;
}

РЕДАКТИРОВАТЬ: Похоже, что пользователь rbrown был немного быстрее меня, мы предлагаем тот же подход.

person Henri Normak    schedule 27.08.2011

Вы можете сделать что-то вроде этого.

NSDate *today = // code for getting today date at 0 oclock
NSDate *now = [NSDate date];
double second = [now timeIntervalSinceDate:today];

Теперь у вас есть время в секундах с начала дня для сравнения.

person sarunw    schedule 27.08.2011