2

This should be really simple!

I have a shop, it opens at 8:30 and closes at 17:00. I want my app to say the shops current open or currently closed.

Whats the best way to store my open_time and close_time? Store them as seconds since the start of the day, i.e. 30600 and 63000?

This make sense, but how do I get the current time right now, in seconds since the begining of today, so I can check if current_time is between open_time and close_time, i.e. open!!

Thanks in advance!

3 Answers3

2

This problem isn't quite as trivial as you may think. You have to work with dates very carefully. The best solution is to store all of your open and close times as dates. Here is some code for creating your open/close times and comparing them:

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.
}

Here's what I did:

  1. Grab the current date.

  2. Get the components of the date, except hours, minutes, and seconds.

  3. Set the hour and minutes.

  4. Create an open time.

  5. Repeat steps 3-4 for close time.

  6. Compare open and close times to now.

If you ever need to do any modification of dates, you should always use NSCalendar and NSDateComponents. Check out this answer for why it's so important.

Community
  • 1
  • 1
rbrown
  • 2,635
  • 2
  • 24
  • 24
  • It is rather ridiculous that Apple makes this simple problem so difficult. – zaph Aug 27 '11 at 14:13
  • 1
    I would argue the contrary. Apple makes a difficult problem simple. Check out the answer I linked to in my answer. Dates are very complicated, especially if you want to do any kind of localization. It's also easy to wrap my above code into its own method so the code doesn't look so ugly. – rbrown Aug 27 '11 at 14:21
  • 1
    Shouldn't the NSOrderedAscending and NSOrderedDescending be flipped? It would seem your code returns positive for times that aren't actually within the open times but vice versa. – Henri Normak Aug 27 '11 at 14:23
  • Good catch. I've fixed it now. This is the problem with writing code in a browser. – rbrown Aug 27 '11 at 14:27
  • Thanks! I've used your code, but when I NSLog some output I have an hour removed from the end_time? setHour:17 is displaying a resulting date.time of 16:00? – Jason Podwojski Aug 27 '11 at 14:48
  • Check the timezone. NSLog converts dates to UTC time. – rbrown Aug 27 '11 at 14:54
  • You should use NSDateFormatter for converting dates into strings. – Henri Normak Aug 27 '11 at 15:21
  • Got it! Now I'm display my debug info using NSDateFormatter, I can see the correct dates, not the UTC ones display be NSLog! Thanks!! – Jason Podwojski Aug 27 '11 at 15:29
1

I think a clearer solution would be to use NSDate objects with only hour/minute components present.

Basically, somewhere in your app you need to store the shop's open/close times as such:

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

And if you need to see whether the current time is between two such NSDate objects you could have a method like this:

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

EDIT: Seems like user rbrown was a bit faster than me, we are suggesting the same approach.

Henri Normak
  • 4,695
  • 2
  • 23
  • 33
0

You can do something like this.

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

Now you got time in second since the start of the day for compare.

sarunw
  • 8,036
  • 11
  • 48
  • 84